使用具有通用 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 中添加保留......

我该如何解决这个问题?

谢谢

【问题讨论】:

简单的解决方案是 使用 synthesizeNSObject 子类。 (请参阅***.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 动态属性的主要内容,如果未能解决你的问题,请参考以下文章

[OC]MRC和ARC

Java 线程安全问题

如何只允许 getter/setter 获取/设置变量值? [复制]

为啥 setter 的 'this._obj['a']=2' 在 Dart 类中不起作用

Setter 方法真的在 Obj-C 中做吗?

如何使用具有类的通用类型的 ObjectMapper 反序列化 JsonString