【问题标题】:Calling ARC method from non-ARC code从非 ARC 代码调用 ARC 方法
【发布时间】:2012-12-01 07:07:35
【问题描述】:

我有一个使用 ARC 库的非 ARC 项目。我很困惑是否应该释放库方法返回的对象。举个例子:

- (void)test{
    LibObject* obj1 = [[LibObject alloc] init];
    LibObject* obj2 = [obj1 otherObj];

    [obj1 release]; //should I release it?
    [obj2 release]; //should I release it?
}

据我所知,如果对象在自动释放池中,我应该不理会它。否则,我应该释放它。

但是,the ARC document 这么说

当从这样的函数或方法返回时,ARC 在返回语句的求值点保留值,然后离开所有局部范围,然后平衡保留,同时确保值跨越调用边界。在最坏的情况下,这可能涉及自动释放,但调用者不能假定该值实际上在自动释放池中。

文档是否暗示我应该始终释放对象,因为我不能假设对象是自动释放的?

【问题讨论】:

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


    【解决方案1】:

    我的理解是,如果您为此文件使用编译器标志-fno-objc-arc,您需要自己处理保留/释放。所以你应该打电话给[obj1 release]。如果你不应该自己调用它,编译器会相应地警告你。

    【讨论】:

      【解决方案2】:

      当您从启用 ARC 的类获取对象到未启用 ARC 的类时,您有责任管理内存。

      ARC 只是简单地在编译期间在启用 ARC 的代码中添加保留和释放。它不会管理处于非 ARC 模式的其他类或对象的内存。

      您应该在需要时释放这些对象。

      【讨论】:

        【解决方案3】:

        据我了解,在您的非 ARC 代码中,您只需像往常一样使用启用 ARC 的库执行所有保留/释放(就像与其他非 ARC 代码交互一样)。

        我创建了一个简单的应用程序来证明这种行为。

        测试代码 - 编译没有 ARC

        - (void)testARC
        {
            ARCLib *al = [[ARCLib alloc] init];
            NSLog(@"%p retainCount = %u", al, [al retainCount]);
            [al release];
        
            ARCLib *al2 = [ARCLib arcLib];
            NSLog(@"%p retainCount = %u", al2, [al2 retainCount]);
        }
        

        ARCLib - ARC

        编译
        @implementation ARCLib
        
        + (id)arcLib
        {
            return [[self alloc] init];
        }
        
        - (id)init
        {
            self = [super init];
            if (self)
            {
                NSLog(@"%p init",self);
            }
            return self;
        }
        
        - (void)dealloc
        {
            NSLog(@"%p dealloc",self);
        }
        
        @end
        

        结果

        2012-12-13 20:15:21.879 ARCTest[15206:907] 0x1e821500 init
        2012-12-13 20:15:21.883 ARCTest[15206:907] 0x1e821500 retainCount = 1
        2012-12-13 20:15:21.884 ARCTest[15206:907] 0x1e821500 dealloc
        2012-12-13 20:15:21.885 ARCTest[15206:907] 0x1dd26060 init
        2012-12-13 20:15:21.886 ARCTest[15206:907] 0x1dd26060 retainCount = 1
        2012-12-13 20:15:21.893 ARCTest[15206:907] 0x1dd26060 dealloc
        

        回答您的问题

        你应该释放你的 obj1,但不需要释放 obj2。

        【讨论】:

        • 这实际上并不能证明什么,因为retainCount 既不会反映自动释放状态,也不会反映线程下的任何活动(也不会反映任何内部实现细节)。巧合,你的结论是正确的。
        • @bbum 你误解了我的代码。那里的 retainCount 没有显示任何内容。演示代码证明底层自动释放池为我们创造了魔力。
        • 那为什么还有retainCount呢?返回的值在这种情况下没有用。
        • retainCount 用于确保在使用非 ARC 代码调用 ARC 代码时对象不会被双重保留:p
        • retainCount 不能告诉你的。生成的可能是[[foo retain] autorelease]; 5 次,retainCount 可能是 ~6 次,并且代码仍然可以按预期“工作”......
        【解决方案4】:

        参见《高级内存管理编程指南》中的Memory Management Policy

        您拥有自己创建的任何对象
        您使用方法创建对象 其名称以“alloc”、“new”、“copy”或“mutableCopy”开头(对于 例如,alloc、newObject 或 mutableCopy)。

        您不得放弃不属于您的对象的所有权

        这些规则与使用 ARC 编译的方法一致。 在ARC documentation中,第一类方法的行为在“3.2.2.保留返回值”中有所描述:

        当从这样的函数或方法返回时,ARC 会保留该值 在返回语句的评估点,...

        这意味着调用者必须释放对象。

        第二类方法在“3.2.3.未保留的返回值”中描述:

        当从这样的函数或方法返回时,ARC 会保留该值 在返回语句的评估点,然后离开所有 本地范围,然后平衡保留 ...

        这意味着调用者不能释放对象。

        所以在你的例子中:

        LibObject* obj1 = [[LibObject alloc] init];
        LibObject* obj2 = [obj1 otherObj];
        [obj1 release]; //should I release it? --> YES
        [obj2 release]; //should I release it? --> NO
        

        你拥有obj1,因为它是用alloc创建的,所以你必须释放obj1

        你不拥有obj2,因此你不能释放它。

        注意:如果您对代码运行 Xcode 静态分析器,它会准确显示违反这些规则的位置。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-04-09
          • 2012-01-31
          • 1970-01-01
          • 1970-01-01
          • 2015-08-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多