Those things about ib_designable/ibinspectable.

Source: Internet
Author: User

Objective

Ib_designable/ibinspectable These two keywords are in the WWDC 2014 "What's New in Interface Builder" This session, using Swift to tell an example. It is also a new keyword added with Xcode 6.

These two keywords are used in our custom view, currently can only be used in UIView subclasses, so the system comes with native controls that use this keyword has no effect.

Live renderingyou can use different attributes-@IBDesignable and @IBInspectable-to enable live, interactive custom vie W Design in Interface Builder. When you create a custom view this inherits from the UIView class or the NSView class, you can add the @IBDesignable Attri Bute just before the class declaration. After you add the custom view to Interface Builder (by setting the custom class of the view in the Inspector pane), Interf Ace Builder renders your view in the canvas. You can also add the @IBInspectable attribute to properties with types compatible with user defined runtime attributes. After you add your custom view to Interface Builder, you can edit these properties in the Inspector.

The idea of "WYSIWYG" means that we can render custom code in real time to interface builder. And the bridge between them is done by two instructions, namely @ibdesignable and @ibinspectable. We tell interface builder that this class can be rendered to the interface in real time, no matter how complex the drawrect is, how complex the customization is, Xib/storyboard can compile it and render it @ibdesignable. However, this class must be a subclass of UIView or NSView. By @ibinspectable, you can define dynamic properties to visualize and modify property values in the Attributes Inspector panel.

@ibinspectable var integer:int = 0

@ibinspectable var float: cgfloat = 0

@ibinspectable var double: Double = 0

@ibinspectable var point:cgpoint = cgpointzero

@ibinspectable var size:cgsize = cgsizezero

@ibinspectable var customframe:cgrect = cgrectzero

@ibinspectable var color:uicolor = uicolor. Clearcolor()

@ibinspectable var string:string = ""

@ibinspectable var bool: bool = false

These two keywords are not the focus of today, see a demo will be used.

Demo Address: Https://github.com/halfrost/CircleSlider

If you want to see the session, you can see these two WWDC 2014 links

Whats_new_in_xcode_6:http://t.cn/rtyjkbg

Whats_new_in_interface_builder:http://t.cn/rtyjcrb

Apple Official document: Http://t.cn/RtyJpCq

Today to share some of the problems and procedures that I encountered when I used these two keywords.

1.The agent raised a "nsinternalinconsistencyexception" exception

File://bottomcommentview-master/bottomcommentview/base.lproj/main.storyboard:error:

IB designables: Failed to Update auto layout status:the agent raised a "nsinternalinconsistencyexception" exception:could not load NIB In bundle: ' nsbundle/xcode.app/contents/developer/platforms/iphonesimulator.platform/ Developer/library/xcode/overlays> (Loaded) ' with name ' Bottomcommentview '

File://bottomcommentview/base.lproj/main.storyboard:error:

IB designables: Failed to render instance of bottomcommentview : the Agent threw an exception.

We're going to see the panel on the designables here is a crashed,xib/storyboard that's actually going to crashed! The whole app is running up, but it's 2 mistakes, you can't tolerate it! These two errors are actually compile time Xib report error, not run-time error.

When we see debug, the first thing we must think of is the point of Debug. But unfortunately, in this case, click Debug, each time will tell you "finishing debugging instance of XXXX for interface Builder", even if you in your custom view inside the break point, also useless.

Back to the question, let's take a closer look at the crash message. The message says could not the load NIB in bundle, and also gives us a similar address to the same thing ' nsbundle/xcode.app/contents/developer/platforms/ Iphonesimulator.platform/developer/library/xcode/overlays> (Loaded) ', we can navigate to the Xib when the error is read from the bundle.

By looking up information on the Internet, the problem is actually the case.

When loading the nib, we ' re relying on the "fact that" passing bundle:nil defaults to your app's mainbundle at run time.

Every time we take mainbundle, it's the default method.

Let nib = uinib(nibname:string(stripyview), bundle:nil)

Here in Xib/storyboard compile, we need to tell the iOS system, we want to specify which bundle class to read. Change the code above to the following.

Let bundle = nsbundle(forclass:self. DynamicType)

Let nib = uinib(nibname:string(stripyview), bundle:bundle)

Or so

