Does an IBOutlet needs to be a property & synthesized?

前端 未结 4 2250
隐瞒了意图╮
隐瞒了意图╮ 2020-11-29 16:37

In most examples I see the following setup of IBOutlets:



(Example A)

FooController.h:

@interface FooController : UIViewController {
    UILabel *fooLabel         


        
相关标签:
4条回答
  • 2020-11-29 17:15

    The end result is exactly the same, but you have to keep a few things in mind:

    • When using instance fields as outlets, you should NOT release them in dealloc.

    • When using properties that have the (retain) attribute, you have to release the property in dealloc (using self.property=nil or by releasing the backing variable). This makes it a lot more transparent as to what's going on.

    Actually it all comes down to the same old rule: "thou shalt release what you alloc/retain". So in case you use an instance field as outlet, you didn't alloc/retain it, so you shouldn't release it.

    0 讨论(0)
  • 2020-11-29 17:20

    On Mac OS X, IBOutlets are connected like this:

    1. Look for a method called set<OutletName>:. If it exists call it.
    2. If no method exists, look for an instance variable named <OutletName>, set it without retaining.

    On iPhone OS, IBOutlets are connected like this:

    1. call [object setValue:outletValue forKey:@"<OutletName>"]

    The behavior of set value for key is to do something like this:

    1. Look for a method called set<OutletName>:. If it exists call it.
    2. If no method exists, look for an instance variable named <OutletName>, set it and retain it.

    If you use a property, you'll fall into the "Look for a method called set<OutletName>:..." case on both platforms. If you just use an instance variable, then you'll have different retain/release behavior on Mac OS X VS iPhone OS. There's nothing wrong with using an instance variable, you just need to deal with this difference in behavior as you switch between platforms.

    Here's a link to full documentation on just this topic. https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW6

    0 讨论(0)
  • 2020-11-29 17:23

    On Mac OS X, IBOutlets are not retained by defaults. This is the opposite of the behavior on iPhone OS: on iPhone OS, if you don't declare a property it is retained and you must release this property in the dealloc method. Additionally, the 64-bit runtime can synthesize instance variables using property declarations. That means that someday the instance variables (with the IBOutlet) may be omitted.

    For these reasons it is more homogeneous and compatible to create always a property and use the IBOutlet only in the property. Unfortunately, it is also more verbose.

    In your first example you always have to release the outlet in the dealloc method. In your second example you must release the outlet only with iPhone OS.

    0 讨论(0)
  • 2020-11-29 17:35

    Its possible that those examples use the retain because the sample code is programmatically allocating and initializing a UILabel and then adding it to the UIView. That's the case for many examples, since learning how to use Interface Builder is often not their point.

    The second example (no property and no synthesize) with the IBOutlet is used when the developer 'assigns' the UILabel (Button, View, etc) within the Interface Builder -- by dragging the IBOulet to the Label or other View component. In my opinion, the preceding drag and drop action (Label onto View) also add the subview, the Label to a View -- and so on. Label is retained by a View; a View is retained by Window; Window is retained by File's Owner. File's Owner is usually your Document that is booted up in main.

    You will note that when you step through your program (by adding an awakeFromNib

    - (void)awakeFromNib
    {
        [fooLabel blahblah];
    }
    

    that fooLabel already has a memory address.

    Thats because the Label was initialized from a file bundle (the nib file) using not init but initWithCoder. Which essentially deserializes the filestream to an object - and then sets the IBOutlet variable. (We're still talking about the IBOutlet method).

    Also note that the aforementioned iOS method uses the Key Value method

      call [object setValue:outletValue forKey:@"<OutletName>"]
    

    which is the Observer/Observable pattern. That pattern require the Observable object reference each Observer in a Set/Array. A change in value will iterate the Set/Array and equally update all Observers. That Set WILL already retain each Observer thus the lack of retain in iOS.

    Further and the rest is speculation.

    It seems that cases when you do use Interface Builder then

     @property (nonatomic, retain) IBOutlet UILabel *fooLabel;
    

    should possibly be changed to

    @property (nonatomic, weak) IBOutlet UILabel *fooLabel;
    

    or @property (nonatomic, assign) IBOutlet UILabel *fooLabel;

    And then it needn't be released in a dealloc method. Plus it will satisfy the OSX and iOS requirements.

    That's based on logic and I could be missing some pieces here.

    Nevertheless, it may not matter if the view is persistent through the life of your program. Whereas a label in a modal dialog box (open, close, open, close) may in fact have over-retained and leak per cycle. And that's because (speculation again) each closed dialog box is serialized into a file system and thus persists x,y position and size, along with its subviews, etc. And subsequently deserialized ... on the next session open (Opposed to say minimiz or hidden.)

    0 讨论(0)
提交回复
热议问题