On May 6, 2009, at 21:34 , Jeff Johnson wrote:

Ownership 'transfer' is rare. If you call +alloc or -copy, for example, ownership is transferred to the caller. Otherwise, there's no such thing.

The fact that you think this is a testament to how well - autorelease works :-)

How about +[NSMutableString string] ? Do you think the NSMutableString class keeps ownership of the array you have created?

No, the NSMutableString class relinquishes ownership. But this does not mean that the caller acquires ownership.

OK, quiz time: the reason for NSMutableString to relinquish ownership is to (a) release the object (b) allow someone else to take ownership?

The documentation is absolutely, unmistakably, crystal clear on this: "You do not own objects returned from convenience constructors, or from other accessor methods."

EXACTLY. Autorelease allows ownership transfer from called methods to occur without thrusting ownership on those that don't want it.

This is largely incorrect. There is no need for an -autorelease in a getter, just like there is no need for the retain. *If* you do a retain, for whatever reasons, then you need to balance it with a release or an autorelease.

Retain/autorelease is the preferred way of implementing a getter method.

Some claim, many dispute. Wether it is 'preferred' or not, however, is irrelevant to what I said: it is not required and thus there is no need to do this. Alas, misunderstandings such as yours are exactly the sort of thing I foresaw when I co-wrote "Autoreleasing accessors considered harmful"

You need to re-read that document, because it does not say what you think it says.

I can't argue against these statements, because you've offered no argument in favor of them, so I'll just ignore them.

This is not a debate. This is me explaining to you how this stuff works.

Heh, I can't very well delete Apple's documentation. "The autorelease method, defined by NSObject, marks the receiver for later release."

Yes, but you don't get to say how much later.  Your caller does.

In response to this last argument (which is essentially the same in the three 'sections' immediately above): it's certainly true that the caller doesn't need to pass objects up to its own caller; indeed, this is not even possible if the caller has no return value.

Wether it passes the values up or not is not the point. The point is that you don't have any guarantee as to the lifetime of objects after your method has returned unless you own it, and you will not find such a guarantee in the docs.

The point is that the callee is not responsible for worrying about what the caller will do with the objects.

Sort of. The callee does not worry about this because it is completely out of his control. You do not get any guarantees.

If the callee ensures that the object remains valid within the caller's scope,

The callee cannot actually ensure this without owning the object. The wording in the docs is a little sloppy at this point. What it "ensures" is that it remains valid until it gets to the callers scope, and anyway, this is a guarantee for the *caller* not for the *callee*. The callee does not get any guarantees in this model except that the object will reach the caller.

that's the extent of its memory management job. It would be hard to do any more. How is the callee supposed to know when the caller is done with the object?

Exactly.


Now, in this particular case I don't think it's acceptable to take the dogmatic attitude that the caller has the right to do whatever it wants with the objects, because we have a bit of an unusual situation here, involving a weak reference. The delegating object cannot have a strong reference to its delegate, otherwise you'd have a retain cycle. The rules of memory management that apply to strong references don't fully apply here, we need to be very careful.

Yes, we need to be somewhat careful, which is why don't do crazy stuff like releasing an object from within a delegate method.


My view, to put it somewhat casually, is that in 'odd' situations such as this, object encapsulation is best served by having the object that's using unusual memory management techniques take responsibility for not screwing things up. In standard code, you have one main autorelease pool for the main thread, which is either automatically created by AppKit or, in a Foundation tool, you create at the beginning of main() and destroyed at the end. If you have threads, each thread has one main autorelease pool created at the beginning and destroyed at the end. Other than that, it's unusual to create your own pools. You may do it in a tight loop to keep memory from ballooning. It's really a rare and weird situation where you're creating a pool and then calling methods on your object's weak- referenced owner.

No, this is not 'weird' at all. In fact, NSXMLParser very likely *should* maintain autorelease pools, because its clients can't safely do this and there is quite a potential for growing the heap during XML parsing.


To me, it's madness to say that it should be standard practice to design an object around the possibility that an object it owns (strong reference) may create these rare and weird autorelease pool situations and possibly cause its own deallocation in mid-method. It's really hard to design an app around that idea.

Well, I've been doing it for maybe 15 years and it never seemed particularly hard to me.

You'll end up writing crazy, inelegant, hard to read, hard to understand code.

What's crazy and weird about:

        id parser = [NSXMLParser alloc] initWithData:myData];
        [parser parse];
        [parser release];

?

Trying to deallocate an object from within its delegate, now that's weird and crazy, as numerous people have pointed out to you.


It makes much more sense to code in a more straightforward way, for the common case, and if an object is going to do weird memory things with its delegate, it needs to take responsibility for not causing crashes and other problems. In this case, the delegating object knows when it's going to wrap the delegate calls in an autorelease pool, so it can easily account for that, whereas the delegate itself has no idea and would have a very hard time accounting for that. How does the delegate know when exactly in the future it's safe to actually release or autorelease its instance variable? You might say wait until dealloc, but it may need to re-use that instance variable for another object.

I'm not sure I understand what the alternative is that you're suggesting. Short of dealloc, when exactly is it safe for the delegate to relinquish ownership of the object?

The delegate never has ownership of the object.

According to your argument, you can't even assume it's safe in some kind of "didFinish" delegate method, because the object could still do weird stuff after calling didFinish on the delegate.

The only thing that would be weird here would be if the caller were actually deallocated when it returns from sending the "didFinish" message. Look at the following.

It's of course somewhat easier to work around this problem given the API of NSXMLParser, but you can't generalize to all delegate methods based on NSXMLParser. What about more async delegate like NSURLConnection?

It is the *owner* of the object that releases it, not the delegate.

Anyway, various people have now tried to explain to you how this stuff works and the fact that the docs do not say what you think or would like they say. Debating with us doesn't change the code or how it works.

Cheers,

Marcel

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to