Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicit getters/setters for @properties (MRC)

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)
like image 943
Stanislav Pankevich Avatar asked Feb 15 '14 18:02

Stanislav Pankevich


People also ask

Should setters and getters be private?

Usually you want setters/getters to be public, because that's what they are for: giving access to data, you don't want to give others direct access to because you don't want them to mess with your implementation dependent details - that's what encapsulation is about.

Do getters and setters permit different access levels?

Getters and setters can allow different access levels - for example the get may be public, but the set could be protected.

Can we use setter without getter?

The interface specifies that the property should at least have a public setter. The definition and accessibility of the getter is left to the implementing class. So if the interface contract only needs to write, get can be left open. No need to demand a public getter.


2 Answers

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.

like image 164
Gabriele Petronella Avatar answered Sep 27 '22 15:09

Gabriele Petronella


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.

like image 29
Stanislav Pankevich Avatar answered Sep 27 '22 15:09

Stanislav Pankevich