I am the author of one of the linked topics and I think now I understand MRC enough to write this answer here:
1) You're obviously leaking the copy in the getter (see it also in the comments) - so it should be balanced by corresponding autorelease
call.
Also note, that this copy inside your getter is done because of you need to return immutable object, not because of getters for @properties declared with (copy) require you to do so!
2) Your setter should not retain
after mutableCopy
, since mutableCopy already does +1 for you.
See the following quotes from Advanced Memory Management Programming Guide
Basic Memory Management Rules.
You own 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 Is Implemented Using Retain Counts
The ownership policy is implemented through reference counting—typically called “retain count” after the retain method. Each object has a retain count.
When you create an object, it has a retain count of 1.
3) In my topic's comments @robmayoff shared the link to open source implementation of runtime: reallySetProperty in objc-accessors.mm with the following reasoning behind it:
The nonatomic retain and copy setters unfortunately have an unnecessary race condition. If, on thread 1, the setter releases _count, and on thread 2 the getter accesses _count before thread 1 has set _count = [count retain], thread 2 may access a deallocated object. Always store the new value in _count before releasing the old value. The real accessor in the Objective-C runtime does it correctly. See reallySetProperty in objc-accessors.mm. – rob mayoff
4) You example is also missing dealloc since you were to write it under MRC.
5) [IMO, maybe subjective] Since your setter is creating copies of array argument, you don't need to have this if (_array != array)
check since the task of (copy) setter
is, I believe, to produce copies of what is passed, so I think this is may be omitted.
Having these points in mind I would write your example like the following:
- (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 answer to your question in the comments:
Is it normal and really can be used in the daily practice?
I would say, that it can be used in a daily practice with the following additional considerations:
1) You should move you ivar declaration into a private category @interface SomeClass ()
be it inside your .m file or a private class extension.
2) You should make your getters/setters nonatomic since atomicity of this property is on your shoulders (you already do synchronized on your own in both setter and getter).
3) See also the setup from linked topic which omits ivar and uses second @property declaration. In your case it would 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 setup looks promising though I haven't really tested it for the case like yours.
P.S. Recently I did some research for this back-to-the-past Manual Reference Counting, let me share with you the following links which I found to be the best on this topic: