【问题标题】:Retaining reference to properties in Objective-C在 Objective-C 中保留对属性的引用
【发布时间】:2020-06-19 18:08:19
【问题描述】:

我的班级中有一个自定义对象属性。我在一个函数中分配这个对象。一旦函数执行完毕,该属性就会被释放。我不希望这种情况发生。我希望该对象一直存在,直到对 MyClass 的引用处于活动状态。 这是与ARC。

这是代码

@interface MyClass : NSObject
@property (nonatomic, strong) MyCustomClass *obj;
@end

@implementation MyClass

- (id)init {
// initialize 
_obj = nil;
}

- (void)func {
 _obj = [[MyCustomClass alloc] initWithParams...];
// do more things 
}

// the object deallocates once the function exits. 

【问题讨论】:

  • 你说“这是 ARC”,但我不得不否认这一点。使用 ARC,分配给 _obj 也保留,除非您替换它,否则 MyCustomClass 对象不会被释放,或者除非 MyClass 本身被释放。我建议你实现dealloc 看看是不是这样。要么是,要么你没有像你认为的那样在 ARC 下运行。
  • 顺便说一句,在初始化程序中没有理由说_obj = nil。已经是nil
  • 在唯一提供的代码中,_obj 将使用或不使用 ARC 独立存储 MyCustomClass 的新实例。如果它在函数退出时被释放,则意味着 ARC 已打开(否则它会泄漏或持续存在),并且!,do more things 中的某些内容要么替换 _obj 实例,要么将其设置为 nil .

标签: objective-c properties automatic-ref-counting


【解决方案1】:

您的代码中的其他地方还有其他内容,因为上面提供的代码不会释放该 MyCustomClass 实例。一些可能导致_obj 引用的实例被释放的可能原因包括:

  • _obj 正在其他地方设置为 nil
  • _obj 再次被设置(例如,您再次调用 func)并且旧实例将被释放;或
  • 父对象MyClass 本身正在被释放。

我建议两件事来诊断发生了什么:

  1. 首先,我建议将 dealloc 方法添加到 MyClassMyCustomClass 中,这样您就可以看到它们何时被释放:

    - (void)dealloc {
        NSLog(@"%s", __FUNCTION__);
    }
    
  2. 如果您仍然无法推断出发生了什么,我建议使用 Instruments 来跟踪对相关对象的每个引用。

    例如,启动分析器(command+i 或“Product”»“Profile”)并选择“Leaks”工具。在开始录制会话之前,请确保“分配”工具的“录制选项...”没有设置为“丢弃事件以释放内存”,但 设置为“记录引用计数”:

    您现在可以记录您的分析会话。就个人而言,我添加了“兴趣点”工具,并在我创建 MyClass 实例的位置添加了路标,

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        os_log_t log = os_log_create("ViewController", OS_LOG_CATEGORY_POINTS_OF_INTEREST);
        os_signpost_id_t identifier = os_signpost_id_generate(log);
    
        os_signpost_event_emit(log, identifier, "MyClass");
    
        MyClass *myClass = [[MyClass alloc] init];  // the problem here is that I’m using a local variable for the parent class, but the situation in your case may vary
        [myClass func];
    }
    

    但是,如果您知道创建此对象的时间,则可能不需要这样做。但很高兴在 Instruments 中看到这些路标。

    无论如何,请锻炼您的应用程序,以便您可以发现问题。然后停止录制。然后选择 Allocations 工具并找到您的对象:

    您可以(通过单击该对象地址旁边的箭头)然后可以查看添加和删除的每个引用:

我不仅看到它已被释放,而且我可以看到发生这种情况的完整堆栈跟踪。请注意,func 方法不在此堆栈跟踪中,而是我在viewDidLoad 中,在MyClassdealloc 内,这触发了MyCustomClassdealloc。我什至可以双击右侧堆栈中的viewDidMethod,然后直接被带到它发生的地方:

我现在可以看到问题所在,我“不小心”将MyClass 设为局部变量。因此,我将其更改为使用该属性(目前已被注释掉),问题就会消失。

现在,您的案例中问题的确切来源无疑会有所不同,但通过明智的 dealloc 日志记录以及 Instruments 向我们展示已添加和删除的每个引用的能力,您应该能够诊断问题。并且不要忘记查看完整的堆栈跟踪(专注于您的白色代码),看看那里的一切是否有意义。通常我们会关注有问题的属性(您的示例中的 obj),而忘记查看堆栈跟踪中的早期内容。

【讨论】:

    猜你喜欢
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-12
    • 2023-04-09
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多