使用 MRC 的可变 ivar 的不可变属性 [英] Immutable property for mutable ivar using MRC

查看:49
本文介绍了使用 MRC 的可变 ivar 的不可变属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天我在面试时被问到一个问题:

Today I was at interview and was asked a question:

手动生成 setter 和 getter 以使用手动引用计数进行正确的声明:

Generate setter and getter by hands for proper declaration using manual reference counting:

@interface SomeClass : NSObject 
{
     NSMutableArray* _array; 
}
@property (copy) NSArray* array;

@end

我的回答是:

- (NSArray *)array 
{
     @syncronized (self)
     {
         return [_array copy];
     }  
}

- (void)setArray:(NSArray *)array 
{    
    @synchronized (self)    
    {    
      if (_array != array)
      {
         [_array release];
         _array = [array mutableCopy];
         [_array retain]
      }    
    } 
}

我从未使用过 MRC,因此不确定答案的正确性.请帮我更正此代码并附上说明!

I never worked using MRC so not sure about correctness of an answer. Please help me to correct this code with description!

推荐答案

我是 其中一个链接主题,我想现在我对 MRC 的了解足以在这里写下这个答案:

I am the author of one of the linked topics and I think now I understand MRC enough to write this answer here:

1) 您显然在 getter 中泄露了副本(也可以在评论中查看)-因此应该通过相应的 autorelease 调用来平衡.

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.

另请注意,getter 中的这个 copy 之所以完成,是因为您需要返回不可变对象,而不是因为使用 (copy) 声明的 @properties 的 getter 需要你这样做!

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) 你的 setter 不应该在 mutableCopy 之后 retain,因为 mutableCopy 已经为你做了 +1.

2) Your setter should not retain after mutableCopy, since mutableCopy already does +1 for you.

请参阅高级内存管理编程指南

基本内存管理规则.

您拥有您创建的任何对象

You own any object you create

您使用名称以alloc"、new"、copy"或mutableCopy"开头的方法(例如,alloc、newObject 或 mutableCopy)创建对象.

You create an object using a method whose name begins with "alloc", "new", "copy", or "mutableCopy" (for example, alloc, newObject, or mutableCopy).

还有

使用保留计数实施所有权政策

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.

当您创建一个对象时,它的保留计数为 1.

When you create an object, it has a retain count of 1.

3) 在我的主题评论中,@robmayoff 分享了运行时开源实现的链接:reallySetProperty in objc-accessors.mm 其背后的推理如下:

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:

不幸的是,非原子的保留和复制设置器有一个不必要的竞争条件.如果在线程 1 上,setter 释放了 _count,并且在线程 2 上,getter 在线程 1 设置 _count = [count retain] 之前访问了 _count,则线程 2 可以访问已释放的对象.在释放旧值之前,始终将新值存储在 _count 中.Objective-C 运行时中的真正访问器会正确执行此操作.参见objc-accessors.mm 中的reallySetProperty.– 罗伯梅奥夫

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) 您的示例也缺少 dealloc,因为您要在 MRC 下编写它.

4) You example is also missing dealloc since you were to write it under MRC.

5) [IMO,可能是主观的] 由于您的 setter 正在创建数组参数的副本,因此您不需要检查此 if (_array != array),因为 (copy) setter 是,我相信,产生所传递内容的副本,所以我认为这可能被省略.

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) 您应该将您的 ivar 声明移动到私有类别 @interface SomeClass () 中,无论是在您的 .m 文件中还是私有类扩展名中.

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) 你应该让你的 getter/setter 非原子,因为这个属性的原子性在你的肩上(你已经在 setter 和 getter 中自己同步了).

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) 另请参阅链接主题中的设置,该主题省略了 ivar 并使用了第二个 @property 声明.在您的情况下,它看起来像这样:

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:

深入了解 Objective-C 中的手动内存管理(这个也是!)

clang 教了什么我们关于 Objective-C 的属性

内存和线程-安全的自定义属性方法

objc 运行时源代码.

这篇关于使用 MRC 的可变 ivar 的不可变属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