views:

357

answers:

3

Hey everyone,

The more I code, the more I get lost ... so I decided to create a topic entirely dedicated to the memory management for me (and others) not to waste hours understanding obj-c basics ... I'll update it as new questions are asked !

Okay below is some examples :

// myArray is property (retain)
myArray = otherArray;

//myArray isn't a property
myArray = otherArray;

//myArray is a property (retain)
myArray = [[NSArray alloc] init];

//myArray isn't a property
myArray = [[NSArray alloc] init];

--- So, if I understand ... when you put self.myArray you tell Xcode to use the getter or setter but when you just do myArray, you are responsible for everything, right ?

[SOLVED] UPDATE1 : Is there a difference between :

//myArray is a property
myArray = otherArray; // it is only a reference, releasing otherArray will imply releasing myArray
self.myArray = otherArray; // otherArray is sent a retain message so releasing otherArray will still keep myArray in memory

--- Yes, there is a difference (see comments above)

[SOLVED] UPDATE2 : Is myArray below equal to nil ?

NSArray *myArray;

--- Kubi : Yes, it is equal to nil.

[SOLVED] UPDATE3 : does it count for 2 retains ? One retain from self and one retain from alloc ? Is this a memory leak ?

self.myArray = [[NSArray alloc] init];

--- Kubi : Yes, this is a memory leak !

[SOLVED] UPDATE4 : the property takes care of everything ? no need to alloc or release ?

self.myArray = [NSArray array];

--- We here use the setter so that the array is retained properly

[SOLVED] UPDATE5 : Are these two blocks the same ?

//myArray is a retained property

self.myArray = [NSArray array]; //retain
self.myArray = nil; //release and set to nil

myArray = [[NSArray alloc] initWithArray]; //retain
self.myArray = nil; //release and set to nil

--- Kubi : Yes, they're identical

Thanks for the time.

Gotye.

+4  A: 

First, I'm assuming that you have a property called myArray and an iVar called myArray? If so, cases 1,2 are identical and 3,4 are identical. If you need to set a property of your current class, you must do it through one of the following methods:

self.myArray = otherArray;
[self setMyArray:otherArray];

the line myArray = otherArray will only set the iVar, never the property.

Second part, you're asking about memory management. Step one: read Apple's Guide. It really is required reading. Don't worry if you don't completely understanding, keep reading it once a month and it'll crystalize eventually.

Step two: remember this rule of thumb: If you alloc, copy, new, or retain an object, you are responsible for releasing that object, if you don't, it will be leaked.

In all other cases, you are not responsible for releasing the object, but it will be released eventually. If you need to keep it around, you need to retain it (and, of course, release it later).

Back to your example, in the first two cases, if you don't retain myArray it'll be released at some point after this code block. If you try and message that object later, you'll get an error. In the second two cases, if you don't release the myArray object at some point, it will be leaked.


Update 1 Very big difference. The two lines are completely different. The important thing to realize about dot syntax is that these two lines are exactly equivalent:

self.myArray = otherArray;
[self setMyArray:otherArray];

Notice the second line is a method call. Theoretically you could put anything you wanted in that method. You could set myArray to nil, or set it to someOtherArray, or update twitter or whatever.


Update 2 Yup, pointers in Obj-C are initialized to nil.


Update 3 Exactly. If the myArray property is declared as retain and you're using the default synthesizers you will be causing a memory leak.

Update 5 Also exactly right.

kubi
Thanks a lot ;)
gotye
A: 

The best place to find an answer for this would be in the relevant Apple documentation that explains all about memory management. Having said that, you're only using the ivars here, you're not setting your ivar using the ObjC generated setters. As kubi says, you'd have to say

self.myArray = otherArray;

in order to use myArray's "property"ness.

saramah
+1  A: 

Kubi's answer is good. Rereading Apple's Guide until you grok it is really mandatory.

In the mean time, you may benefit by adopting this strict set of practices I follow to avoid accidental memory errors. These prescribe a little more typing than is strictly necessary, and they're probably slightly less efficient at runtime than they could be, but following these rules consistently will protect you against the most common memory management errors. Then as you become more comfortable with memory management, you may choose to selectively deviate from these rules, although I still rarely do.

  1. Declare a property for every object instance variable you create. Declare it as (nonatomic, retain), unless it's an object your class doesn't own, like a delegate, which would create a circular reference. In that case, declare it as (nonatomic, assign) to avoid leaking all the objects in that cycle.

    @property (nonatomic, retain) NSString *title;
    @property (nonatomic, assign) id <WidgetDelegate> delegate;
    
  2. Even if an object instance variable is intended only for private use by the class, declare a property for it in a category at the top of your .m file so that the synthesized setter method can take care of memory management for you.

    // Widget.m
    @interface Widget()
    @property (nonatomic, retain) NSString *privateState;
    @end
    
    
    @implementation Widget
    @synthesize title, delegate, privateState;
    // ...
    @end
    
  3. Any time you assign an instance variable object, always set it through the property using self.

    self.title = @"Title";
  4. In your dealloc, set every object property to nil. If you've followed the above practices, this will simultaneously release your instance variables properly and set them to nil to guard against EXC_BAD_ACCESS. Make dealloc the first method in your class so you don't forget any properties.

    - (void) dealloc {
        self.title = nil;
        self.delegate = nil;
        self.privateState = nil;
        [super dealloc];
    }
    
  5. For every custom class you write, make sure it has at least one class factory method that delegates to an init method with the same parameters and autoreleases the returned object. This confines almost all alloc and init calls to these factory methods rather than scattering them throughout your code.

    - (id)initWithTitle:(NSString *)theTitle delegate:(id )theDelegate {
        if (self = [super init]) {
            self.title = theTitle;
            self.delegate = theDelegate;
            self.privateState = @"start";
        }
        return self;
    }
    + (id)widgetWithTitle:(NSString *)theTitle delegate:(id )theDelegate {
        return [[[self alloc] initWithTitle:theTitle delegate:theDelegate] autorelease];
    }
    
  6. Whenever you instantiate an object, always do it through a factory class method if possible. This gives you an autoreleased object, so you don't have to release it unless you retain it.

    self.widget = [Widget widgetWithTitle:@"My Widget" delegate:self];
    
  7. When you need to instantiate an object that has no appropriate factory class method, autorelease it on the same line, so you don't forget to do it later. (Exception: release manually if you're doing this thousands of times in a tight loop.)

    self.containerView = [[[UIView alloc] initWithFrame:self.bounds] autorelease]; 
    
  8. If you're releasing an object that has a delegate or similar property that points back in a circular reference, set that property to nil first. This prevents EXC_BAD_ACCESS in the event that an object outlives its delegate and tries to call a method on the delegate after it's been dealloced.

    - (void)dealloc {
        self.widget.delegate = nil;
        self.widget = nil;
        self.containerView = nil;
        [super dealloc];
    }
    

Many experienced developers manage memory successfully without following all of these practices. If you understand memory management and don't tend to have memory related bugs, I'd certainly encourage you to stick with whatever works for you. But if you're new to iPhone memory management, or if your code is plagued with accidental memory related bugs, I hope you find these practices as helpful as I have.

cduhn
I would upvote this 20 times if I could.
willc2