Why we need property outlet and variable in iOS? - iphone

Normally I'm use 'property' outlets and variables only if it's access by another class. Otherwise it's declare within interface block. But I saw some are create 'property' outlet and variables but they are not access these in another class. So any one can explain, if we not access some outlet or variable from another class why we need 'property' outlets and variables?

If you don't need to access the outlet from another class, you don't need to make it a property. You can make it an instance variable in your #implementation:
#implementation ViewController {
IBOutlet UIView *someView;
}
...
Some people don't like using plain instance variables and prefer to always use properties, even for private data. It is particularly useful to use properties instead of raw instance variables if you are not using ARC, because you can rely on property setters to retain and release their objects. If you are using ARC, this is not an issue.
If you want to use a property but you don't want to declare the property in your #interface, you can put a class extension at the top of your .m file (above your #implementation), and put the property there:
#interface ViewController () {
#property (nonatomic, strong) IBOutlet UIView *someview;
#end
#implementation ViewController
...

They were declared so that they would be exposed in the NIB/XIB editor (aka Interface Builder).
This allows you to associate views to the object's properties in the NIB editor, and the XIB unarchiver will set the properties when initialized so that you may easily reference those instances from your class once initialized.

I think you are asking about Properties. Properties are used to facilitate you writing getters and setters.
Why do we need getters setters? to have one place from where we can access a variable so that in future if we need to add some rule we can do it without changing whole code.
this question is covered indepth in Why use getters and setters?
Outlets are for interfacebuilder to access properties.

Related

How do you use the Object type in interface builder?

