Do I need release in the dealloc? - objective-c

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.

Related

NSWindowController subclass will not release in ARC

I'm encountering a strange situation with NSWindowController. I want the window controller to be released but it will not. It doesn't seem to be following my expectations for ARC behavior.
I've created a simple window controller subclass, PlainWindowController. Its interface and implementation are empty:
#import <Cocoa/Cocoa.h>
#interface PlainWindowController : NSWindowController
#end
#implementation PlainWindowController
#end
I created with it a default windowController xib named PlainWindowController.xib, which has a window with delegate and windowController connections already set.
In a test, I've written this code:
PlainWindowController *strongWindowController = [[PlainWindowController alloc] initWithWindowNibName:#"PlainWindowController"];
__weak PlainWindowController *weakWindowController = strongWindowController;
[strongWindowController showWindow:nil];
strongWindowController = nil;
STAssertNil(weakWindowController, #"The window controller should have been deleted, wasn't");
When this test runs, the weak reference is not nil.
If I leave out the showWindow it is nil. If I use init instead of initWithWindowNibName, it is nil.
Does anyone know what's going on here? Thank you in advance for any guidance.
There’s no guarantee that an object under ARC hasn’t been added to the autorelease pool, in which case it won’t be freed until the end of the current event.
In your case, I strongly suspect somewhere within initWithWindowNibName: the controller gets retained and autoreleased.
If you really want to ensure your object is being freed, just subclass the -dealloc method and add an NSLog to it or break on it.
You generally shouldn't harbor "expectations" about when objects are deallocated if they've ever been passed to other code which you don't control.
Cocoa might have retained and then autoreleased the controller. Cocoa may retain the window controllers of any windows which are showing.
In general, when it comes to Cocoa memory management, you are supposed to make sure your own code follows the rules (which ARC largely does for you) and you should assume that other code follows the rules, but you can't assume that other code doesn't retain objects beyond where your interest ends. You should basically not care about what the other code is doing with respect to memory management.
If you really want to know what's happening, run your app under the Allocations instrument and explore the retain/release/autorelease history of your object after the point where you expected it to have been deallocated.
I had a similar issue when first using ARC. I unfortunately don't remember the details as this was more than a year ago. I eventually tracked it down as a circular retain problem using Instruments to monitor retain values, although not without losing a lot of hair.
I think the actual problem was with the delegate which I fixed with #property (unsafe_unretained) id delegate;
I ran into a similar issue yesterday with an ARC based project - a NSWindowController subclass would not deallocate, nor did -dealloc fire. I worked with Zombies, Allocations to no avail. The problem was very simple. There was a subclassed control within the window, and in that controls subclass .h header file a property was defined as:
#property id delegate;
correcting it to
#property (nonatomic, weak) id delegate;
fixed the issue.

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.

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.

EXC_BAD_INSTRUCTION when synthesizing #property (weak) IBOutlet NSWindow *window

I'm a newbie to ObjC/Cocoa and Mac development in general, and toying with the basics.
The simplistic default template for a new Cocoa application in Xcode 4.2 on Lion looks like this:
// AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#end
// Appdelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
#end
I've been using that as a basis for various experiments. Reading up on Automatic Reference Counting (which the project is set to use)—this article, for example—I assumed that one could, perhaps even should replace the assign qualifier for NSWindow *window with weak, but that does not seem to be the case.
The app builds fine, but hangs during startup, with Thread 1: Program received signal: "EXC_BAD_INSTRUCTION" in AppDelegate.m on the line with #synthesize window = _window;.
Changing the qualifier to strong makes the program work, but I fail to see how it would make sense to go from assign to strong. I'd gotten the impression that the pairings for non-ARC/ARC are assign/weak and retain/strong.
A more experienced coder friend suggested that even if the weak qualifier causes window to be prematurely deallocated and some access attempt on it to fail, the exception should be EXC_BAD_ACCESS, not EXC_BAD_INSTRUCTION.
I'm obviously missing something here, but I have no idea what.
EDIT: After a closer look at the crash-time gdb output, the same friend pointed me to this article by Mike Ash that sheds some light on this. Due to reasons beyond my understanding, NSWindow and some other classes that override retain and release can't be the target of zeroing weak references. Interestingly, changing the property declaration to this works:
#property (unsafe_unretained) IBOutlet NSWindow *window;
...even though unsafe_unretained isn't mentioned in Apple's documentation for Declared Properties.
With that, a REVISED QUESTION:
What would be the proper way to go here? Stick to assign despite mentions around the web that it shouldn't be used with ARC? Go for strong? Keep using unsafe_unretained since it seems to work? Something else?
Conceptually, 'weak' is the correct qualifier for a top-level IBOutlet on OS X (iOS is another story). However, to create a proper weak reference that zeroes on deallocation requires cooperation from the Objective C runtime. Classes that override retain or release break this support and so you can't create a weak reference to them. UIWindow is one such class.
That's why the template uses 'assign'. Perhaps it should really use the synonym 'unsafe_unretained' if ARC is enabled. In either case you have a simple weak reference that is not zeroed.
Mike Ash's blog discusses the issue with some Cocoa classes.
Look for it in the middle part of the page: Friday Q&A ARC. Look/Search for the text that starts with "ARC's implementation of zeroing weak references..."
The problem is that some classes don't handle the zeroing weak references that __weak brings. The solution is to go with what the normal ARC templates provide assign.
Well, to answer the second question, even Apple's templates use assign for window when using ARC. So you may be safe for now. But your mileage may vary in the future.
Mike Ash has a very good explanation of what's going wrong here (search for "ARC's implementation"). The gist of it is that the NSWindow class specifically does not support weak referencing: apparently because it relies on overriding retain and release with its own implementations.
I expect there's a few more such gotchas scattered through the legacy Cocoa classes, and these don't appear to be documented yet - instead, you find out through a runtime error. (I expect this will become a compiler warning as well at some point.)

Double releasing when it shouldn't be happening

I am really puzzled by this. I believe I am managing memory the correct way but executing the code suggests that I am double releasing the object. Here is the code and then I'll explain what is happening.
#protocol SomeDelegate <NSObject>
#required
- (id)initWithCols:(NSUInteger)Cols Rows:(NSUInteger)Rows;
#end
#interface SomeObject : NSObject <SomeDelegate> {
}
- (id)initWithCols:(NSUInteger)Cols Rows:(NSUInteger)Rows;
#end
#interface Layout : UIView {
id<SomeDelegate> someDelegate;
}
#property(retain) id<SomeDelegate> someDelegate;
- (id)initWithFrame:(CGRect)aRect Cols:(NSUInteger)Cols Rows:(NSUInteger)Rows;
#end
#implementation Layout
#synthesize someDelegate;
- (id)initWithFrame:(CGRect)aRect Cols:(NSUInteger)Cols Rows:(NSUInteger)Rows {
if(self = [super initWithFrame:aRect]) {
cols = Cols;
rows = Rows;
id<SomeDelegate> delegate = [[SomeObject alloc] initWithCols:cols Rows:rows];
[self setSomeDelegate:delegate];
//[delegate release];
}
return self;
}
-(void)dealloc {
[someDelegate release];
[super dealloc];
}
#end
Now when I uncomment out the "//[delegate release];" line in the constructor of the Layout class, then I get a "EXC_BAD_ACCESS" error and the application crashes when it attempts to dealloc. I have traced the crash to the release of the someDelegate object in the dealloc method of Layout class. If I leave it commented then the application works fine.
Can someone please explain why this is happening as it appears to be going against everything I have read about memory management in Objective-C.
Just a note that the code example actually works, however my code doesn't which follows the example. Could there be something inside of my actual SomeObject that is causing an autorelease?
Thanks in advance.
First, go back and reread the memory management rules just to make sure you are not missing anything obvious in your use of delegate elsewhere.
Next, turn on NSZombieEnabled (in your executable settings, Arguments panel, add an environment variable NSZombieEnabled set to YES).
Then add a dealloc method to your delagate if it does not have one already (make sure you call [super dealloc]!) and put a break point on there - that will tell you when your delagate is deallocated which will tell you when it is being released.
Alternatively, add trivial release/autorelease methods to your delegate class which do nothing but call through, and then breakpoint them and that will tell you exactly when it is being released.
Three final comments: in the standard naming convention for Objective C/Cocoa, you should have lowercase parameter fields, ie it should be:
- (id)initWithFrame:(CGRect)aRect cols:(NSUInteger)Cols rows:(NSUInteger)Rows;
When your ivar and property are named identically, it is very easy to accidently use the wrong one, so I recommend using a different ivar name and property name to avoid confusion, either use an _ prefix like Apple, or some other prefix to avoid confusion with Apple as well:
id<SomeDelegate> _someDelegate;
#synthesize someDelegate = _someDelegate;
And Apple recomends against using setters/getters in init/dealloc, so your init code should be:
_someDelegate = [[SomeObject alloc] initWithCols:cols Rows:rows];
As alluded to in the comments, the problem does not appear to be in the code posted.
I could ask for more information, but I'm firmly in the teach a man to fish camp....
A crash in -release will often be misleading in that various optimizations -- tail call optimizations, generally -- will make it look like the crash happened a frame or two above the actual call that crashed. When the crash happens, there isn't enough info on the stack to really identify the culprit.
Whenever you suspect you have any kind of a crash in -release or -dealloc, immediately turn on Zombies. This can be done through Instruments or via an environment variable or by calling a function in the Foundation very early in your program's execution.
Search for "Zombies" or "NSZombie" in the documentation included with the development environment (that'd be more of the "teach a man to fish" thing).
The problem was a MutableArray deep in a subclass that was created through a factory (autoreleased) but I was also releasing too. Unfortunately the crash wouldn't indicate which inherited dealloc was causing the crash and just stop on the first overridden dealloc.
The Zombie thing helped a little in that it told me an array was the culprit but not much else. I think there is more to NSZombie and requires more experience to take full advantage of it.