4

我有一个懒惰地创建对象并将其存储为弱属性的类。其他类可能会请求这个对象,但显然必须保持对它的强引用以防止对象被释放:

// .h
@interface ObjectManager
@property(nonatomic, weak, readonly) NSObject *theObject;
@end

// .m
@interface ObjectManager ()
@property(nonatomic, weak, readwrite) NSObject *theObject;
@end

@implementation ObjectManager
- (NSObject *)theObject
{
    if (!_theObject) {
        _theObject = [[NSObject alloc] init];
        // Perform further setup of _theObject...
    }
    return _theObject;
}
@end

当该方案设置为 Xcode 为 Debug 构建时,一切正常 - 一个对象可以调用objectManagerInstance.theObject并返回theObject

当方案设置为发布时,theObject返回nil

// Build for Debug:
NSObject *object = objectManagerInstance.theObject;
// object is now pointing to theObject.

// Build for Release:
NSObject *object = objectManagerInstance.theObject;
// object is now `nil`.

我的猜测是编译器正在优化我的代码,因为_theObject它没有在访问器方法本身中进一步使用,因此nil在返回之前将弱变量设置为。看来我必须在实际返回变量之前创建一个强引用,我只能认为使用块来做,但会很乱,我宁愿避免它!

是否有某种关键字可以与返回类型一起使用来阻止 ivar 这么快被取消?

4

2 回答 2

8

最有可能的是,DEBUG 构建会导致对象在自动释放池中停留足够长的时间以使其“工作”,而 RELEASE 构建会导致优化器进行更多控制流分析,从而消除自动释放喋喋不休。

坦率地说,编译器并没有在发布版本中发出警告说代码永远无法工作是一个错误(请提交它,因为您有一个很棒的简洁示例)!

您需要在某处保持对该对象的强引用,直到任何需要强引用的对象有机会获取引用为止。

我想知道这样的事情是否可行:

- (NSObject *)theObject
{
    NSObject *strongObject;
    if (!_theObject) {
        strongObject = [[NSObject alloc] init];
        _theObject = strongObject;
        // Perform further setup of _theObject...
    } else {
        strongObject = _theObject;
    }
    return strongObject;
}

即上面将更类似于返回自动释放对象同时还在内部维护弱引用的工厂方法。但是优化器可能太聪明了一半并且也破坏了上述内容。

于 2013-02-27T18:28:54.950 回答
4

You're being bitten by the optimizer.

Since _theObject is a weak reference, the system is free to get rid of it, and zero out your weak reference, whenever it's not retained. But it's not required to do it right away.

In your lazy instantiator, the newly-created object is never retained. The optimizer sees this, and says "Wow! I can zero this reference at any time! Why don't I do it...right now!" And before you know it, you're returning nil.

What you want to do is assign the lazily-instantiated object to a local variable, for an implicitly strong reference that lasts for the scope of the function. You also want to tell the compiler that you really do want the full scope, using the objc_precise_lifetime annotation.

For details from the standard, see this page.

于 2013-02-27T18:35:41.043 回答