使用具有通用 setter 和 ARC 的 Objective-C 动态属性
Posted
技术标签:
【中文标题】使用具有通用 setter 和 ARC 的 Objective-C 动态属性【英文标题】:Using Objective-C Dynamic properties with generic setter and ARC 【发布时间】:2013-12-17 22:06:42 【问题描述】:我想将动态属性与通用 getter/setter 一起使用,但似乎在某些情况下,ARC 会在不应该释放对象时释放对象。我在这里给出最简单的代码来说明问题。
有效的代码:
我的 Person 类具有一个动态属性“名称”
@interface Person : NSObject
@property (strong, nonatomic) NSString *name;
@end
在实现中,这 2 种方法具有能够设置人名的最少代码。我删除了代码的 getter 部分。
@implementation Person
@dynamic name;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
// Setter signature for a NSString
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
- (void)forwardInvocation:(NSInvocation *)invocation
// Get the NSString to set
NSString *s;
[invocation getArgument:&s atIndex:2];
NSLog(@"The string is: %@",s);
@end
在我的 UIViewController 中,我只有一个按钮:
- (IBAction)OnTestClicked:(id)sender
Person *p = [[Person alloc] init];
p.name = @"John Doe";
并且测试工作正常。我得到了日志
字符串是:John Doe
如果我点击按钮 10 次,我有 10 次正确的日志
问题
如果值 @"John Doe" 不是字符串文字,当我再次单击测试按钮时,应用程序将崩溃。
这是一个使用不使用字符串文字的私有属性“defaultName”的示例。
@interface MyViewController ()
@property (strong, nonatomic) NSString *defaultName;
@end
@implementation MyViewController
- (void)viewDidLoad
[super viewDidLoad];
self.defaultName = [[NSString alloc] initWithFormat:@"John Doe"];
- (IBAction)OnTestClicked:(id)sender
Person *p = [[Person alloc] init];
p.name = self.defaultName;
如果多次单击测试按钮,我会收到消息
malloc: *** 对象 0xa8257b0 错误:未分配指针被释放
或
malloc: *** 对象 0x8f68430 错误:双重释放
似乎 ARC 正在释放强属性“DefaultName”。但因为我使用的是 ARC,所以无法在 setter 中添加保留......
我该如何解决这个问题?
谢谢
【问题讨论】:
简单的解决方案是 使用 synthesize 和NSObject
子类。 (请参阅***.com/questions/1160498/…)但是,我认为您可能正在尝试在这里做一些特别的事情?你为什么要在这里使用动态?我见过的dynamic
唯一有目的的用例是NSManagedObject
子类。
如果你这样做会发生什么p.name = [self.defaultName copy];
是的 JRG-Developer,我尝试实现自己的托管对象。而nhgrif,对于副本来说,对于大对象来说并不是最好的解决方案。
【参考方案1】:
使用__unsafe_unretained
应该可以解决问题:
- (void)forwardInvocation:(NSInvocation *)invocation
// Get the NSString to set
__unsafe_unretained NSString *s;
[invocation getArgument:&s atIndex:2];
NSLog(@"The string is: %@",s);
因为getArgument:
只是将参数复制到给定的缓冲区中,没有
保留它。
【讨论】:
以上是关于使用具有通用 setter 和 ARC 的 Objective-C 动态属性的主要内容,如果未能解决你的问题,请参考以下文章
如何只允许 getter/setter 获取/设置变量值? [复制]