In interface builder there is available type of object called "Object".
I have tried to use this to wire up a view with a property pointing to one of these objects.
I have set the class on Object in interface builder to a custom class. I don't need to set any other properties on this custom class. Basically my desired behaviour is that if that property is set then the view will call a method on it during its lifecycle.
When the view is inflated from the nib file however, my property on the view remains nil.
Is what I am trying to do possible?
I think that:
if you added your custom object in Interface Builder like shown on this video; AND
if you connected it to a properly defined property in your view controller (e.g. #property (nonatomic, retain) IBOutlet MyClass *anObj; and synthesized it in *.m file; AND
if you didn't override +alloc and -init of your custom class in a
strange way (IB objects get instantiated via alloc and init calls AFAIK - someone please correct me if I'm wrong)
your object should not be nil after the nib file was unarchived in runtime. If I meet above conditions for my objects in IB, they are not nil.

Should every IBOutlet have a property?

We create property for a variable for using it in some other view. Same we do for IBOutlets. But not always for using them. Is it necessary to create property for each IBOutlet we just created it our xib? Or is it only a good practice to do so?
I like to look at it is in terms of ease of memory management, and external access. If you need to access it externally, obviously make a property. (Yes ease of memory management, if it's easy you won't mess it up, if you don't mess it up it doesn't become a bug later)
80% of the time my view controller has the IBOutlets and nobody else accesses them, therefore ivars work.
The problem is that when you don't use #property, the assigned value is still retained. Then you need to remember to release it even though you didn't retain it yourself, which I found counter-intuitive.
For that reason I usually use #property (assign) for the ones I won't be changing, and #property (retain) for everything else, and never declare IBOutlets directly as ivars.
Example:
#interface something : NSObject {
//This one needs to be RELEASED then set to nil in both viewDidUnload, and dealloc.
IBOutlet UILabel * myLabel;
//also cannot be accessed outside of "something" class (technically it can, but don't do that)
//I NEVER declare my outlets this way.
}
//This one can just be set to nil in viewDidUnload and dealloc
#property (nonatomic, retain) UILabel * myOtherLabel;
//it can also be accessed from mySomething.myOtherLabel by any other class.
//This one just works. I don't own it, the view owns it, so I don't retain/release.
#property (nonatomic, assign) UILabel * myOtherOtherLabel;
//It also provides access to outsiders.
//I wouldn't recommend using this type if you want to change the value though.
It is not necessary to create a property for each IBOutlet.
Specifically, if you access the outlet only from the class where it is declared, you do not strictly need the property. If you have a property, you get the advantages that properties offer, but you could always directly refer the outlet directly.
If you plan to access the outlet from another class, then a property is useful so you don't have to define yourself setter and getter methods.
If you want to use the IBOutlet for only the view for which you created the XIB then no need to set the property here. But yes, it is good practice to use but not mandatory to use everytime we create IBOutlet for the view.
If what you are going to display is not going to change, you can skip creating a property or a IBOutlet for that widget.
For example in a screen where you have a label and a textfield and the label always has the string "Name:" and textfield is used for getting input from the user, you have to just create a referencing outlet for the textfield to access the data input from the user. Creating a referencing outlet for label doesn't make any sense here.
I hope you get the point.
Properties are a feature in Objective-C that allow us to automatically generate accessors, and also have some other side benefits. so as Praveen S gave you an example with Label and UIText i just little explore.
Lets say you have nothing to do with UILabel you do not exactly need to set the properites but if are asking from user to give some text to your UITextField you have to set the properties. and if you setting the properties with retain, you must release it in viewDidUnload.
If you want to change the Contents of your display then you should add the property..for an example if we want to change the label text then we need to use IBOutlet nd Property so that we need to able to get to the label control that the framework will build from our nib..

When is #property and #synthesize needed?

When exactly do I have to add #property (nonatomic, retain) and #synthesize? Also, when is declaring IBOutlet someObject enough? How is it that I can set/get UILabel value without #property & #synthesize? Does it depend on UI object type?
And yes, I have read similar questions about these 2 :)
The pair (#property, #synthesize) will create the set/get methods used for accessing your ivars from other objects.
In a usual view controller you don't need to define properties for your IBOutlets since they should normally only be accessed by the view controller they belong to.
Highly recommended read: Using Properties in Objective-C Tutorial
property is needed only when you need the access to the member variables through the objects of that particular class. If you want to change some label's text at run time, that too accessing the object of the View Controller, then only you will need to have property defined for it, else not.
Outlet is just to make connection between an object from xib and a member from the class. If you want to give access to that member though object write property for it, else not.
Have a look at this
Its not needed if you dont want the variables or objects to be accessed outside the class by other objects.

interface builder setters? please punch me!

if you have an IBOutlet on an ivar like
IBOutlet UIView *view;
#property (nonatomic, retain) UIView *view;
that object created by ib will be managed by ib,
but what if you have,
UIView *view;
#property (nonatomic, retain) IBOutlet UIView *view;
does ib now use your setter to set that object? that would mean the setter has added +1 and needs to be set to nil or the object would leak?
IBOutlet doesn't do anything in the resulting code — it's literally erased by the preprocessor. It's just there so Interface Builder can scan your header to see which things it should treat as outlets.
Have a read here, a posting by Aaron Hillegass about some of this.
On the desktop, when a nib file is loaded, outlets are set in a sensible way: to set an outlet called foo, the nib loader looks for an accessor called setFoo:. If it is unable to find the accessor, the nib loader sets the variable foo directly. This sounds like key-value coding, right? It isn’t. The important difference is that nib loading treats foo as a weak reference; the object it points to is not retained.
Thus, if you create a subclass of NSViewController that has a dozen outlets to subviews, only the top-level view is retained. So, when the view controller is deallocated, it releases the top-level view and all the subviews are automatically deallocated. Tidy!
On the phone, however, the nib loader uses key-value coding to set the outlets; By default, outlets are treated as strong references. If you don’t have an accessor for your outlet, the view it refers to is retained.
It both cases you must release the outlet. If you have a property IB will use it and let you manage the retain or not (if you use assign). If you do not have a property IB will assign the value but retain it automatically, which you need to then release.
If you mark the property as an IBOutlet you don't need to also mark the class variable as an IBOutlet.
AFAIK, it doesn't matter if you put the IBOutlet on the ivar or the property. Either way, in general, IBOutlet properties should be (nonatomic, assign), and not retained, as the NIB loader handles all of that.

Does an IBOutlet needs to be a property & synthesized?

In most examples I see the following setup of IBOutlets:
(Example A)
FooController.h:
#interface FooController : UIViewController {
UILabel *fooLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *fooLabel;
#end
FooController.m:
#implementation FooController
#synthesize fooLabel;
#end
But this works also fine (notice: no property and no synthesize):
(Example B)
FooController.h:
#interface FooController : UIViewController {
IBOutlet UILabel *fooLabel;
}
#end
FooController.m:
#implementation FooController
#end
Are there any downsides of defining IBOutlets as in Example B? Like memory leaks? Seems to work fine and I prefer to not expose the IBOutlets as public properties as they are not used as such, they are only used in the controller implementation. Defining it in three places without a real need does not strike me as very DRY (Don't Repeat Yourself).
On Mac OS X, IBOutlets are connected like this:
Look for a method called set<OutletName>:. If it exists call it.
If no method exists, look for an instance variable named <OutletName>, set it without retaining.
On iPhone OS, IBOutlets are connected like this:
call [object setValue:outletValue forKey:#"<OutletName>"]
The behavior of set value for key is to do something like this:
Look for a method called set<OutletName>:. If it exists call it.
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
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.
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.
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.)