【问题标题】:Explicit getters/setters for @properties (MRC)@properties (MRC) 的显式 getter/setter
【发布时间】:2014-03-15 03:42:40
【问题描述】:

我在 2012 年年中开始使用 Objective-C 语言进行编程,当时 ARC 取代了 MRC 作为一种通用实践,几乎不需要学习后者。

现在我正在尝试了解 MRC 的一些基础知识,以加深我对 Objective-C 内存管理的了解。

我现在感兴趣的是,如何手动为声明的@propertiesgetters/setters

到目前为止,我发现的唯一合理示例来自 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;
}

我的猜测是,为(非原子,复制)做同样的事情,我应该写这样的东西:

- (NSNumber *)count {
    return _count;
}

- (void)setCount:(NSNumber *)newCount {
    [_count release];

    _count = [newCount copy];
}

所以问题是关于我不确定的其余组合:

如果有人可以向我展示在使用手动引用计数 (MRC) 的情况下应如何为以下 @property 声明编写显式 getter/setter 示例,我将不胜感激:

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)

【问题讨论】:

  • 检查这个link1link2
  • @pawan,我已经阅读了这两个链接,我认为它们与这个问题无关。还是谢谢。

标签: objective-c memory-management


【解决方案1】:

虽然@Gabriele 的答案是正确的,但我想写下我自己的答案,其中包含:

  1. 我在链接主题的研究:Immutable property for mutable ivar using MRC
  2. @robmayoff 发表评论
  3. 探索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];
}

注意:if (count != _count) 中不需要检查,因为 (copy) 会生成副本(objc 运行时源也有这种行为)。

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;
    }
}

附:最近我对这个回到过去的手动引用计数做了一些研究,让我与你分享以下我认为在这个主题上最好的链接:

【讨论】:

  • 很好的研究工作。我更新了我的答案以反映您的最新发现。我也相信你在 3) 中有一个错误。实现执行copy,而属性声明为retain
  • 谢谢,我已经确定了 3 号!
  • 抱歉拼错了你的名字,Gabriele!
  • 哈哈,没问题。这经常以非常接近 1 的概率发生;)
【解决方案2】:

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];
            }
        }
    }

注意:Objective-C 2.0 规范提到了锁是在内部使用的,但没有具体说明如何使用。您在上面看到的大致是原子 getter/setter 的样子,但可能并不准确。

正如您所读到的here,getter 中的retain/autorelease 舞蹈旨在防止另一个线程中的 setter 在我们返回值之前释放它。

4。 @property (assign) NSNumber *count;

    - (NSNumber *)count {
        @synchronized(self) {
            NSNumber *tmpCount = _count;
        }
        return tmpCount;
    }

    - (void)setCount:(NSNumber *)count {
        @synchronized(self) {
            _count = count;
        }
    }

注意:atomic 是默认值。

其他可能的属性修饰符是readwrite/readonly,但它们只会产生合成或没有setter的效果。

【讨论】:

  • 您能否评论一下为什么您的 3.(原子,保留)与我们在这里看到的不同:stackoverflow.com/questions/8382523/…(还包含保留自动释放)?那么谁错了:你还是链接的帖子?
  • @stanislaw 我的立场是正确的,retain/autorelease 确实需要,但您还需要将 retain 包装在 synchronized 块中。检查我编辑的答案。
  • @Gabrielle,感谢您的回答。我会等一会儿再接受你的回答,因为我想重新检查并理解你写的东西。
  • @Stanislaw,不客气。这已经是一个相当长的答案,所以我没有对实施发表太多评论。如果您有与我的回答相关的具体问题,请随时提问:)
  • 不幸的是,非原子保留和复制设置器具有不必要的竞争条件。如果在线程 1 上,setter 释放了_count,而在线程 2 上,getter 在线程 1 设置 _count = [count retain] 之前访问了_count,则线程 2 可以访问已释放的对象。在释放旧值之前,始终将新值存储在 _count 中。 Objective-C 运行时中的真正访问器正确地完成了它。请参阅objc-accessors.mm 中的reallySetProperty
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-31
  • 2023-03-07
  • 1970-01-01
相关资源
最近更新 更多