I am the author of one of the related topics , and I think that now I understand MRC enough to write this answer here:
1) You are obviously leaking a copy in getter (see also in the comments) - therefore it needs to be balanced using the appropriate autorelease call.
Also note that this copy inside your recipient is made because you need to return an immutable object, not because of the getters for @properties declared with (copy) . you will do it!
2) Your setter should not retain after mutableCopy , since mutableCopy already does +1 for you.
See the following citations from the Advanced Memory Management Programming Guide.
The basic rules of memory management.
Do you have any object you create
You create an object using a method whose name begins with "alloc", "new", "copy" or "mutableCopy" (for example, alloc, newObject or mutableCopy).
AND
Ownership policy implemented using held values
Ownership policies are implemented through reference counting, commonly referred to as the “save account” after the save method. Each object has a save account.
When you create an object, it has a storage counter of 1.
3) In my comments on the topic, @robmayoff shared a link to an open source runtime implementation: reallySetProperty in objc-accessors.mm , following these considerations:
Non-nuclear holders and copyists, unfortunately, do not need racing conditions. If on stream 1, the installer releases _count, and on stream 2, the getter accesses _count before stream 1 sets _count = [count keep], stream 2 can access the freed object. Always save the new value in _count before releasing the old value. The real Objective-C runtime assistant does this right. See RealSetProperty at objca-accessors.mm. - rob mayoff
4) You also lack dealloc , because you had to write it to the MRC.
5) [IMO, perhaps subjectively] Since your setter creates copies of the array argument, you do not need to have this if (_array != array) check since the (copy) setter task, I suppose, creates copies of the passed one , so I think that this may be omitted.
Having these points, I would write your example as follows:
- (NSArray *)array { id array; @synchronized (self) { array = [_array copy]; } return [array autorelease]; } - (void)setArray:(NSArray *)array { id oldValue; @synchronized (self) { oldValue = _array; _array = [array mutableCopy]; } [oldValue release]; } - (void)dealloc { [_array release]; [super dealloc]; }
In response to your question in the comments:
Is this normal and can it really be used in everyday practice?
I would say that it can be used in everyday practice with the following additional considerations:
1) You must transfer your ivar declaration to the private @interface SomeClass () category inside the .m file or private class extension.
2) You must make your getters / setters non- atomic, since the atomicity of this property is on your shoulders (you are already synchronized independently in both setters and getters).
3) See also customization from a related topic that omits ivar and uses the second @property declaration. In your case, it will look like this:
// .h @interface SomeClass : NSObject @property (nonatomic, strong, readonly) NSArray *array; @end // .m or private class extension @interface SomeClass() @property (nonatomic, strong) NSMutableArray *array; @end @implementation SomeClass // and here your getters/setters @end
This setting looks promising, although I have not tested it like yours.
PS I recently did some research for this back-to-the-past Manual Reference Counting, let me share with you the following links that I consider the best in this topic: