Want to perform action when __weak ivar is niled - objective-c

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.

Related

Should IBOutlets be ivars or properties?

Though I'm sure they exists, I'm having difficulties finding or pinning down an official best practice for declaring outlets in a ViewController.
There are 3 options so far as I can see:
ivar only
property only
property backed with an ivar
Xcode currently crashes when I try and auto-generate a property by dragging into my ViewController from IB, but from what I remember, doing so creates a property without an ivar. It is also possible to drag into the ivar section and this will create an ivar without a property. This suggests that property-only and ivar only outlets are both OK with apple.
So in viewDidUnload we need to assign nil to any of our outlets, but what about dealloc. If we have used a property without an ivar, how can we release our outlet give that we are not supposed to use any accessors in an init or dealloc?
It seems to me that the only pattern which would allow us to release our outlet without an accessor is using a property backed with an ivar, so we can manually release our ivar in dealloc without using its accessor, however this is the one option which Apple's code-generation doesn't support.
As a rule of thumb, I usually create accessors for IBOutlets.
In ARC or non-ARC projects I usually do the following:
//.h (ARC)
#property (nonatomic, weak) IBOutlet UILabel* myLabel;
//.h (non-ARC)
#property (nonatomic, retain) IBOutlet UILabel* myLabel;
//.m
#synthesize myLabel;
In this manner you can let the compiler to create an instance variable for you. But you can also declare your instance variable and tell the compiler to use that.
Then you can use that accessors/instance variable wherever you want.
The Apple Memory Management guide says that you have to avoid accessors methods in init or dealloc methods when you have non-ARC projects. So, for example:
// (non-ARC)
- (void)dealloc
{
[myLabel release]; myLabel = nil; // I'm using the instance variable here!
[super dealloc];
}
This is very important in non-ARC projects. The reason is that, if there is no accessor, KVC will assign the nib object to the instance variable and will put a retain on it. If you forget to release it, you could have a memory leak. Using an accessor force you to release that object at the end.
I strongly suggest to read friday-qa-2012-04-13-nib-memory-management by Mike Ash. It's a very cool article on nib and memory management.
Hope it helps.
Here's my understanding
Use properties for variables that will be accessed by other classes, either read from (getters) or written to (setters). Both setters and getters are synthesized for properties.
Use ivars for variables that will be used internally by the owning class only, that is, other classes will not set or get their values.
Sure you can use properties in lieu of ivars, but they incur the function-call overhead whenever they're accessed. So if you have an internal variable that is accessed by your class a LOT, the function calls will affect the real-time performance, and this can be avoided by declaring them as ivars.

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).

Releasing Unused properties in iOS

I have this property synthesized and declared in my class 'ClassA'
#interface ClassA
#property (nonatomic, retain) NameFieldCell* nameCell;
#end
I know that the rule says that the nameCell property should be released in my dealloc method when it is declared with retain|copy|...
However, 'ClassA' gets instantiated lazily and sometimes the nameCell property is not even used, which means that I don't use its setter method nor access it nor retain it explicitly.
Should I still be calling [nameCell release] in my dealloc method? I find it difficult to understand that I should be releasing something that is not even initialized. And since it is not initialized, the reference counter is 0 and makes no sense to release it? Or is nameCell somehow retained automatically when instantiating 'ClassA' even if I am not making use of it?
In Objective-C, the memory allocated by alloc for a class is initialized to all-bits-zero on allocation (and then the isa ivar is set), which results in nameCell's backing ivar being set to nil by default. And since it is not an error to send a message to nil in Objective-C (the message is just ignored), you are free to just call [nameCell release] without worrying about whether nameCell was ever set.
If nameCell is nil, then [nameCell release] has no effect. This makes it easy to cover both cases, so yes, you should release it in your dealloc method.
That or start using ARC, and you won't have to worry about it.

Do I need release in the dealloc?

