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

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

我正在使用 ARC 在 Objective-C 中开发应用。

我的简化代码如下所示:

A 类 (.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”将已被释放,因此我不能再使用它了。

我的解决方法是:

A 类 (.h)

@interface ClassA : UIViewController {
    MyCustomClass *obj;
}

A 类 (.m)

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

这是正确的方法吗?!我不这么认为:为什么我必须存储一个对 ClassA 无用的对象?
我无法解释实际发生的事情。你能帮帮我吗?

最佳答案

事实上,在 ClassA 中保留对 obj 的引用是不合逻辑的。

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

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

这样,当您的 MyViewController 实例仍然存在时,该对象将被保留并保留。


[编辑] 如果您希望此属性是私有(private)的,您可以在类扩展中声明它,以便其他类无法访问它,如下例所示。参见 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 session 中所建议的那样,我现在真的很少使用实例变量,而更喜欢使用属性,无论是在 .h 中公开还是在 .m 中私有(private)。


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

关于Objective-C:为什么自定义对象会变成僵尸,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12951093/

相关文章:

ios - 按下按钮时需要在单个tableView中显示两个不同数组的数据

ios - 如何模态呈现 ViewController,然后在 ViewController 被关闭后运行回调函数/ block ,没有委托(delegate)?

ios - 如何将 modalPresentationCapturesStatusBarAppearance = NO 与自定义 UIPresentationController 一起使用?

iphone - 使用 initWithNibName : bundle: or via an IBOutlet behave differently 创建的 UIViewController

c++ - 引用计数智能指针如何避免或处理引用计数器溢出?

ios - 以图形方式自定义 Parse 登录 View

iphone - 是否可以将弹出框内的导航栏高度更改为默认高度?

iOS:使用 UIBezierPath bezierPathWithOvalInRect 绘制清晰的圆圈:

iphone - Objective-C - 使用 ARC 分配/初始化对象

objective-c - 在ARC中,为什么init方法中的self是一个消费参数?