• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Memory management question (passing objects to method)
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Memory management question (passing objects to method)


  • Subject: Re: Memory management question (passing objects to method)
  • From: Dietmar Planitzer <email@hidden>
  • Date: Thu, 3 Mar 2005 13:22:12 +0100


On Mar 3, 2005, at 3:58 AM, Tim Lucas wrote:

On 02/03/2005, at 4:46 PM, mmalcolm crawford wrote:
That said, this pattern is unusual, and you are encouraged to use standard accessor methods pervasively. Better than the above would be to simply invoke:

[object setBlah:nil];

And also just to add to the above, this is the pattern you should use in your dealloc methods (you all write delloc methods, right?!).

Sure, but not necessarily the way you recommend below :)

I would strongly advice against calling setter methods from an object's -init or -dealloc methods. The simple reason being that the state of an object is by definition undefined while it is being constructed or deconstructed. This is not a problem as long as you can guarantee that other objects are not able to inspect the state of your object while its executing its -init or -dealloc method. However, as soon as -init or -dealloc calls a setter, the setter may make the partially initialized / deallocated state of your object visible to other objects by either:

1) Sending a notification
2) Sending an KVO observation message
3) Storing data on the undo stack

Consider for example what would happen if the -setName: method below would send a "object changed its name" notification. If the notification gets posted by -setName: while it was invoked from -dealloc, then every observer of the notification would get a chance to look at your object which is currently in an undefined state because its being deallocated. Worse, an observer may decide to retain the notification sender (the object currently being deallocated), which naturally will have no effect because as soon as we return from the notification callout, our object will be freed. However, the observer still thinks he's working with a valid object, because after all, he retained it. Its just that that retain didn't have any effect because the retain count was already 0 and the object was already doomed to finish its finial march to the great object heaven. If the observer then tries to access the object at a latter time, it will likely crash the application. Debugging problems like this, are, well, interesting and highly time consuming.

If -setName: would store the old name on the undo stack, then we would have another interesting problem. The execution of -dealloc would result in a situation where the internal guts of the object would be spilled onto the undo stack, with no way to reconstruct the original object when the user invokes the redo command.

Even if we would correct the above two problems by precisely controlling when the object gets disconnected from the notification center and undo manager, there is one thing that we can not control: subclassing.

If our -init or -dealloc method calls a setter, assuming that our particular implementation of that setter will work as expected and free all instance variables associated with it, we still don't know if this is the case for a override of our setter in a subclass. The override may send notifications, though our implementation didn't. It may store old instance variable values on the undo stack, although our version didn't. Worse of all, it may introduce a caching scheme where the old instance variable value is not immediately freed but moved to a cache. The contents of that cache may then be leaked, if it doesn't get freed another way.

No, -init and -dealloc are special methods in the sense that, from the viewpoint of the outside world, they should be atomic. Atomic in the sense that other objects do not get a chance to observe / inspect the state of an object which is being constructed or deconstructed. As otherwise, observers may decide to keep a reference to an object which is about to die, or start to work with an object that is not yet fully initialized and ready to do its job.


While I'm here, another thing about passing nil to setters: again, I strongly advise against writing setters which accept random values especially nils. There are two reasons for this:


1) Setters which accept everything and your mother in law, have the tendency of hiding and propagating bugs in your application.

2) Most of the time, passing nil to a setter which takes an object has an unclear meaning. I.e. what exactly does it mean to pass nil to the below -setName: method ? Does it mean, remove the name ? (but what should the UI do for such an object ?) Does it mean, set the name to the empty string ? Does it mean, set the name to an arbitrarily chosen default name ?

I write all my setters in such a way that they always contain a bunch of good old assert() macro invocations at the very beginning, where I check that the passed in value is acceptable and in the valid range. I then let the developer build of the application always run from inside the debugger. This has the big advantage that when one of my setters gets called with a bogus value, that the debugger instantly stops the execution of the application at the point of the problem and prints out a nice stack backtrace. This makes hunting down bugs much easier as they get no chance to propagate away from the place of their creation.

Accepting nils in setters is especially problematic in ObjC because of that, in my opinion, highly unfortunate msg-sends-to-nil-get-ignored feature. Both things combined can make debugging a problem very hard because they make it so easy for nils to propagate throughout your application code and then blowing up your application where you would least expect it.

Just don't get me started regarding the msg-sends-to-nil-get-ignored feature or class posing :)


Regards,

Dietmar Planitzer


For example, if you have something like the following:

- (id)init
{
	if(self = [super init])
	{
		[self setName:@""];
	}
	return self;
}
- (void)setName:(NSString*)aString
{
	if(aString != name)
	{
		[name release];
		name = [aString retain];  // (or copy if you want)
	}
}

then your dealloc should look like:

- (void)dealloc
{
	[self setName:nil];
	[super dealloc];
}

- tim lucas

_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


_______________________________________________ Do not post admin requests to the list. They will be ignored. Cocoa-dev mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: This email sent to email@hidden
  • Follow-Ups:
    • Re: Memory management question (passing objects to method)
      • From: Tim Lucas <email@hidden>
References: 
 >Re: Re: Memory management question (passing objects to method) (From: Conor Dearden <email@hidden>)
 >Re: Re: Memory management question (passing objects to method) (From: Justin Spahr-Summers <email@hidden>)
 >Re: Memory management question (passing objects to method) (From: mmalcolm crawford <email@hidden>)
 >Re: Memory management question (passing objects to method) (From: Tim Lucas <email@hidden>)

  • Prev by Date: Re: DotMacKit not prebound
  • Next by Date: Re: Table Column Drawing Weirdness
  • Previous by thread: Re: Memory management question (passing objects to method)
  • Next by thread: Re: Memory management question (passing objects to method)
  • Index(es):
    • Date
    • Thread