【问题标题】:What is an autorelease scope?什么是自动释放范围?
【发布时间】:2012-01-22 15:00:19
【问题描述】:

测试对象是否有可能在 [self saveContext] 之前被释放?

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Test" inManagedObjectContext:[self managedObjectContext]];
for (int i = 0; i < 10; i++) 
{
 Test *test = [[[Test alloc] initWithEntity:entity insertIntoManagedObjectContext:[self managedObjectContext]] autorelease];
 test.text = @"Text";
 test.index = [NSNumber numberWithInt:i];
}
[self saveContext];

【问题讨论】:

    标签: ios autorelease


    【解决方案1】:

    是的。但我认为这需要一个线程。

    任何时候发送一个对象-autorelease,它都会被添加到最高级别的自动释放池中。只要您不在方法 B 中或调用堆栈的下方创建任何新的自动释放池,方法 A 的池就应该是最高级别的池。

    在此处填写 What is the scope of (nested) autorelease pools?

    【讨论】:

    • 即使您在方法 B 中创建了一个新池,方法 A 中的对象也不会添加到其中,因为它们不在同一个上下文中。
    【解决方案2】:

    通过自动释放范围,我假设您的意思是自动释放池何时耗尽。您可以使用以下语法定义自动释放范围:

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Test" inManagedObjectContext:[self managedObjectContext]];
    @autoreleasepool {
        for (int i = 0; i < 10; i++) 
        {
            Test *test = [[[Test alloc] initWithEntity:entity insertIntoManagedObjectContext:[self managedObjectContext]] autorelease];
            test.text = @"Text";
            test.index = [NSNumber numberWithInt:i];
        }
        [self saveContext];
    }
    

    在正常情况下,当执行到空闲循环时,自动释放池将被耗尽,但这可以在您的程序中更改。

    【讨论】:

    • @autoreleasepool 不仅适用于 ARC,它仍然适用于引用计数环境,并且同样有用。
    • 哦,我不知道,但你是对的。来自文档:“@autoreleasepool 块比直接使用 NSAutoreleasePool 的实例更有效;即使您不使用 ARC,您也可以使用它们”。谢谢!
    【解决方案3】:

    不,除非在某些特定情况下,让我们找出原因。假设这是在主线程上,在你的选择器被调用之前,那么系统会在你的函数之前和之后为你创建一个NSAutoreleasePool

    所以,如果展开后,您的代码如下所示:

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Test" 
    inManagedObjectContext:[self managedObjectContext]];
    for (int i = 0; i < 10; i++) 
    {
     Test *test = [[[Test alloc] initWithEntity:entity insertIntoManagedObjectContext:[self managedObjectContext]] autorelease];
     test.text = @"Text";
     test.index = [NSNumber numberWithInt:i];
    }
    [self saveContext];
    [pool drain];
    

    entity 将在您的函数退出后立即释放,即在[self saveContext] 之后。如果您选择启用 ARC,它将解决很多此类问题。

    警告!

    请注意,这不是苹果使用的实际代码,池仅在每一帧而不是每个方法都被耗尽,但是当内存不足时,自动释放池将自动耗尽,因此,如果您的设备内存不足,那么理论上,这可能会导致实体提前发布,但如果发生这种情况,您还有其他问题要担心。

    另外请注意,在处理线程时,您必须创建自己的自动释放池,系统不会为您这样做。这不是您在这里所做的,但如果确实发生这种情况,请记住将您的选择器包装在 @autorelease 块中。

    【讨论】:

    • 我认为他问的是测试对象而不是实体。
    • 同理,除非触发内存警告,否则应该没有问题。
    • 我认为线程会搞砸它,答案必须是肯定的。它可能会导致问题。不要这样做。保存后释放它。
    • 在你知道你没有使用线程或内存不足的正常情况下调用 autorelease 并没有错,因此,作为一般规则,这段代码与使用的任何代码一样好手动保留/释放周期。
    【解决方案4】:

    简单地说:
    如果您自己不使用自动释放池,那么您的所有对象在方法、函数或块中都是安全的。

    【讨论】:

    • 并非在所有情况下,例如,如果您正在处理线程,那完全是另外一头野兽,或者,如果您的设备内存不足,应用程序所做的第一件事就是耗尽并重新创建自动释放池,以节省内存。
    • 在您的方法返回之前,主自动释放池不会耗尽。没办法。
    • 其实可以的。正如我之前所说,NSAutoreleasePool 会监听内存警告,并在发生这种情况时耗尽。
    • 你从哪里知道的? 99% 的情况下发生了类似的事情,应用程序会崩溃......
    • 我已经通过方法调配对其进行了测试,在池耗尽后,是的,应用程序通常会崩溃,除非您的自动释放池中有大量的对象。
    猜你喜欢
    • 2010-11-26
    • 2010-10-09
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 2015-01-08
    • 1970-01-01
    相关资源
    最近更新 更多