In Objective-C, do we have to use self.var or just var to reference a property of self? - objective-c

If I add a property to the ViewController
#property (strong, atomic) UIView *smallBox;
and synthesize it in the .m file, the variable can actually be referenced just by smallBox inside of any instance methods.
But then, self.view cannot be replaced by view, even though view is defined as a property of UIViewController too. Why the difference and what is the rule?

self.view and view/_view are not the same thing. Depending on how you create your instance variables, view or _view refer to the actual object instance variable. It is dangerous to access this directly, and you should only do so in init, dealloc or in accessors. Everywhere else, you should use self.view.
self.view is exactly the same as [self view], which passes the message "view" to the object "self" an returns the result. By default, when an object receives a message, it executes the method with that name, and the default implementation of view will return the value of the related instance variable (either view or _view).
In older versions of Xcode, #synthesize view would create an instance variable called view. In the latest versions of Xcode, declaring a property view will will automatically create an instance variable called _view in many cases, even without #synthesize. This change makes it easier to notice when you are accessing the ivar directly.
In short:
except in init, dealloc and the view accessors (if you custom write them), always use self.view.
In those methods, you should refer to it as _view.
If you are writing for the latest Xcode, do not include #synthesize at all. If you are writing for a slightly older Xcode, use #synthesize view=_view;
self.view does not mean "the value of the instance variable." It means "the result of passing the message 'view'" which is generally implemented as returning the instance variable.

You can't access the view member directly because it's declared as #package visibility in UIViewController. This prevents your code from accessing it. (Normally, you wouldn't want to access instance variables of your superclasses directly anyway.)
For your class's own properties, you can access the instance variable directly, but you need to be aware of the memory management implications of this. (As well, as Rob points out, as any other behaviours you're side-stepping by avoiding the accessor.)

Apple defined properties usually contain an underscore before their name, so when you use self.view, it is actually getting the instance variable _view from the object. You cannot use _view in code, as it will cause a linker error on compiling, but Xcode will still highlight it for you. Another way of accessing the instance variable for self.view is by self->_view, but again, this causes a linker error. The reason for these linker errors is because the compiled libraries do not contain the symbols for _view; even if its declaration can be found in UIViewController.h.

Related

Want to perform action when __weak ivar is niled

I have a #class Foo which contains a __weak id bar ivar. Several actions from methods in different classes can cause the object to disappear and thus get bar niled.
I want to perform an action when the ivar is automatically niled by ARC.
If possible, I would want to avoid turning bar into a property or using Key-Value Observing.
Is this even possible? If not, can KVO be used against non-property ivars?
I was led here by a duplicate question, here is what I answered:
You can't do that with KVO, but you can still get a notification and emulate this by associating an object with your iVar using objc_setAssociatedObject(), it will be deallocated when the weak variable dies.
#interface WeakObjectDeathNotifier : NSObject
#end
#implementation WeakObjectDeathNotifier
- (void)dealloc
{
// the code that shall fire when the property will be set to nil
}
#end
You can build on top of that very elaborate notifiers, using NSNotificationCenter or just custom blocks, depending on how heavily you rely on that for a specific ivar case or for lots of them.
The good thing about this solution is that it works with any __weak ivar, even if you don't control the type the __weak ivar has.
KVO cannot be successfully used on non-property IVARs.
You cannot detect from the runtime when Objective-C's ARC nils an IVAR.
I suggest to override dealloc. If you know the type of the object that will be allocated, and it's a custom class (otherwise subclass it), you can perform the action when the object is deallocated, which is exactly what happens when ARC sets the retain count to zero and sets the weak variable to nil.

objective C underscore property vs self

I'm was playing around with the standard sample split view that gets created when you select a split view application in Xcode, and after adding a few fields i needed to add a few fields to display them in the detail view.
and something interesting happend
in the original sample, the master view sets a "detailItem" property in the detail view and the detail view displays it.
- (void)setDetailItem:(id) newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
i understand what that does and all, so while i was playing around with it. i thought it would be the same if instead of _detailItem i used self.detailItem, since it's a property of the class.
however, when i used
self.detailItem != newDetailItem
i actually got stuck in a loop where this method is constantly called and i cant do anything else in the simulator.
my question is, whats the actual difference between the underscore variables(ivar?) and the properties?
i read some posts here it seems to be just some objective C convention, but it actually made some difference.
_property means you are directly accessing the property.
self.property means you are using accessors.
In your case, in the setter method you are calling it, creating a recursive call.
In the course of your experiment, you've set up an endless loop which is why the simulator goes non-responsive.
Calling self.detailItem within the scope of setDetailItem: calls setDetailItem: recursively since your class implements a custom setter method for the property detailItem.
I would refer you to the Apple documentation on declared properties for the scoop on properties, ivars, etc; but briefly, declared properties are a simplified way of providing accessor methods for your class. Rather than having to write your own accessor methods (as we had to do before Objective-C 2.0) they are now generated for you through the property syntax.
The properties are basically a way of the compiler to generate a setter and getter for a given instance variable.
So when you use something like:
id detailItem = self.detailItem;
what you are doing under the hood is:
id detailItem = [self detailItem];
Same for:
self.detailItem = otherDetailItem;
would be:
[self setDetailItem:otherDetailItem];
So when you write the setter yourself.. you get in an infinite loop since you access the method itself in itself.
You can freely make use of the 'self.' notation in your class, just not when you're overriding the setter or accessor because of the mechanism I described above.
Cases in a class where I use the . notation over simply accessing the ivar is when I change the value, you never know inside your class what needs to happen when you change the value. do you have something in terms of a status that should notify some delegate that a status changed? Usually this is not the case, however, just by using the . notation you are making sure that in the future you won't have to refactor some code if you did decide to do some magic in your setter method.
I'll make an example (without ARC enabled):
#property (nonatomic, retain) NSNumber* number;
If you don't synthesize it, you can access it this way:
self.number= [NSNumber numberWithBool: YES];
This case the number is retained.If instead you synthesize it and don't use the property:
#synthesize number;
Later in the file:
number=[NSNUmber numberWithBool: YES];
You haven't used the property, so the number is not retained.That makes a relevant difference between using accessors and synthesized properties.

