【问题标题】:How to keep an __autoreleasing address as a strong property in a class?如何将 __autoreleasing 地址保留为类中的强属性?
【发布时间】:2014-02-18 08:32:10
【问题描述】:

如何使变量的地址成为NSObject 中的强属性?我有一个名为SCPFMessageThreadQuery 的类,它通过传递SCPFMessageThread 变量的地址来进行分配。

@interface SCPFMessageThreadQuery ()

// This declaration seems correct.
@property (nonatomic) SCPFMessageThread *__strong *thread;

- (id)initWithRootMessage:(SCPFMessage *)root threadAddress:(SCPFMessageThread **)address;

@end

@implementation SCPFMessageThreadQuery

// Xcode somehow makes the ownership type __autoreleasing here during autocompletion.
- (id)initWithRootMessage:(SCPFMessage *)root threadAddress:(SCPFMessageThread *__autoreleasing *)address
{
    if (self = [super init]) {
        _root = root;

        // ERROR HERE. Xcode complains about changing the ownership of address.
        _thread = address;
    }
    return self;
}

@end

我得到的错误是:

将 'SCPFMessageThread *__autoreleasing *' 分配给 'SCPFMessageThread *__strong *' 会更改指针的保留/释放属性

我计划在我的视图控制器中以下列方式使用这个类:

SCPFMessageThread *thread = self.thread; // self.thread can be nil
SCPFMessageThreadQuery *query = [[SCPFMessageThreadQuery alloc]
    initWithRootMessage:self.rootMessage threadAddress:&thread];

我真的需要在这里传递地址。我将对我们的 API 进行多次调用,以完成应用程序代码中单个对象 (SCPFMessageThread) 的信息。请不要问我为什么 API 不自己做 JOIN。

【问题讨论】:

    标签: ios iphone objective-c c pointers


    【解决方案1】:

    您不能将__autoreleasing 存储用于除局部变量之外的任何内容。自动释放是每个线程的行为。跨线程或跨可能弹出自动释放池的堆栈帧共享 __autoreleasing 存储是不安全的。

    SomeObject ** 类型的参数默认为__autoreleasing。您可以更改您的方法声明,使其与强变量一起使用。然后你可以直接将它与你的强属性的 ivar 一起使用:

    - (id)initWithRootMessage:(SCPFMessage *)root threadAddress:(SCPFMessageThread * __strong *)address
    

    请注意,当您获取 ivar 或局部变量的地址时,ARC 不会确保包含的对象或堆栈帧在您需要时一直存在。

    【讨论】:

    • +1 另一个“解决方案”表明没有简单的解决方案,但要求打破了 ARC 可以处理的限制。
    【解决方案2】:

    显示问题:

    @interface AppDelegate ()
    @property NSString * __strong * ivar;
    @end
    
    @implementation AppDelegate
    - (void)storeIndirect:(NSString * __autoreleasing *)par
    {
      id xpar = *par;
      _ivar = &xpar;
    }
    @end
    

    通过取消引用,您有一个指向可保留对象的指针。只有这些(以及不是“指向可保留对象的指针”)是 ARC 的主题。因此,xpar 指向的对象被保留——并在方法结束时被释放。

    当然,您可以将xpar 存储到一个属性中来保存它。但这表明整个代码毫无用处:双重间接在 ARC 中会丢失。 ARC 关心指针后面的对象,如果它是一个可保留对象。你的指针指向一个 C 指针,它不是一个可保留的对象。

    我认为没有简单的解决方案。 (但是你可以使用CFRetain() 等,如果你不关心或多或少理论上的CFRetain() 是针对CF 对象的问题。)

    即使您明确地确认了这一点:您为什么需要额外的间接级别?如果您真的非常需要它,请考虑在中间添加一个额外的对象:

    @interface NSStringRetainableReference
    @property NSString *string;
    @end
    
    @implementation
    @end
    

    将此类的实例对象作为参数传递。然后你有一个指向可保留对象的指针和另一个级别的间接。但在这种情况下,它是由一个对象构建的。

    【讨论】:

    • "你的指针指向一个 C 指针,它不是一个可保留的对象。"现在牢记在心。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-08
    • 1970-01-01
    • 1970-01-01
    • 2016-01-23
    • 2010-09-21
    相关资源
    最近更新 更多