> Unfortunately, I don’t remember the specifics anymore. This happened when I
> was converting Pacifist from MRC (Medieval Reference Counting ;-) ) to the
> newer Objective-C 2.0 with the @property syntax and ARC, which was years ago
> (nowadays, I’m converting it to Swift). I do think it had something to do
> with my model objects representing a file or folder inside a package; when
> opening the OS X installers, there end up being a *lot* of these, and some
> operations—I don’t remember exactly what—went from “Hmm, this is taking a
> little while” to “Hang on, let me go make a cup of coffee” after the
> conversion. I can’t remember if this was due to the spinlock, the autorelease
> pool getting slammed, or both, but going back and making all the @properties
> nonatomic solved it.
In general, if nonatomic really made the difference, this sounds like something
was hammering the property way more than it should - so I guess the actual bug
would be elsewhere, but the atomic just made it more visible.
>> 0000000100000e42 callq 0x100000ec8 ## symbol stub for:
>> _objc_retainAutoreleasedReturnValue
This is where the problem occurs: It's calling
objc_retainAutoreleasedReturnValue, when it should call objc_retain.
> As you can see, objc_retainAutoreleasedReturnValue is called as soon as we
> receive the result of valueForKey:, and is not released until Baz() exits,
> thus ensuring that ‘foo' will remain valid until we are done with it.
Except that what was returned never was retained and autoreleased! valueForKey:
just calls the property. If it does not retain and autorelease, what it returns
is not retained and autoreleased. The following code demonstrates this easily:
> #import <Foundation/Foundation.h>
>
> @interface Foo: NSObject
> @property (nonatomic, retain) Foo *test;
> @end
>
> @implementation Foo
> - (id)retain
> {
> NSLog(@"retain");
> return [super retain];
> }
>
> - (id)autorelease
> {
> NSLog(@"autorelease");
> return [super autorelease];
> }
> @end
>
> int main()
> {
> Foo *f = [Foo new];
>
> [f setTest: [Foo new]];
> [f valueForKey: @"test"];
>
> return 0;
> }
(compile as MRC, as ARC does not allow overriding retain / autorelease)
This outputs retain once instead of twice and no autorelease. Using ARC does
not change how valueForKey: behaves.
=> You call objc_retainAutoreleasedReturnValue on something that is not
retained or autoreleased.
=> You can end up with a dangling pointer.
> To my mind, in an ARC world, autorelease is nothing but an unneeded
> performance hit
This is not true. There's a neat little hack which makes sure the object never
is autoreleased when using ARC: It looks at the callsite to see if
objc_retainAutoreleasedReturnValue is called, and if so never puts it into the
autorelease pool.
> which only gains relevance if there is a chance that legacy MRC code might
> try to access the property
MRC is not legacy. Some people just prefer it.
> and in a typical modern project, the only MRC code I can imagine being
> involved would be in the Cocoa frameworks themselves. And if framework code
> is grabbing a value from code from God knows where that might do God knows
> what, not copying or retaining the value, and then, before it’s done, calling
> a callback that might change the unretained value that it grabbed—well, I’d
> argue that’s a bug in the framework.
So you'd argue to always add an extra retain + autorelease in valueForKey:?
This would over-retain in the atomic case and retain in the nonatomic case.
--
Jonathan
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Objc-language mailing list ([email protected])
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/objc-language/archive%40mail-archive.com
This email sent to [email protected]