In the book I'm studying from for iPhone dev, they utilize IBOutlet instances using the Interface Builder. An example would be a UIButton. So they add a thing in the struct like this:
IBOutlet UIButton *whateverButton;
Then they add a #property for each of these in the .h, and a #synthesize in the .m.
Then they include a release in the dealloc of the .m. Two questions:
Is the release necessary? Aren't all properties already handled automatically?
How can I check the ref count to see what's happening, for debug purposes...?
Is the release necessary? Aren't all
properties already handled
automatically?
If the property is retained, the release is necessary. When you declare a #property and #synthesize it, all you get is the accessors, there is no special automatic behaviour in dealloc.
Also, there is nothing magical about IBOutlet – it’s just a marker for Interface Builder to see which properties you would like to appear in IB. It’s simply an empty macro, Cmd-click the IBOutlet keyword to see its definition:
#ifndef IBOutlet
#define IBOutlet
#endif
Same thing goes for IBAction which expands to void.
How can I check the ref count to see
what's happening, for debug
purposes...?
When I need to debug memory management, I usually simply set up a breakpoint in the dealloc method or log a string there. It is also helpful to log the retainCount of an object around the calls that might do something fishy with it.
It might also help to see how the #synthesize directive creates the accessors. When you declare a retained #property and ask the compiler to #synthesize them, you get something like this:
#property(retain) NSString *foo;
#synthesize foo;
- (void) foo {
return foo;
}
- (void) setFoo: (NSString*) newFoo {
// Try to think what would happen if this condition wasn’t
// here and somebody called [anObject setFoo:anObject.foo].
if (newFoo == foo)
return;
[foo release];
foo = [newFoo retain];
}
This isn’t exactly the thing, but it’s close enough. Now it should be more clear why you should release in dealloc.
Properties are not "handled automatically." The closest that comes to being true is that synthesized accessors handle their memory management responsibilities properly. But that is just those accessors. Properties are just a way of declaring accessible "things" on your class. They don't get much special treatment beyond that. It doesn't turn on some sort of garbage collection. So yes, release is necessary.
And you should use the debugging tools like Instruments if you want to inspect a running app for leaks or memory that doesn't get released. I would not look at the ref count directly, because it's almost dangerously useless — there's no guarantee that the ref count will be what you expect at any point, and that doesn't necessarily indicate a problem.
You should read Apple's memory management rules for Cocoa. It's pretty simple once you've absorbed that. I wouldn't necessarily recommend reading other guides first, because subtle misstatements can lead you down the wrong path (for instance, the idea that properties will be released for you probably came from hearing somebody misstate how they work).
Is the release necessary? Aren't all
properties already handled
automatically?
It depends on how the property is implemented. If it is auto-implemented (#synthesize'd), the property will retain its value in the setter and release it if set to another value. If you just got into Obj-C and Cocoa, you should read about the conventions for memory management. I have put up a post on my blog about them, there are plenty of resources elsewhere too.
How can I check the ref count to see
what's happening, for debug
purposes...?
You can check the NSObject retainCount property. Information on that is here. For advanced debugging purposes, there is the NSZombieEnabled environment flag that will cause all release message to not decrement the reference count but log an error when an object that would have normally been released is accessed.

Difference between accessing property methods and class fields (Objective-C)

Assume that I have this piece of code:
#interface Foo : NSObject {
Bar *bar;
}
#property (retain, nonatomic) Bar *bar;
#end
When using this field/property, is there any difference between lines:
[self.bar doStuff];
and
[bar doStuff];
?
When doing assignment, property method will perform correct retaining, but what about the read access to the property, as described above? Is there any difference?
There is a big difference.
[self.bar doStuff] is equivalent to [[self bar] doStuff]
[bar doStuff] is equivalent to [self->bar doStuff]
The former uses the accessor method, the latter just accesses the instance variable bar directly.
If you use the #synthesize directive on your bar property, the compiler will generate two methods for you:
- (void)setBar:(Bar*)b;
- (Bar*)bar;
Also note, that the compiler generated setter method is retaining your Bar instance as you told it in the #property declaration.
Using the accessor self.bar is translated into a method call: [self bar]. The period syntax is just for looks. Accessing the member variable directly doesn't involve an extra function call, and is therefore slightly faster. It really only matters if you're accessing it within a loop, or in some process where that difference will add up. (On the iPhone) The setters created for properties also have some extra overhead for doing key value coding. A KVO notification is sent when you call "setBar:" or say "self.bar =" , so calling it over and over will result in a flood of notifications.
Jim is right, though - there's no functional difference between a nonatomic #property and a direct use of the variable in your code. Unless you're really concerned with the speed, using the property is probably your best bet.
A synthesized (or correctly hand-written) nonatomic accessor will be functionally equivalent to
- (Bar *)bar
{
return bar;
}
so there is no functional difference between your two examples.
However, outside of -dealloc or your initializers, consistently accessing the property via its accessor is a good idea.
If you assign value to your field with a convenient constructor of a Bar class, your Bar field will become a Zombie sooner than your Bar Property with Retain option, because reference count is not incremented by assigning to fields, and sometimes you run into "accessing deallocated objects" error.