maybe it's a little childish question, but I really want to know the detail. I've just seen this code:
#implementation SimpleMainViewController
{
SimpleTableViewController *simpleTableViewController;
AboutViewController *aboutViewController;
}
what's the difference between this and the following one?
#interface SimpleMainViewController : UIViewController
#property(nonatomic,retain) SimpleTableViewController *simpleTableViewController;
#property(nonatomic,retain) AboutViewController *aboutViewController;
#implementation SimpleMainViewController
#synthesize simpleTableViewController;
#synthesize aboutViewController;
Thanks in forward.
The first one is only visible and acceseable from inside the implemented class. It is called an instance variable.
Whereas the property is visible to other classes as well. A property is backed by an iVar too. The #synthesize is doing this behind the scenes. In your case the backing iVar would be accessable with the name of the property (e.g. simpleViewController). But one should access a property via self (e.g. self.simpleViewController) for simpler memory management and to distinguish it from an normal iVar. The #synthesize will generate getter and setters to the iVar and will do memory management according to the property declaration (here retain).
Nowadays you do not even need a #synthesize any more. Just declare a property. The compiler will create the property with an backing iVar with a prefix underscore. So one could access it either via self.simpleTableViewController or via _simpleTableViewController.
Related
ViewController.h
#property (strong,nonatomic) NSMutableArray *products;
#property (strong, nonatomic) IBOutlet UITableView *tableViewProducts;
i would like to know apple or developer recommended method of accessing instance variables and accessor methods.
Should i use _instanceVariable or self.instanceVariable or should i synthesize all ivars ?
Method 1
ViewController.m
#synthesize products;
#synthesize tableViewProducts;
#synthesize productCount;
......
UITableViewCell *cell=[tableViewProducts dequeueReusableCellWithIdentifier:#"cellReuseIdentifier"];
productCount.
Method 2
ViewController.m
UITableViewCell *cell=[_tableViewProducts dequeueReusableCellWithIdentifier:#"cellReuseIdentifier"];
Method 3
ViewController.m
UITableViewCell *cell=[self.tableViewProducts dequeueReusableCellWithIdentifier:#"cellReuseIdentifier"];
Always access properties with the accessor methods, so always use self.property etc. Except, in init (and initWithWhatever etc) methods, in which you should always access the backing variable directly _property etc. This is to avoid side effects of accessing self before self has finished initializing.
The reason you always want to use self.property is because that enables useful side effects. The accessor methods can be overridden to validate values, trigger KVO effects (automatically update views for example), use default values if no specific value has been set and much more. Those are bypassed if you use the backing variables directly.
You haven't needed to use #synthesize for years now so don't bother adding those lines.
Since you have properties, access the properties, not the underlying instance variables.
This means your 3rd option is the best choice.
Nowadays you don't need to #synthesize properties. Since you've already defined your properties you even don't need to user the instance variable, simple use the property itself as self.instanceVariable.
You doesn't need to #synthesize all properties. But Can #synthesize property to create custom Setter Method.
self.propertyName will trigger this setter Method & _propertyName won't trigger.
Example:
.h
#property(string, nonatomic) NSString *name;
.m
#synthesize name = _name;
- (void)setName:(NSString *)name {
_name = name;
}
There are at least 3 methods of creating an IBOutlet in Objective-C, for making iOS 10 App, in Xcode 8.
Method 1: in ViewController.h
#interface ViewController : UIViewController
#property (nonatomic, strong) UILabel *textLabel;
#end
Method 2: in the interface of ViewController.m
#interface ViewController () {
IBOutlet UILabel *textLabel;
}
#end
Method 3: in the interface of ViewController.m, using #property
#interface ViewController ()
#property (nonatomic, strong) UILabel *textLabel;
#end
Given that the textLabel has to be accessed & its text is needed to be updated frequently, which method is the correct way to do so?
That all depends on whether you need your outlet to be accessible to classes outside of the containing one; generally I would discourage this because it is good practice to keep your view controllers responsible for updating your UI and not pass this task around to other classes. With this being said, Method 3 would be the best option, however, if you do have to access your object from another class, then simply use Method 1 so it is exposed in your class header.
Method 2 utilises iVars rather than object properties and is not the proper way to declare outlets, it may even cause unexpected behaviour so it is best to avoid this method.
Your code contains no proper IBOutlet. Outlets are connections to Storyboard.
Method 1
This is a property. As it is in .h file, it can be reached from outside. The Objective-C pattern for public.
Method 2
This is an iVar. Do not use iVars if you do not have to.
Method 3
This is a property. As it is in .m file, it can not be reached from outside. The Objective-C pattern for private.
Method 4
A proper IBOutlet looks like this:
#interface ViewController ()
#property (nonatomic, weak) IBOutlet UILabel *label;
#end
It is a simple property. You have to decide if you put it in .h or .m file depending on whether or not you want to publish it.
The IBOutlet simply makes the property connect-able to Storyboard. It's an annotation for Xcode and does not alter the semantic of your code.
Edit 1:
As Sulthan correctly mentions in the comments:
In most situations the correct design pattern is to hide outlets because it's an implementation detail. External classes should not set data directly using views.
Edit 2:
Why "not to use iVars if you do not have to" (2)
Opinion based:
I consider it as good OOP practice to use getters & setters (and thus not to access the variables directly). Also code is easier to read as you know while reading what x = self.variable (property) and x = variable (local variable) are.
If you have to use iVars for some reason, it is common to (and I would recommend to) prefix the name with _. x = _variable (iVar).
I have an object called PanelView in Cocoa Touch which has a UINavigationController instance variable. At some point in my app, when the UINavigationController is presented as modal view, I send in a PanelView object as a parameter to the rootViewController of the UINavigationController where it is stored as an instance variable. I declare it how I would normally in the .h file:
PanelView *_panelView;
#property(nonatomic, strong) PanelView *panelView;
And in the .m file:
#synthesize panelView = _panelView;
So far I've had no side effects, but I'm wondering if I'm declaring this correctly as it might be a circular reference. What is the correct way to declare this variable?
Objective-C has evolved to be pretty forgiving on syntax, especially on iOS. You don't actually need to declare the variable that's acting as the backing store for your #property -- it will be synthesized for you.
It used to be the case that if you declared both a getter and a setter, then you would need to insert the #synthesize in your #implementation block, as you have it above. I just tried it out in Xcode 7.1 to double-check, and the compiler didn't complain for either a Cocoa Touch project or a command-line app project.
It seems from your follow-up question that you need to sort out the ownership of your data. Circular references in and of themselves usually aren't the problem. Keeping strong circular references is. That's how you get memory cycles that lead to leaks.
I would advise that you change the UINavigationView's reference to be a weak reference, since it the PanelView is guaranteed to be in existence as long as the UINavigationView is in existence.
I'm a fan of not exposing class variables unless needed. In most objective-c code I see, the variables are declared as properties even if they are never to be used by an outsider.
#interface DetailViewController : UIViewController {
__weak IBOutlet UILabel *name;
}
vs
#interface DetailViewController : UIViewController
#property (weak, nonatomic) UILabel *name;
As a student of Software Engineering, this seams to me to be a pretty bad violation of principles such as encapsulation and could potentially lead to unwanted coupling in a large project.
I do understand the KVC aspects of using properties, but not why one would expose variables which are clearly only meant to be used internally in the class, such as the UILabel above.
Could someone explain why this is the preferred way when working with Objective-C on iOS?
Properties encapsulate the memory management (eg assign, retain, copy, strong, weak) of a iVar, while direct access to an iVar (instance variable) does not. This greatly reduces memory bugs.
Non-public properties can be declared at the top of the .m so there's no reason for them to be in the header:
#interface DetailViewController ()
#property (weak, nonatomic) NSString *name;
#end
Properties do create ivars that can be accessed. For the example above, with an explicitly synthesized property, the ivar would be named name while an implicitly synthesized synthesized property will have a leading underscore _name.
IBOutlets are declared in the header even though other classes don't need access to them as they are required so that Interface Builder connect to them and the nib loading system can populate the outlets. IBOutlets are most often going to be views, such as your UILabel.
Edit:
The previous paragraph about IBOulets is a legacy method required for Xcode 3 and earlier. However, newer versions of Xcode can use outlets defined in the implementation file just as the property above thanks to tighter integration of the InterfaceBuilder to the rest of the IDE.
What you see is an old style. Earlier Objective-C compilers required that you declare instance variables in the interface. However, by default they are #protected, so not everyone can just use them.
Current best practice is that you don't declare instance variables at all but use properties, unless you need to declare them (if you have a custom getter for a readonly property, or both custom getter and setter for a readwrite property, no instance variable is generated automatically), that you declare them in your .m file unless someone really needs to access them, that you declare properties and methods in your .m file unless someone needs to access them, and that you don't declare methods at all unless needed.
It's also quite common to declare a property as readonly in the header file, and redeclare it as read/write in the implementation.
In other words, hide what you can hide.
The first example indicates that you want to use the label as an outlet for a Xib or Storyboard. This answer sheds some light on that case: https://stackoverflow.com/a/1236985/171933
In general, however, you don't need to declare internal instance variables as properties. Actually, you can move them completely out of the header by putting them into your .m file like so:
#implementation DetailViewController
{
NSInteger _someValue;
UILabel *_someLabel;
}
That way you can really only keep the things in the header that should be visible to the outside. And those things would typically either be properties or plain old methods.
I'm subclassing a UIToolbar because I'm gonna reuse it all over my app. The UIToolbar uses a delegate protocol:
//
// UIToolbarCustom.h
//
#import <UIKit/UIKit.h>
#protocol UIToolbarCustomDelegate
#required
- (void)tab:(UIBarButtonItem *)sender;
- (void)ok:(UIBarButtonItem *)sender;
#end
#interface UIToolbarCustom : UIToolbar {
id <UIToolbarCustomDelegate> delegate;
}
#property (strong, nonatomic) id delegate;
#end
The standford iOS development course teacher recommends to explicit declare all the ivars prefixing it with a underscore, like:
#implementation UIToolbarCustom
#synthesize delegate = _delegate;
#end
But, in this specify scenarion it gives me a error:
error: property 'delegate' attempting to use ivar '_delegate'...
The code works just fine if I use:
#synthesize delegate = __delegate; or
#synthesize delegate;
What is going on here? Is there a private instance variable in the UIToolbar class named _delegate?
UPDATE
Thank all you guys for all the clarifications and protips, I'm learning a lot. Turns out that I'm new to iOS development (this is my first app second version, so I'm trying to do it right =p). Following the tips I came out with this new header file:
//
// Toolbar.h
//
#import <UIKit/UIKit.h>
#protocol ToolbarDelegate
#required
- (void)tab:(UIBarButtonItem *)sender;
- (void)ok:(UIBarButtonItem *)sender;
#end
#interface Toolbar : UIToolbar
#property (strong, nonatomic) id delegate;
#end
Notes:
The class prefix was removed.
The delegate declaration was removed (I'm using a ios delegate tutorial code, but the code sample uses a older xcode version, where the declaration is needed).
The synthesize was removed, I also didn't knew that we don't need synthesize our properties anymore.
PS: Obviously the code does not work, because the ivar problem. I'm gonna change its names, so I don't need to synthesize it, not sure about what name to use anyways...
What is going on here? Is there a private instance variable in the UIToolbar class named _delegate?
Yes, that's exactly the problem. You need to come up with a different name for your instance variable. __delegate will work, or you could prefix the name with a 3 letter prefix (see last paragraph).
Do note that you've declared your ivar as delegate, then in the synthesize statement told the compiler to use _delegate. Effectively that means that your delegate ivar isn't being used at all. In any case, if you're writing for iOS (as opposed to 32-bit Mac), like you are, you don't need the explicit instance variable declaration in your subclass's #interface section, because the compiler will automatically create it for you.
Finally, it's bad form to name your own subclass something that begins with 'UI', since the UI prefix is reserved for classes that are part of UIKit. You should use your own 3 letter prefix instead, or else no prefix at all. The problem is that a future version of UIKit could conceivably include a class called "UIToolbarCustom", and your subclass would collide with it.
Since last year, when Xcode 4.3 came out, you don't need to synthesize your properties. It is done for you by the compiler (an ivar is generated, and a leading underscore is added to its name). This means that you also don't need to declare an ivar. If you do, be sure to name it something other than _delegate.
So, all you really need is this line:
#property (strong, nonatomic) id<UIToolbarCustomDelegate> delegate;
UPDATE: please see the Andrew Madsen's answer for the full story. Turns out UIToolbar has its own ivar named _delegate. Who knew!