今天我接受采访时被问到一个问题:
手动生成二传手和吸气剂,使用手动参考计数进行适当的声明:
@interface SomeClass : NSObject
{
NSMutableArray* _array;
}
@property (copy) NSArray* array;
@end
Run Code Online (Sandbox Code Playgroud)
我的回答是:
- (NSArray *)array
{
@syncronized (self)
{
return [_array copy];
}
}
- (void)setArray:(NSArray *)array
{
@synchronized (self)
{
if (_array != array)
{
[_array release];
_array = [array mutableCopy];
[_array retain]
}
}
}
Run Code Online (Sandbox Code Playgroud)
我从未使用过MRC,所以不确定答案的正确性.请帮我修改这段代码并附上说明!
我是其中一个链接主题的作者,我想现在我理解MRC足以在这里写下这个答案:
1)你显然是在getter中泄露了这个副本(在评论中也看到了它) - 所以它应该通过相应的autorelease调用来平衡.
还要注意,你的getter 中的这个副本是完成的,因为你需要返回不可变对象,而不是因为声明了@properties ( get)的getter 要求你这样做!
2)你的setter不应该retain在之后mutableCopy,因为mutableCopy已经为你做了+1.
请参阅" 高级内存管理编程指南"中的以下引用
基本内存管理规则.
您拥有自己创建的任何对象
使用名称以"alloc","new","copy"或"mutableCopy"开头的方法(例如,alloc,newObject或mutableCopy)创建对象.
和
使用保留计数实施所有权政策
所有权策略通过引用计数实现 - 通常在retain方法之后称为"保留计数".每个对象都有一个保留计数.
创建对象时,其保留计数为1.
3)在我的主题评论中@robmayoff分享了运行时的开源实现的链接:objc-accessors.mm中的reallySetProperty,后面有以下推理:
不幸的是,非原子保留和复制装置具有不必要的竞争条件.如果在线程1上,setter释放_count,并且在线程2上,getter在线程1设置_count = [count retain]之前访问_count,则线程2可以访问解除分配的对象.始终在释放旧值之前将新值存储在_count中.Objective-C运行时中的真实访问器正确执行它.请参阅objc-accessors.mm中的reallySetProperty. - 抢劫
4)你的例子也缺少dealloc,因为你是在MRC下写的.
5)[IMO,也许是主观的]因为你的setter正在创建数组参数的副本,所以你不需要进行这项if (_array != array)检查,因为(copy) setter我相信,任务是生成传递的副本,所以我认为这可能是被省略.
牢记这些要点我会写下你的例子,如下所示:
- (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];
}
Run Code Online (Sandbox Code Playgroud)
在评论中回答你的问题:
它是正常的,真的可以用于日常实践吗?
我想说,它可以用于日常实践中,并考虑以下因素:
1)您应该将ivar声明移动到@interface SomeClass ().m文件或私有类扩展中的私有类别中.
2)你应该让你的getter/setter 非原子,因为这个属性的原子性在你的肩上(你已经在setter和getter中自己同步).
3)另请参阅链接主题的设置,该设置省略了ivar并使用了第二个@property声明.在你的情况下,它看起来像这样:
// .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
Run Code Online (Sandbox Code Playgroud)
这个设置看起来很有希望虽然我还没有真正测试过像你这样的情况.
PS最近我对这个回到过去的手动参考计数做了一些研究,让我与大家分享以下链接,我发现这个主题是最好的:
高级内存管理编程指南(这是必须的)
深入了解Objective-C中的手动内存管理(也是这个!)
| 归档时间: |
|
| 查看次数: |
602 次 |
| 最近记录: |