【问题标题】:Using Objective-C Dynamic properties with generic setter and ARC使用具有通用 setter 和 ARC 的 Objective-C 动态属性
【发布时间】: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 子类。 (请参阅stackoverflow.com/questions/1160498/…)但是,我认为您可能正在尝试在这里做一些特别的事情?你为什么要在这里使用动态?我见过的dynamic 唯一有目的的用例是NSManagedObject 子类。
  • 如果你这样做会发生什么p.name = [self.defaultName copy];
  • 是的 JRG-Developer,我尝试实现自己的托管对象。而nhgrif,对于副本来说,对于大对象来说并不是最好的解决方案。

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


【解决方案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: 只是将参数复制到给定的缓冲区中,没有 保留它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-08
    • 1970-01-01
    • 2012-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多