Explicit getters/setters for @properties (MRC)

大城市里の小女人 提交于 2019-12-29 04:23:07

问题


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)

回答1:


1. @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];
        }
    }

2. @property (nonatomic, copy) NSNumber *count;

    - (NSNumber *)count {
        return _count;
    }

    - (void)setCount:(NSNumber *)count {
        NSNumber *oldCount = _count;
        _count = [count copy];
        [_oldCount release];
    }

3. @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.

4. @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.




回答2:


While @Gabriele answer is correct, I want to write my own answer containing:

  1. My research in linked topic: Immutable property for mutable ivar using MRC
  2. Comment by @robmayoff
  3. exploration of objc runtime

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!)

  • What clang taught us about Objective-C properties

  • Memory and thread-safe custom property methods

  • Source code of objc runtime.



来源:https://stackoverflow.com/questions/21802069/explicit-getters-setters-for-properties-mrc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!