objective-c - ARC 中奇怪的对象生命周期 : how to force precise object lifetimes?

标签 objective-c automatic-ref-counting

我在 ARC 中遇到了对象生命周期的奇怪行为。我已将范围缩小到以下示例:

//---------------------------------------------------------------------------------
@interface MyObject : NSObject
@end

@implementation MyObject
-(id)init
{
    self = [super init];
    if(!self) return nil;
    NSLog(@"    MyObject init %p", self);
    return self;
}
-(void)dealloc
{
    NSLog(@"    MyObject dealloc %p", self);
}
@end

//---------------------------------------------------------------------------------
@implementation TLAppDelegate

-(MyObject *)createMyObject:(NSString *)unusedArg
{
    return [MyObject new];
}

-(void)someOperation
{
    NSLog(@"  Entering someOperation");
    MyObject* x = [self createMyObject:@"some message"];
    NSLog(@"  Exiting someOperation; x should be deallocated right after this...");
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSLog(@"entering applicationDidFinishLaunching");
    [self someOperation];
    [self someOperation];
    NSLog(@"exiting applicationDidFinishLaunching");
}

@end

代码摘要:applicationDidFinishLaunching来电 someOperation连续两次。 someOperation创建一个本地对象,该对象 我期望在 someOperation 时被释放返回。

因此,这是我期望的输出:

entering applicationDidFinishLaunching
  Entering someOperation
    MyObject init 0x600000012cd0
  Exiting someOperation; x should be deallocated right after this...
    MyObject dealloc 0x600000012cd0
  Entering someOperation
    MyObject init 0x600000012cb0
  Exiting someOperation; x should be deallocated right after this...
    MyObject dealloc 0x600000012cb0
exiting applicationDidFinishLaunching

但这是我实际得到的输出:

entering applicationDidFinishLaunching
  Entering someOperation
    MyObject init 0x600000012cd0    <-- this object is retained until the end of the output!
  Exiting someOperation; x should be deallocated right after this...
  Entering someOperation
    MyObject init 0x600000012cb0
  Exiting someOperation; x should be deallocated right after this...
    MyObject dealloc 0x600000012cb0
exiting applicationDidFinishLaunching
    MyObject dealloc 0x600000012cd0

为什么第一个对象一直保留到 applicationDidFinishLaunching返回? 据我所知,没有MyObject实例应该位于 someOperation 之外。 这不是泄漏,因为它在下一个作用域中被释放。

感觉几乎就像编译器内联 someOperation ,将作用域与调用者合并。但这也不是真的,因为 (如果我错了,请纠正我),编译器无法内联 Objective-C 方法。

对于我的实际项目,这会在多个方面引起问题。首先在我们的日志记录类中,我们跟踪一些范围,但由于这种行为,以下日志:

Generating some list {
    Calculating item #1 {
    }
    Calculating item #2 {
    }
    Calculating item #3 {
    }
}

变成这样,毫无意义:

Generating some list {
    Calculating item #1 {
        Calculating item #2 {
            Calculating item #3 {
            }
        }
    }
}

此外,这意味着我们无缘无故地保留了太多的内存。

有没有办法让这种行为更加可预测?

请注意,如果我使用 __attribute__((objc_precise_lifetime)),此行为不会改变;它不会改变观察到的行为。

最佳答案

MyObject 不会在 someOperation 结束时释放,因为 createMyObject 返回的对象被保留(创建时)并且自动释放(返回时)。

因此,虽然 someOperation 随后将该对象分配给 x 并按照您的预期保留和释放它,但仍然存在来自 createMyObject 的自动释放引用> 在自动释放池耗尽之前不会被清除(这通常发生在每个运行循环结束时)。

如果您不是从 createMyObject 获取 MyObject,而是直接实例化它,如下所示:

-(void)someOperation{
  NSLog(@"  Entering someOperation");
  MyObject* x = [[MyObject alloc] init];
  NSLog(@"  Exiting someOperation; x should be deallocated right after this...");
}

不会出现自动释放的引用挂起,所有内容都应该按照您的预期立即释放。


更新

Martin R 提出了有关 ARC 和命名约定的好观点。默认情况下,方法返回的对象由 ARC 保留/自动释放(如果不保留,则会立即dealloc)。如果不自动释放,则会泄漏)。

根据 Cocoa 命名约定,有一些方法预计会返回一个“保留”对象,即保留计数为 +1 的非自动释放对象。对于这些特定方法,其名称以 alloc...copy...init...mutableCopy... 开头,或new...,ARC将返回一个保留的对象。其他一切都会返回一个自动释放的。

关于objective-c - ARC 中奇怪的对象生命周期 : how to force precise object lifetimes?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21437807/

相关文章:

ios - AVPlayer播放ts文件

cocoa - Xcode/Cocoa ARC 和 MRC 类。 MRC 自动释放会导致 ARC 类中的内存泄漏吗?

objective-c - NSURLConnectionDelegate 静态类包装器不调用函数调用 (ARC)

ios - 使用 Storyboard实例化的 Controller 的重新分配

objective-c - iPhone obj-c错误:使用“核心绘图”时分配给只读属性

objective-c - NSPopover 的 contentViewController 中的动画变化

ios - 我是否必须在 ARC 下调用 dispatch_release?

ios - 保留有关ivar的__block变量的循环警告

objective-c - WatchKit 的社交框架

ios - DTCoreText 图像不显示