【问题标题】:autoreleasepool and pool drain with ARC使用 ARC 的 autoreleasepool 和池排水
【发布时间】:2013-04-15 19:52:37
【问题描述】:

我想用 ARC 迁移这段代码。

我知道我必须使用:

@autoreleasepool {}

但是我的两个水池排水有问题,不知道怎么办。

- (void)downloadImageToCache:(NSString*)_urlImage
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    if (!(_urlImage) || (_urlImage == nil)) 
    {
        [pool drain];
        return;
    }

    NSURL *url = [NSURL URLWithString:_urlImage];
    NSData *data = [[[NSData alloc] initWithContentsOfURL:url] autorelease];

    if (data != nil) 
    {
        ...do something...
    }
    else
    {

        ...do something...
    }
    [pool drain];
}

【问题讨论】:

  • 目前的方法有什么问题?
  • @H2CO3:ARC 不允许这样做。
  • @MartinR 我确定我已经看到 @autoreleasepool {} 与 ARC 一起使用。 (但无论如何,谁在乎 ARC?我不关心。)
  • @H2CO3:要么我误解了你,要么你误解了我 :-) NSAutoreleasePooldrain 不允许使用 ARC,你必须使用 @autoreleasepool
  • @MartinR 好吧。事实证明我误解了整个事情。这对我来说似乎很明显,显然对 OP 来说不是。你是对的。

标签: ios cocoa-touch automatic-ref-counting


【解决方案1】:

把整个东西包起来。不用担心回报。它会弄清楚的。

即编译器会将其转换为逻辑等效的:(或者您可以显式清理逻辑)

- (void)downloadImageToCache:(NSString*)_urlImage
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  if (!(_urlImage) || (_urlImage == nil))
  {
    //[pool drain];
    //return;
  } else {

    NSURL *url = [NSURL URLWithString:_urlImage];
    NSData *data = [[[NSData alloc] initWithContentsOfURL:url] autorelease];

    if (data != nil)
    {
      ...do something...
    }
    else
    {  
      ...do something...
    }
  }
  [pool drain];
}

归结为:

- (void)downloadImageToCache:(NSString*)_urlImage {
  @autoreleasepool {
    if (_urlImage != nil) {

      NSURL *url = [NSURL URLWithString:_urlImage];
      NSData *data = [[[NSData alloc] initWithContentsOfURL:url] autorelease];

      if (data != nil) {
        // ...do something...
      } else {
        //...do something...
      }
    }
  }
}

或者也许(更少的嵌套缩进总是我的偏好):

- (void)downloadImageToCache:(NSString*)_urlImage {
  if (_urlImage == nil) {
    NSLog(@"[%@ %@] Error Message", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    return;
  }

  @autoreleasepool {

    NSURL *url = [NSURL URLWithString:_urlImage];
    NSData *data = [[[NSData alloc] initWithContentsOfURL:url] autorelease];

    if (data != nil) {
      // ...do something...
    } else {
      //...do something...
    }
  }
}

【讨论】:

  • 请注意,您仍然可以将 @autoreleasepool 与 ARC 一起使用。我不确定。但后来我消耗的内存从 1.5 GB 下降到 100 MB。
【解决方案2】:

您可以从自动释放池中“提前返回”,这将释放 池中的所有对象:

- (void)downloadImageToCache:(NSString*)_urlImage
{
    @autoreleasepool {    
       if (!(_urlImage) || (_urlImage == nil)) 
       {
           // no need (not allowed) to call `drain`
           return;
       }

       NSURL *url = [NSURL URLWithString:_urlImage];
       NSData *data = [[[NSData alloc] initWithContentsOfURL:url] autorelease];

       if (data != nil) 
       {
           ...do something...
       }
       else
       {

           ...do something...
       }
       // no need (not allowed) to call `drain`
    }
}

【讨论】:

    【解决方案3】:

    使用新的@autorelease 块语法,当执行退出块时,池将被耗尽。所以你可以这样做:

    - (void)downloadImageToCache:(NSString*)_urlImage
    {
        @autoreleasepool {
    
            if (!(_urlImage) || (_urlImage == nil)) 
            {
                return; //leaves @autoreleasepool block, automatically drains
            }
    
            NSURL *url = [NSURL URLWithString:_urlImage];
            NSData *data = [[[NSData alloc] initWithContentsOfURL:url] autorelease];
    
            if (data != nil) 
            {
                ...do something...
            }
            else
            {
    
                ...do something...
            }
        } //leaves @autoreleasepool block, automatically drains
    }
    

    更多信息请参见AutoreleasePools

    【讨论】:

      【解决方案4】:

      也许:

      - (void)downloadImageToCache:(NSString*)_urlImage
      {
          @autoreleasepool {
              if (!(_urlImage) || (_urlImage == nil))
              {
                  return;
              }
      
              NSURL *url = [NSURL URLWithString:_urlImage];
              NSData *data = [[NSData alloc] initWithContentsOfURL:url];
      
              if (data != nil)
              {
      
              }
              else
              {
      
              }
          }
      }
      

      发件人:Apple Documentation

      【讨论】:

        【解决方案5】:

        此代码中有两个排水管的唯一原因是因为它在第一次排水管后立即返回。只需将代码包装在@autoreleasepool 中,无论遵循哪个返回路径,它都会在退出时耗尽。

        【讨论】:

          猜你喜欢
          • 2011-12-18
          • 1970-01-01
          • 1970-01-01
          • 2013-05-23
          • 1970-01-01
          • 1970-01-01
          • 2012-01-11
          • 1970-01-01
          • 2011-10-31
          相关资源
          最近更新 更多