NIB, setValue:forKey and retain (iOS) - memory-management

I know some mechanism of outlet connection when loading NIB, but I am not sure. So I'm asking some questions to ensure my knowledge. I assumed these things all true, but It's hard to find mention about these on reference documentation. Please point wrong and right things.
I have an IBOutlet defined like this: (Of course it's not recommended way)
#implementation
{
IBOutlet id var1;
}
#end
NIB loader (alloc | retain) & autorelease all top-level objects. So it will be dealloc on runloop turn ends without additional retain.
Connecting IBOutlets are done with KVC.
KVC uses accessor method primarily.
KVC uses setValue:forKey secondarily. And the IBOutlet will be handled by this method because there's no declared property or access method.
setValue:forKey retains the new value object.
setValue:forKey releases the old value object.
So top-level object connected to the IBOutlet will be retained once. So I have to release it to dealloc. This is why I must release objects connected to IBOutlet on dealloc method.
If the object connected another IBOutlet like the IBOutlet, it should be released once more to be dealloc.

Related

Is it safe to set a view's value in awakeFromNib?

Is it safe to do the following?
// in AppController.h
#interface AppController : NSObject
{
IBOutlet NSTextField *label;
}
#end
// in AppController.m
- (void)awakeFromNib
{
[label setIntValue:5];
}
Or is there a chance that label might not yet have been fully initialised when awakeFromNib is sent to the AppController instance?
Documentation says:
Important
Because the order in which objects are instantiated from an archive is not guaranteed, your initialization methods should not send messages to other objects in the hierarchy. Messages to other objects can be sent safely from within awakeFromNib—by which time it’s assured that all the objects are unarchived and initialized (though not necessarily awakened, of course).
In Fact, awakeFromNib is send to all objects the nib created and File's Owner , after creation of the objects and connecting outlets and actions is complete.
I'm not sure if it is safe.
But you should use viewDidLoad: for any view setup after the loading of the nib file.

NSWindow property set with the assign attribute instead of the strong

I notice the Mac App template has create the following:
#interface AppDelegate : NSObject
#property (assign) IBOutlet NSWindow *window;
According to the ARC guidelines all top level object should use a strong property but instead this is using an assign property. Would someone explain why?
A window will generally be "owned" by File's Owner, which will usually be your NSApplication instance (for the main nib) or an instance of NSWindowController, not necessarily the app delegate or the window delegate. This is why it wouldn't be appropriate for the reference to be strong inside the delegate class.
In Mac OS/X 10.7, NSWindow (along with several other Cocoa classes) didn't support management via ARC, so declared properties to NSWindow had to be assign rather than strong or weak. See the Transitioning to ARC and Nib Object Life Cycle documents for a more detailed discussion. The basic answer is that you can't use ARC-managed references for objects that override the release and retain methods.
In 10.8, it looks like NSWindow isn't on that list, but Xcode is still generating the assign attribute rather than weak.

delegate member in NSMenu

From my understanding the delegating class is the one which always inherits from NSResponder class and delegate is only available to classes that inherits from NSResponder. NSMenu inherits directly from NSObject, so then why do i see deletgate in the outlets?
Or is it that i misunderstood the options that you see after ctrl-click on an object in Interface Builder? I see Outlets, Referencing outlets, Received Actions , what does these mean then?
I am using Xcode 4 (10.7.3), if that matters.
I have no idea where you saw this but it's completely and totally incorrect. Delegation is just a pattern, there are no restrictions on the type of objects that can implement a delegate.
In fact, you are encouraged to use the delegation pattern in your own classes.
NSMenu declares its delegate property as an outlet in the header, which is why you see it in Interface Builder. You can do the same in your own code like so:
#interface YourObject : NSObject {}
#property (weak) IBOutlet id delegate;
#end
In Interface Builder, Outlets refers to the outlets that are defined in your class's header and that you can connect to other objects. Referencing Outlets and Referencing Actions connections from other objects to your object.

iOS Xcode 4 properties access

I switched to Xcode 4 recently and I don't really understand this new way to write accessors.
For example, in the application delegate class that is auto-generated when creating a new project, the window object is not declared in the #interface but just this way:
#property (nonatomic, retain) IBOutlet UIWindow *window;
Then, in the implementation file, we have the #synthesize window=_window;.
And in the functions, we have either self.window OR _window.
For example:
[self.window makeKeyAndVisible]; // in didFinishLaunchingWithOptions function
[_window release]; // in dealloc function
Can you explain me the difference, why there is nothing in the #interface, why we do #synthesize window=_window; instead of #synthesize window; and what is the difference between self.window and _window, I mean when do I have to call one more than the other?
I'm a bit lost, and feel like the new code I doing trying to do the same in not working properly...
Thanks!
"Why is there nothing in the #interface"
The runtime is synthesizing the ivar for you.
"Why do we do #synthesize window=_window;
This means that the window property will use an ivar named _window (by default the ivar name is the name of the property)
"What is the difference between self.window and _window?"
The former is using the window "getter" method (ie, foo = [self window]), and the latter is accessing the ivar directly.
"Why do I have to call one more than the other?"
It is generally considered unsafe to use accessor methods in your dealloc method, which means using the ivar is preferred.
This has nothing to do with Xcode 4. This is Objective-C 2.0 (which Xcode 4 uses by default when creating project templates).
I recommend reading the chapter on properties in The Objective-C Programming Language, that should make things much clearer
And doing things "the old way" will still work. You don't have to change everything overnight, simply remove the auto-created code if you don't like it, until you feel comfortable with the new syntax.

Question about NSWindowController and NSPersistentDocument Core Data Tutorial

In the Implementation Overview section of the NSPersistentDocument Core Data Tutorial it says:
…
One issue with creating the new top-level object in the nib file is that when you use bindings an object retains other objects to which it is bound. This means that bindings must be broken to ensure there are no retain cycles when a document is closed. Moreover, since the nib file the new controller owns contains top level objects and the controller’s class does not inherit from NSWindowController, you need to release the top level objects when the window is closed.
Why not just have the controller inherit from NSWindowController? Is there a reason this would not work? Or was this just a matter of style?
As commented below, I did get this to work with an NSWindowController subclass, and it does seem to save quite a bit of code.
Here is my subclass header:
#import <Cocoa/Cocoa.h>
#interface NewAccountSheetController : NSWindowController {
#private
BOOL isValidForInsert;
NSManagedObjectContext * managedObjectContext;
NSObjectController * objectController;
NSObjectController * targetController;
}
#property (setter=setValidForInsert:) BOOL isValidForInsert;
#property (nonatomic, retain) IBOutlet NSManagedObjectContext * managedObjectContext;
#property (nonatomic, retain) IBOutlet NSObjectController * objectController;
#property (nonatomic, retain) IBOutlet NSObjectController * targetController;
- (void)beginSheetForWindow:(NSWindow *)window;
- (IBAction)endSheet:(id)sender;
#end
And here is the implementation in a Pastebin.
I have no good idea how to describe the required bindings, etc. but if you're familiar with the above tutorial they should be straightforward to extrapolate… I think. :-)
In the example, its talking about controlling a sheet instead of a window. A sheet is technically a window component and not a window itself so it can't use a NSWindowController subclass as a controller. A window controller does not know how to handle a window owned by another window.
The text above is just reminding you that although the sheet controller looks very much like a window controller it is not one and that you have to manually handle releasing that is handled automatically by the window controller.

Resources