#if target_interface_builder

         NSBundle *bundle = [ nsbundle bundleforclass : [ self class ];

         [ bundle loadnibnamed : @ "Bottomcommentview" owner : Self options : nil ];

#else

        &NBSP [[ nsbundle mainbundle ] loadnibnamed : @ "Bottomcommentview" owner : Self options : nil ];

 

#endif

Ps: If your custom view is not displayed on the Xib/storyboard, but the program will be able to display the view, the reason may also be the reason, although Xib/storyboard no error, because the app is not running, XIB/ Storyboard didn't know the context, so we didn't load our custom view.

2. The code or xib still does not show the appearance of the custom control

If you follow the first question above with the bundle code or not, it might be the wrong place to add your code.

If the code is manually creating the control, the initWithFrame method is called

- (instancetype)initwithframe:(cgrect)frame

The Initwithcoder method is called if the display control is dragged through Xib/storyboard.

- (instancetype)initwithcoder:(nscoder *)adecoder

It is necessary to add bundles to the corresponding two methods. If you want to be on the safe side, add the code to the two init methods.

3.Failed to update auto layout status:the Agent crashed/failed to render instance of Xxxxxxx:the agent crashed

File://bottomcommentview/base.lproj/main.storyboard:error:

IB designables: Failed to Update auto layout status:the Agent crashed

File://bottomcommentview/base.lproj/main.storyboard:error:

IB designables: Failed to render instance of bottomcommentview: the C30>agent crashed

If this is the problem, it is more serious, the problem is not like a problem, the whole app can be run, the error comes from Xib/storyboard compile time error, but does not affect the operation of the app.

But this problem will directly cause the entire app to flash back, directly crashed out! No way, we can only interrupt the point of debugging.

If you open debug at Designables and then hit the breakpoint to Initwithcoder and initWithFrame there, you will find that the program is always running to this line

Self = [super Initwithcoder: Adecoder];

or this line.

Self = [super initWithFrame: Frame];

It collapsed. In fact, from the following stack information can also quickly see what happened:

It is obvious to see that this method of Initwithcoder is trapped in a dead loop. Because this cycle of death caused the program to crashed.

But why is there a cycle of death here? The root cause is that the class of our custom classes is written for ourselves.

To see what's going on. Now in Xode 7, we create a view by default, is not to give us the default generation of a Xib file, Viewcontroller will have the following option, you can choose to tick on.

As we create this class, we also create a xib to associate with this class.

Compare our process of creating Tableviewcell

In general we will tick the "Also Create XIB file", after creation, we will be in the custom class to fill in the name of our cell class.

If we do the same thing now when we customize the view, after the Xib file is created, file's owner is associated. Then, after filling in the custom class with our customized classes, this is the wrong time!

Why do we usually do the same thing, and it's wrong to be here?

Let's consider our custom view loading process. Our custom view is definitely placed on a viewcontroller, the code is created or dragged directly onto the xib/storyboard. Drag a view with code or SB, this time we need to specify what this class is, and this is absolutely no problem. The view class that the SB drags above must choose our custom view.

But in the load of our view, we will go Initwithcoder/initwithframe method, in this method will also go to call super This method, now we put this class as ourselves, according to our above debug log, you can see, After the Initwithcoder, the following route will be called.

[NSBundle loadnibname]--[uinib Instantiatewithowner:options]--[uinibdecoder decodeobjectforkey:]-- Uinibdecoderdecodeobjectforvalue--[uiruntimeconnection Initwithcoder]--[uinibdecoder decodeobjectforkey:]-- Uinibdecoderdecodeobjectforvalue--[uiclassswapper Initwithcoder:]--[bottomcommentview InitWithCoder:]

Starting with NSBundle loading, after parsing it will call to Classswapper's initwithcoder, because we write ourselves in class, and here we get into a dead loop. Program Crashes! This is the same as the set method inside the call point syntax assignment, infinite recursive call.

After the above analysis, we know that the problem is in our initwithcoder inside and call Loadnibname,loadnibname and will go to the final uiclassswapper Initwithcoder. Are we custom class wrong? Compare our custom Tableviewcell class is itself, how does not have this problem.

Let's take a closer look at how tableviewcell we load, our Xib class or ourselves, but Registerwithnibname method calls in TableView, so there's no infinite recursion.

Of course we can do this in this way, so we need to write loadnibname to another class. Class still writes itself, using that class to load our view so that it does not crash, not infinite recursion. But again, we can't preview our view in real time on Xib/storyboard.

Here you need to mention how the ib_designable works. When we use the Ib_designable keyword, xib/storyboard will compile the view code without running the entire program, and because there is no program context, all the compilation is done in the view code.

We dragged a view in the Viewcontroller and changed its class to our custom class, then all of the view's drawings will be given to our custom view class, which is managed by this class. There are two kinds of situations here. The first case is an example of the demo I gave at the beginning of the article, using the DrawRect code to draw the view. There will be no problem here. The second case is that we also want to use a xib to display the view, which is the case of Xib/storyboard loading xib again. Now that our custom class has the right to draw over the entire view, we should loadnibname in Initwithcoder and load the entire view at initialization time. According to the above analysis, we find that the cause of the crash is infinite recursion, and here we have to call Initwithcoder, our only way is to change the class to the parent class, that is UIView, this time everything is good, Xib/storyboard not error, Can also show the appearance of the view in time.

To summarize:

When using loadNibNamed:owner:options:, the File ' s owner should is NSObject, the main view should be your class type, and All outlets should is hooked up to the view, not the File ' Owner.

Ps. This is just about loadnibnamed, not initwithnibname. Incidentally, the difference between the two of them. Initwithnibname the class of xib to load is the viewcontroller we define. Loadnibnamed the class of xib to load is nsojbect. They also load differently, Initwithnibname method: Lazy loading, the control on this view is nil, only to need to display, it is not nil. Loadnibnamed is immediately loaded, and each element in the Xib object that is called to load this method already exists.

Summarize

When I first knew Ib_designable/ibinspectable, I felt special magic, even our custom view can be seen in time. But after a period of research, it was discovered. There are some flaws in ib_designable/ibinspectable. Ib_designable temporarily can only be used in UIView sub-class, the common UIButton fillet these temporarily can not preview. Ibinspectable essentially sets the value in runtime attributes, which makes ibinspectable only use the common type. NSDate This type cannot be set to ibinspectable.

This is what I share with you some of the "pits" encountered during ib_designable/ibinspectable use.

Update:

The following paragraph to thank @andy, the above pointing me, in fact, the sub-class of the system can do this: a few commonly used to draw the common class of control, by the way with the external peel the common properties, more complex to shift this library ibanimatable

@Andy also cautioned that this feature is best iOS8 + swift,oc or iOS7 will appear failed to update and no solution, thanks again @andy Vector Warehouse great God's guidance!!! Is his visual transformation of the system controls!

Those things about ib_designable/ibinspectable.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.