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.)
Related
I hate doing following
//in file.h
#property (strong) NSString *reuseIdentifier;
//in file.m
#synthesize reuseIdentifier = _reuseIdentifier;
This feels so redundant. I get the distinction of concepts between property in which is named "reuseIdentifier" and memory block that's named "_reuseIdentifier" but why can't the xcode IDE do the work by itself?
I feel like I am doing chores.
It's not been necessary to explicitly implement or synthesize Objective-C properties since Xcode 4.4 in 2012. See the Xcode 4.4 section of the archived "What's New in Xcode" documentation:
Objective-C #properties are synthesized by default when not explicitly implemented.
This question already has answers here:
Do declared properties require a corresponding instance variable?
(6 answers)
Closed 8 years ago.
For example, in the following codes.
#interface TUTViewController : UIViewController
{
NSTimer *timer;
}
#end
and
#interface TUTViewController : UIViewController
#property (weak, nonatomic) NSTimer *timer;
#end
In which scenario do we use the first method to declare variable?
You are going to get lots of opinions on this, often stated as hard fast rules.
Example:
Maddy: Never put ivars in the .h. ivars should always be private
meaning they do not belong in the public .h. If you create ivars, put
them in the .m file
I have tremendous respect for Maddy, but I disagree with him on this one.
If you put your iVars in your .m file, they are hidden from other classes, but they are also hidden from subclasses that you create.
I prefer to mark my instance variables as #protected, which makes them available to subclasses, but not to other classes.
Others will tell you to make EVERYTHING a property. Before ARC, it made sense to save all your objects in properties, since you could use the setter on the property to manage the memory on your objects. (When assigning a value to a retained property, the setter would first release any old value, then retain the new value.) Now ARC takes care of that for you even for iVars, so the argument for making everything a property is less.
What I do is to make everything an iVar, unless:
I need a custom getter or setter method with special behavior.
I want to access the value from another object.
I need to mark a property as "atomic" for access from another thread. (get in the habit of declaring all of your properties as "nonatomic." If you don't know what atomic is for for, you want nonatomic. Atomic properties are slower than nonatomic.)
As a matter of policy I NEVER access another object's iVars except trough a property.
There is a small but real amount of overhead in using a property rather than an instance variable. A property read/write always makes a method call. An iVar accesses the memory directly without the overhead of a method call. Usually the difference is too small to matter. But, if you're doing millions of operations, like doing something to every pixel in a large image, or handling callbacks from processing video or audio samples in real-time, the difference can be large.
I would highly suggest to use #properties unless there is a very good reason not to. It's true the discussion is a religious one more than a technical one but since we are probably all followers of the Cult of Mac, if Apple prefers you to use #properties then that's the standard. In my opinion both Apple documentation and Xcode aren't as pushy on standards like ReSharper would do in Visual Studio for instance (it warns when you don't use var for example). That's a pity because that would make it easier for me to pick up code after somebody else.
There is a way to "hide" #properties in a .m file, you should declare it as follows:
#interface ABCMySpiffyClass ()
#property (weak, nonatomic) IBOutlet UIImageView *spiffyImage;
#property (weak, nonatomic) IBOutlet UILabel *spiffyTitle;
#end
These are not completely private to another consumer of your class but it is hidden at first sight. This should tell the other developer that he or she should not use them. I think public/private has more to do with documentation as it has to do with application security for most apps.
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.
This is a style question:
Because Apple reserves the "_" privatization for its keywords, I was thinking of something along the lines of the following:
#import <Cocoa/Cocoa.h>
#define _(name) pvt_##name
#interface SFMeasureViewController : NSViewController {
#private
NSTextField *_(label);
}
#property (retain) IBOutlet NSTextField *label;
#end
#implementation SFMeasureViewController
#synthesize label = _(label);
#end
This is to help force the difference between [self label] and using label when it comes to retaining, and disposing of the variable properly. Here, using the term "label" within the code returns an error, forcing the user to distinguish between a call to self.label or _(label).
Now _(label) contains 2 more characters (shift-characters at that) than _label does. Is there any other good conventions out there? vLabel? Nothing is as quite as clear as _label but since its reserved, I don't want to use it.
Thoughts, critiques? This is for a style guideline at work, for primarily C++ work using Objective-C++ when necessary.
Thanks,
Well, Apple recommends not to use _ as the first letter of anything, especially on method names. But as for instance variables, they themselves go against this principle in their sample codes. So I think _... is perfectly fine for that, without making the macro. I like the property names var vs. the backing instance variable theVar, too. More about this, see the discussion here in SO.
In the new runtime (i.e. 64 bit on Mac, or iPhone OS, or iPhone simulator starting the ones coming with XCode 4) you don't even have to declare a backing instance variable explicitly; an ivar is created by the compiler when you #synthesize it, and you can't access that ivar directly. Thus, if you are OK with supporting only those platforms, that's the best approach.
Actually, it is not hard to distinguish label/self.label inside of module, so I doesn't see any problem in using the same name for property and field.
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.