Reputation: 3629
I'm learning memory management for a while. Read both Apple's memory management guide as well as some other authors' book/blog/essay/post.
Still puzzling me is the whether should I write:
nameOfMySynthesizedProperty = [[NSObject alloc] init]; // version 1
or
nameOfMySynthesizedProperty = [[[NSObject alloc] init] autorelease]; // version 2
In a sample project, manual memory management is used and there is no dealloc
method, and the version 1 is used for all class properties/ivars. And sometimes some properties are not even synthesized but its getter is used,
These are not taught in those tutorial/guide I've ever read, however that sample project goes well without crash...
Anyone can give me some light...
Manual memory management is used in the sample project.
Another example
AppDelegate.h
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
}
@property (nonatomic, retain) UIWindow *window;
@property (nonatomic, retain) UIViewController *viewController;
@end
AppDelegate.m
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// To be inserted with the following choices of code
}
@end
Inside the AppDelegate.m
-> -(BOOL)application:application didFinishLaunchingWithOptions:
method, which of the following is correct for initializing self.window.rootViewController
? (Manual memory management is used. Xcode 5 is used.)
Version 1
self.window.rootViewController = [[UIViewController alloc] init];
self.viewController = [[[UIViewControllerDrawer alloc]init] autorelease];
self.window.rootViewController = self.viewController;
Version 2
self.window.rootViewController = [[[UIViewController alloc] init] autorelease];
self.viewController = [[[UIViewControllerDrawer alloc]init] autorelease];
self.window.rootViewController = self.viewController;
Version 3
self.viewController = [[[UIViewControllerDrawer alloc]init] autorelease];
self.window.rootViewController = self.viewController;
Here I know window
is a property (and the instance variable for it is also named as window
). But is window.rootViewController
an instance variable? Experiment result shows that version 3 is working, both version 1 and 2 crashes.
Upvotes: 1
Views: 1494
Reputation: 7534
You have several different question here and I'll try to address them all.
There is always a dealloc method, you may not be overriding it, but it is at the very least implemented by NSObject. you almost always need to override this method in your subclasses to release the objects ivars. with ARC you just set them to nil, but in MRC such as you have you need to send a release message to any retained or allocated variables.
The dealloc method is called automatically when an objects retain count reaches 0.
the code you posted has a problem where you are assigning an autoreleased object to an ivar and that object will cease to be valid after the autorelease pool is drained (typically the start of the event loop).
you use autorelease when you don't want to retain an object, but it needs to live on for the caller of the method. when a method returns an object that object should always be autoreleased as per the objective-c ownership rules this doesn't mean you always need to send the autorelease message yourself, however. if the object you are returning was autoreleased else where then you can simply return that object.
anything you alloc-init will have a retain count of 1 and you need to release it at some point or you have a leak.
you don't need to explicitly synthesize properties. the compiler will synthesize them for you. you have to pay attention to how the property is declared (and implemented if you do the implementation yourself) to know if assigning to the property will either increment the retain count, copy the object, or do a simple assign. I see in your updated question that you mean to be doing self.property = [[[NSObject alloc] init] autorelease]
because the properties are declared as retaining. you could instead do_property = [[NSObject alloc] init]
, which is fairly typical usage. you need to be aware of the semantics around properties before using the ivars directly (for example KVO notifications won't fire by assigning to the ivar).
just an aside about MRC vs ARC. many people claim that you should always use ARC (if you can help it) and never MRC. It is important that you understand that improperly using ARC can result in significantly slower code. I have seen "ARC" code that uses implicit strong references for a temporary value in a loop causing lots of unnecessary retain-release calls. Understanding MRC is imperative for writing good ARC code IMO, and dont let these people dissuade you from learning the ins and outs of memory management.
Upvotes: 4
Reputation: 299623
Neither. You should use ARC. There is very seldom a reason to use manual memory management today. (It is useful to understand how ARC applies memory management rules, but it is a bad idea to use it directly.)
If you absolutely must use manual memory management, then you also should not generally access ivars directly this way. Except in init
and dealloc
, you should do this:
self.property = [[[NSObject alloc] init] autorelease];
In init
, you should do this:
_property = [[NSObject alloc] init];
In either case (but only if you're using manual memory management, which you should not), you will need the following in dealloc
:
[_property release];
_property = nil;
The best reference for the precise rules is the Memory Management Policy.
But I cannot stress enough: if you are even asking these questions, you should be using ARC. And if you don't have to ask these questions, you should already know why you should use ARC. If you have some kind of very specialized problem that precludes ARC (such as running on 32-bit OS X), then you likely already know the rules and how to apply them correctly.
If you're encountering existing code with manual memory management, you should use "Edit>Refactor>Convert to Objective-C ARC…" which will fix it for you.
Upvotes: 6
Reputation: 21383
If you get an object instance from a method beginning with alloc/init, copy, mutableCopy, or new, you own it and are responsible for releasing it when you're done. Otherwise, you aren't responsible for releasing it. If you want to keep a non-owned object around, you must retain it, then release it when you're done with it. For the purposes of these rules, autoreleasing an object is the same as releasing it. An autoreleased object will be released at some point in the future (end of the current run loop in most cases).
In your question, you're directly setting an ivar. You don't want the object pointed to by the ivar to disappear out from under you, so you should not autorelease it. Unless the line in question is in your class's -init
method, you should use the setter instead and autorelease the object before passing it to the setter (self.nameOfMySynthesizedProperty = [[[NSObject alloc] init] autorelease];
). That way, the setter (assuming the property is strong
/retain
handles retaining the object, and will also handle releasing it if you set it again later to a different object.
Lastly, I appreciate and admire your learning manual memory management. I think it's important for Objective-C programmers to understand it. So if this is just a learning exercise, keep going how you're going. However, for writing real code, you should probably use ARC, which makes this whole question essentially moot.
Upvotes: 2