Objective-C:为什么自定义对象将成为僵尸

时间:2012-10-18 09:12:46

标签: objective-c uiviewcontroller automatic-ref-counting parameter-passing nszombie

我正在使用ARC在Objective-C中开发一个应用程序。

我的简化代码如下所示:

ClassA(.m)

MyCustomClass *obj = [[MyCustomClass alloc] initWithValue1:@"abc" value2:1000];
MyViewController *vc = [[MyViewController alloc] initWithObject:obj];
// "vc" will become the first item of a UITabBarController

MyViewController(.h)

- (id)initWithObject:(MyCustomClass *)obj {
    ...
    localReferenceToOjbect = obj;
    ...
}

- (void)viewWillAppear:(BOOL)animated {
    // do something with "localRefernceToObject" <---
}

启动应用程序将导致对僵尸的调用:当显示ViewController时,“obj”将被解除分配,因此我不能再使用它了。

我的解决方法是:

ClassA(.h)

@interface ClassA : UIViewController {
    MyCustomClass *obj;
}

ClassA(.m)

obj = [[MyCustomClass alloc] initWithValue1:@"abc" value2:1000];
MyViewController *vc = [[MyViewController alloc] initWithObject:obj];
// "vc" will become the first item of a UITabBarController

这是正确的方法吗?!我不这么认为:为什么我要存储一个对 ClassA 无用的物体的距离?
我无法解释实际发生的事情。你能救我吗?

1 个答案:

答案 0 :(得分:1)

你是对的,因为在ClassA中保留对obj的引用是不合逻辑的。

但是如果你需要保持对obj的引用以便MyViewController使用它,请将它保留在MyViewController中,而不是保存在ClassA中,因为那是将使用它的MyViewController。

最简单的方法是将您在localReferenceToObject中使用的MyViewController转换为@property(retain) propertyToObject;(如果您使用ARC,则转换为@property(strong) propertyToObject)并在您的MyViewController.m self.propertyToObject {而不是localReferenceToObject,以确保调用属性的setter,从而真正保留对象。)

这样,当MyViewController实例仍然存活时,对象将被保留并保留。


[EDIT] 如果您希望此属性为私有,则可以在类扩展中声明它,以便无法从其他类访问它,如下例所示。有关详细信息,请参阅here in Apple's documentation

在MyViewController.h头文件

@interface MyViewController : UIViewController
// Here you write the public API in the .h / public header
// If you don't want your property to be visible, don't declare it there
@end

在MyViewController.m文件中

@interface MyViewController ()
// This is the private API, only visible inside the MyViewController.m file and not from other classes
// Note the "()" to declare the class extension, as explained in Apple doc
@property(nonatomic, retain) MyCustomClass* referenceToObject; // Note: use strong (which is a synonym of retain) if you use ARC
@end

@implementation MyViewController
@synthesize referenceToObject = _referenceToObject; // not even needed with modern ObjC and latest LLVM compiler

- (id)initWithObject:(MyCustomClass *)obj
{
    self = [super init];
    if (self) {
        ...
        self.referenceToOjbect = obj;
        ...
    }
    return self;
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // do something with "self.refernceToObject"
}

// This memory management code is only needed if you don't use ARC
-(void)dealloc
{
    self.referenceToObject = nil; // release memory
    [super dealloc];
}

就个人而言,正如Apple在某些WWDC会议中所建议的那样,我现在很少使用实例变量而更喜欢使用属性,无论是.h中的public还是.m中的private。


如果您使用ARC,您仍然可以使用实例变量而不是属性,因为ARC会为您保留它,但只要您确保您的实例变量声明为strong而不是weak