8

Something I have been wondering about properties for a while. When you are using properties, do you need to override the release message to ensure the properties are released properties?

i.e. is the following (fictitious) example sufficient?

@interface MyList : NSObject {
NSString* operation;
NSString* link;
}
@property (retain) NSString* operation;
@property (retain) NSString* link;
@end

@implementation MyList
@synthesize operation,link;
@end
Jay
  • 19,649
  • 38
  • 121
  • 184
  • 1
    Because NSString confirms to the NSCopying protocol, it is better to use @property (copy, readwrite) NSString *operation Also, if you use modern runtimes, you don't need to specify the instance variables: they will be synthesized as well. To learn more, search for Apple's "Objective-C 2.0 Programming Guide" and look for the sections named "Property Declaration Attributes" and "Property Implementation Directives". – Elise van Looij Oct 08 '09 at 11:39
  • +1 great question, was wondering the same thing exactly – andy Dec 23 '10 at 00:43

6 Answers6

13

You should always release the backing variables in dealloc:

- (void) dealloc {
   [operation release];
   [link release];

   [super dealloc];
}

Another way:

- (void) dealloc {
   self.operation = nil;
   self.link = nil;

   [super dealloc];
}

That's not the preferred way of releasing the objects, but in case you're using synthesized backing variables, it's the only way to do it.

NOTE: to make it clear why this works, let's look at the synthesized implementation of the setter for link property, and what happens when it is set to nil:

- (void) setLink:(MyClass *) value {
   [value retain]; // calls [nil retain], which does nothing
   [link release]; // releases the backing variable (ivar)
   link = value;   // sets the backing variable (ivar) to nil
}

So the net effect is that it will release the ivar.

Philippe Leybaert
  • 168,566
  • 31
  • 210
  • 223
  • 1
    Actually, if you're using synthesized ivars (ie, you declare the property but not a corresponding ivar), then an ivar will be generated for you. See my question here: http://stackoverflow.com/questions/1283419 – Dave DeLong Sep 07 '09 at 15:34
  • 3
    Some compilers didn't synthesize the ivar. That was fixed after the first compiler that supported synthesized ivars was released. Hence the confusion. – bbum Sep 07 '09 at 17:24
  • Better still, move from managed memory to garbage collection. Then, the example would be fine as written. – Jeremy W. Sherman Sep 07 '09 at 20:00
  • 2
    Lol, someones a java developer (: – Jay Sep 08 '09 at 22:10
  • @Jacob — You are aware that Objective-C 2.0 introduced garbage collection, correct? It may not apply in every situation (such as iPhone or when using frameworks that don't support it) but it's a great solution when you can use it, especially with the improvements in Snow Leopard. The garbage collector tends to be extremely smart and speedy. :-) – Quinn Taylor Sep 08 '09 at 22:55
3

In non-GC applications, yes. It is usual to assign nil instead of releasing the ivars. My best experience is to release ivars initialized with init and assign nil to properties with retain and copy mode.

In your case I would assign nil

- (void) dealloc {
   self.operation = nil;
   self.link = nil;
   [super dealloc];
}
Abizern
  • 146,289
  • 39
  • 203
  • 257
cocoafan
  • 4,884
  • 4
  • 37
  • 45
  • 1
    @gs not correct. You can release the ivar and set them to nil directly. Using the accessors can have odd side effects in rare circumstances. If you're observing a property on an object, and the object is set to nil, your observer might try to get other info from the obj, but if the set-to-nil happened in a -dealloc, strange things could happen. – Dave DeLong Sep 07 '09 at 15:36
  • This is a quirk of the syntax. One wishes that a synthesized or implicit"@properties_release();" could just be added to the dealloc method, in some future language spec. If objective-C 2.0 was going to be all things to all people, it seems bizarre to recommend something like this accessor-syntax, and then have to place a caveat on it about observers and property accessors in destructors. – Warren P Mar 31 '10 at 22:58
2

The best way to do this is:

- (void)dealloc {
    [operation release], operation = nil;
    [link release], link = nil;

    [super dealloc];
}

It would indeed be more convenient to use the generated setter methods

self.operation = nil;

but that is frowned upon. You don't always know which thread an object is deallocated on. Thus using an accessor may cause problems by triggering KVO notifications.

The catch here is that you need to adapt your dealloc to match the object management policy defined in your @property. E.g. don't go releasing a iVar backing an (assign) property.

Pierre Bernard
  • 3,148
  • 2
  • 23
  • 31
1

No, you override the -dealloc method. And yes, if you don't release your properties (or rather, the backing ivars), you will leak. So in your @implementation here you should have something like

- (void)dealloc {
    [operation release];
    [link release];
    [super dealloc];
}
Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
1

Synthesizing a property only creates getter and setter methods, and therefor won't release the ivar when the object is deallocated. You need to release the ivar yourself.

Tom Dalling
  • 23,305
  • 6
  • 62
  • 80
  • 1
    That only applies to declared properties that do *not* use the default (assign) attribute. Search for Apple's "Objective-c 2.0 Programing Guide" and read the section on "Declared Properties", particularly the part about dealloc. I Quote: "Declared properties do, however, provide a useful way to cross-check the implementation of your dealloc method: you can look for all the property declarations in your header file and make sure that object properties not marked assign are released, and those marked assign are not released." – Elise van Looij Oct 08 '09 at 11:30
0

In pre-ARC whenever you see new, alloc, retain and copy, whether it is an instance var or a property you must release. In ARC whenever you have a strong variable you must set it to nil. In either case you have to override dealloc().

nstein
  • 339
  • 2
  • 14