#property or init to set instance variables

While doing my project I was wondering if I should set my instance variables for a viewcontroller through the viewcontrollers #synthezied properties or creating a new init function that sets the instance variables when the init it called.
For me, it seems like setting the instance variables using the #properties are cleaner.
What do you think?
I dont use nibs or storyboards...
Synthesizing the properties just saves you from the trouble of writing setters and getters. Just using #synthesize does not initialize your properties. You should definitely initialize them - either in -init or when declaring them.
I'd go for designated initialiser approach as in set instance variables that then can be used via #synthesized properties. Initialising view controller and then setting its properties leave the object in an inconsistent state.
Designated initializer:
MyViewController * viewController = [[MyViewController alloc] initWithParam1:#"foo" param2:#5];
// now viewController is consistent as presumably it has all properties set
Setting properties via setters:
MyViewController * viewController = [[MyViewController alloc] init];
// here viewController is inconsistent as it does not have default properties set
[viewController setParam1:#"foo"];
[viewController setParam2:#5];
// only here viewController is consistent and can be used normally
Depending on implementation of your initialisers you may set default values for properties without passing them as params to initialiser too, so my second example may be faulty if init silently sets param1 to #foo and param2 to #5.
In general your designated initialiser should only have parameters that are strictly necessary. Anything optional usually goes elsewhere, such as being a readwrite #property. There's some amount of leeway here, at your discretion - sometimes you'll include an optional parameter because it is actually used the vast majority of the time (and when it's not it has an easy default, like nil or 0).
The idea being that any object returned by an init method should be usable in some fashion. Requiring additional steps to configure it is almost always indicitive of a poor design.
Following this principle also encourages immutable instances (since in many cases you can specify all the necessary parameters upfront), which are advantageous for many reasons - simplicity, predictability, thread-safety, copy-by-retain etc, etc.
For a view controller specifically, typically you would have an initialiser which takes the view to be controlled, and leaves everything else as #properties. Your view controller should work, in some capacity, with just the view set; all other properties should have reasonable defaults.

When to use `self` in Objective-C?

It's now more than 5 months that I'm in Objective-C, I've also got my first app published in the App Store, but I still have a doubt about a core functionality of the language.
When am I supposed to use self accessing iVars and when I'm not?
When releasing an outlet you write self.outlet = nil in viewDidUnload, instead in dealloc you write [outlet release]. Why?
When you write self.outlet = nil the method [self setOutlet:nil]; is called. When you write outlet = nil; you access variable outlet directly.
if you use #synthesize outlet; then method setOutlet: is generated automatically and it releases object before assigning new one if you declared property as #property (retain) NSObject outlet;.
Very very important blog to understand about properties getter-setter method in objective c
Understanding your (Objective-C) self
http://useyourloaf.com/blog/2011/2/8/understanding-your-objective-c-self.html
You use self when you are refering to a #property.
Usually it will have been #synthesize'd.
You do not use self if you are refering to a "private" variable. Typically, I use properties for UI elements such as UIButtons or for elements I want easily reachable from other classes.
You can use the #private, #protected modifiers to explicitly enforce visibility. You cannot however use private methods, that do not exist in Objective-C.
The part about nil, release and dealloc is unrelated to the use of "self". You release what you retained, you nil what is autoretained.
You should read the Objective-C guide, it's well written and very enlightening.
You use self. when you're accessing properties of class that you're in (hence self). Basically you use self when you want to retain a value, but is only when you have retain in your property definition.
release just releases object that you've retained. You shouldn't release something that you haven't retained cuz it will lead to crash (zombie object).

Local declaration of tableView hides instance variable?

I understand why I get the warning in the title when I define my own tableView property in my own class and then use a local variable name tableView.
What I want to know is why DON'T I get this warning when I derive my class from UITableViewController, which has it's own tableView property? Does the compiler/editor only look at my class and not the parent class?
When you’re implementing a method, parameters/local variables share the same namespace as instance variables. However, they don’t share the same namespace as declared properties, which means that a class can declare a property named someData (or inherit it from one of its superclasses), have the backing instance variable with some other name, and the implementation of a method of that class can also have a parameter/local variable named someData — the compiler won’t give a warning in that case.
I assume you have a declared property named tableView and also an instance variable named tableView, the latter being either explicitly declared in the interface or automatically created when synthesizing the property. In that case, if you define a method that takes a parameter named tableView or declares a local variable named tableView, this local declaration will hide the instance variable named tableView (but not the property).
In the case of UITableViewController, there is no instance variable named tableView. There is a declared property named tableView which, because it’s in a different namespace, won’t be hidden by a local (variable) declaration.
One easy fix to avoid the compiler warnings is to give a different name to the instance variable. For instance, the instance variable can be named _tableView, and the property would still be named tableView but synthesized as #synthesize tableView = _tableView.
Post the exact code that is generating the warning.
"Local declaration" typically implies that you have something like:
- (void) foo {
int thisIsTheNameOfAnInstanceVariable;
}
There are likely other permutations via which you could cause this to happen, though.
I'm not exactly sure if I'm answering this correctly, but if you want to access variables in the super classes (e.g. UITableView, since your class is deriving form it) you have to use "self." then the variable name form the super class. Whenever you directly call a variables, e.g. 'myVariable', it will only look for local instances.