Reputation: 11388
I've started programming on Objective-C language in the middle of 2012 in the time when ARC replaced MRC as a general practice making the latter almost unnecessary to learn.
Now I am trying to understand some basics of MRC to deepen my knowledge of Memory Management in Objective-C.
The thing I am interested in now, is how to write getters/setters
for declared @properties
explicitly, by hands.
By this time the only sane example I found is from "Advanced Memory Management Programming Guide" by Apple:
@interface Counter : NSObject {
NSNumber *_count;
}
@property (nonatomic, retain) NSNumber *count;
@end;
- (NSNumber *)count {
return _count;
}
- (void)setCount:(NSNumber *)newCount {
[newCount retain];
[_count release];
_count = newCount;
}
My guess is that to make the same for (nonatomic, copy) I should write something like:
- (NSNumber *)count {
return _count;
}
- (void)setCount:(NSNumber *)newCount {
[_count release];
_count = [newCount copy];
}
So the question is about the rest of combinations I am not sure about:
I would thankful for someone who could show me examples of how explicit getters/setters should be written for the following @property declarations given Manual Reference Counting (MRC) is used:
1. @property (nonatomic, retain) NSNumber *count;
2. @property (nonatomic, copy) NSNumber *count;
3. @property (atomic, retain) NSNumber *count;
4. @property (assign) NSNumber *count;
5. What else is used often under MRC? (please share, if any other combinations exist)
Upvotes: 9
Views: 4084
Reputation: 11388
While @Gabriele answer is correct, I want to write my own answer containing:
1) @property (nonatomic, retain) NSNumber *count;
- (NSNumber *)count {
return _count;
}
- (void)setCount:(NSNumber *)count {
if (count != _count) {
id oldValue = _count;
_count = [count retain];
[oldValue release];
}
}
2) @property (nonatomic, copy) NSNumber *count;
- (NSNumber *)count {
return _count;
}
- (void)setCount:(NSNumber *)count {
id oldValue = _count;
_count = [count copy]; // retains (+1)
[oldValue release];
}
Note: no need in if (count != _count)
check since (copy) produces copies (objc runtime source also behaves this way).
3) @property (atomic, retain) NSNumber *count;
- (NSNumber *)count {
NSNumber *count;
@synchronized(self) {
count = [_count retain]; // +1
}
return [count autorelease]; // delayed -1
}
- (void)setCount:(NSNumber *)count {
id oldValue;
@synchronized(self) {
oldValue = _count;
_count = [count retain];
}
[oldValue release];
}
4) @property (assign) NSNumber *count;
- (NSNumber *)count {
NSNumber *count;
@synchronized(self) {
count = _count;
}
return count;
}
- (void)setCount:(NSNumber *)count {
@synchronized(self) {
_count = count;
}
}
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:
Advanced Memory Management Programming Guide (this is the MUST)
An In-depth Look At Manual Memory Management In Objective-C (this one too!)
Upvotes: 5
Reputation: 108159
@property (nonatomic, retain) NSNumber *count;
- (NSNumber *)count {
return _count;
}
- (void)setCount:(NSNumber *)count {
if (count != _count) {
NSNumber *oldCount = _count;
// retain before releasing the old one, in order to avoid other threads to
// ever accessing a released object through the `_count` pointer.
_count = [count retain];
// safely release the old one.
[_oldCount release];
}
}
@property (nonatomic, copy) NSNumber *count;
- (NSNumber *)count {
return _count;
}
- (void)setCount:(NSNumber *)count {
NSNumber *oldCount = _count;
_count = [count copy];
[_oldCount release];
}
@property (atomic, retain) NSNumber *count;
- (NSNumber *)count {
@synchronized(self) {
NSNumber *tmpCount = [_count retain];
}
return [tmpCount autorelease];
}
- (void)setCount:(NSNumber *)count {
@synchronized(self) {
if (count != _count) {
[_count release];
_count = [count retain];
}
}
}
Note: the Objective-C 2.0 specification, mentions that locks are used internally, but it doesn't specify exactly how. What you see above, is roughly what an atomic getter/setter would look like, but it might not be accurate.
As you can read here, the retain
/autorelease
dance in the getter is meant to prevent a setter in another thread releasing the value before we can return it.
@property (assign) NSNumber *count;
- (NSNumber *)count {
@synchronized(self) {
NSNumber *tmpCount = _count;
}
return tmpCount;
}
- (void)setCount:(NSNumber *)count {
@synchronized(self) {
_count = count;
}
}
Note: atomic
is the default.
Other possible modifiers for properties are readwrite
/readonly
, but they will just have the effect of synthesizing or not the setter.
Upvotes: 12