使用Objective-C动态属性与通用setter和ARC

时间:2013-12-17 22:06:43

标签: ios objective-c dynamic automatic-ref-counting

我想使用带有通用getter / setter的动态属性,但似乎在某些情况下ARC会在不应该的情况下释放一个对象。我在这里给出了最简单的代码来说明问题。

有效的代码:

我的Person类有一个动态属性'name'

@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中添加一个保留....

如何解决这个问题?

谢谢

1 个答案:

答案 0 :(得分:3)

使用__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:只是将参数复制到给定的缓冲区中,而不是 保留它。