【问题标题】:Strange memory behaviour with static initializer of AVQueuePlayerAVQueuePlayer 的静态初始化程序的奇怪内存行为
【发布时间】:2014-05-21 16:13:25
【问题描述】:

我已申报财产

@property(nonatomic, strong) AVQueuePlayer *player;

当我用+ queuePlayerWithItems: 初始化它时,如果我分配给player 新对象或零,它不会被释放。即使我在下面的一排之后立即这样做。当我用– initWithItems: 初始化player 时,一切都按预期工作。我使用ARC。它是错误还是不是静态初始化程序自动释放或有什么区别?我记得在 ARC 之前的时候,它会是这样的

+ (AVQueuePlayer *)queuePlayerWithItems:(NSArray *)items
{
    return [[[AVQueuePlayer alloc] initWithItems:items] autorelease];
}

那是怎么回事?

【问题讨论】:

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


    【解决方案1】:

    使用 ARC,您的代码可能如下所示:

    + (AVQueuePlayer *)queuePlayerWithItems:(NSArray *)items 
    {
        return [[AVQueuePlayer alloc] initWithItems:items];
    }
    

    编译器可能仍然将创建的对象放入自动释放池中。是否发生这种情况还取决于优化集的级别,以及method family 是否被正确识别。

    你可以帮助编译器这样声明方法:

    + (AVQueuePlayer *)queuePlayerWithItems:(NSArray *)items NS_RETURNS_RETAINED;
    

    这将导致编译器假定该方法返回一个已分配的对象,并且需要在适当的时候发送一个平衡的release 消息,而不是将对象放入自动释放池中。

    NS_RETURNS_RETAINED 将扩展为 __attribute__((ns_returns_retained))

    定义应该省略属性NS_RETURNS_RETAINED

    编辑:

    如果这不是你的方法并且你不能更改声明,你可以使用显式的自动释放池来摆脱自动释放的对象:

    {
        AVQueuePlayer* player;
        @autoreleasepool {
           // the next line retains the returned object:
           player = [AVQueuePlayer queuePlayerWithItems:items];
        }  // here, the autorelease pool releases the returned object (it's still alive)
        // do something with variable player:
        ...
        [player ...];  // last usage of variable player
        // now, the last reference to player ceases to exist, it gets released and deallocated
    
    }
    

    【讨论】:

    • 但是+ queuePlayerWithItems: 不是我的。它在 Apple API 中。我应该避免使用它吗?为什么?因为优化错误?当我不明白的事情时,我非常讨厌......
    • @user620297 最好理解这个问题:如果新创建的对象被放入自动释放池,直到程序离开这个自动释放池的范围后才会释放它(如果这是最后的强参考)。也许一个显式的自动释放池将有助于摆脱该对象。查看我的编辑。
    • 但这是我有问题的财产。你知道...我设置它,然后再次设置它(使用新实例或 nil),并且之前设置的对象没有被释放。最奇怪的想法是,如果使用– initWithItems: 初始化,它会被正确释放。
    • 工厂方法queuePlayerWithItems: 返回一个“自动释放”对象。当自动释放池耗尽时,该对象将最终被释放。在 ARC 之前,我们不必致电 release。相反,从initWithItems:返回的对象没有放入自动释放池。在 ARC 之前,我们必须调用 release 以保持保留计数平衡。现在,在这两种情况下,您都无需担心 ARC。但是,您可能会体验到您所观察到的一切。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    • 2013-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多