Ios 调度中的内存管理

Ios 调度中的内存管理,ios,memory-management,dispatch,Ios,Memory Management,Dispatch,我尝试使用以下代码在我的iPad应用程序上对背景中的所有视图进行浏览: NSString *path = [self.page previewPathForOrientation:currentOrientation]; dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ @autoreleasepool { UIGraphicsBeginImageContextWithOptio

我尝试使用以下代码在我的iPad应用程序上对背景中的所有视图进行浏览:

NSString *path = [self.page previewPathForOrientation:currentOrientation];
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
  @autoreleasepool {
    UIGraphicsBeginImageContextWithOptions(self.previewView.bounds.size, NO, 0.0);
    [self.previewView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    self.previewView = nil;
    float scale = [UIScreen mainScreen].scale;
    CGRect previewRect = currentOrientation == Landscape ? [[OrientationLandscape singleton] frameForPreviewImage] : [[OrientationPortrait singleton] frameForPreviewImage];
    CGSize previewSize = CGSizeMake(previewRect.size.width * scale, previewRect.size.height * scale);
    UIImage *scaledImage = [image scaleImageToSize:previewSize];

    CGImageDestinationRef imageDestination = CGImageDestinationCreateWithURL((__bridge CFURLRef)[[NSURL alloc] initFileURLWithPath:path], (__bridge CFStringRef)@"public.png", 1, NULL);
    CGImageDestinationAddImage(imageDestination, [scaledImage CGImage], NULL);
    CGImageDestinationFinalize(imageDestination);
    CFRelease(imageDestination);

    NSFileManager *fileMngr = [[NSFileManager alloc] init];
    if(![fileMngr fileExistsAtPath:path])
    {
      ZAssert(0, @"could not save preview file");
    }
    dispatch_async(dispatch_get_main_queue(), ^{
      rendered++;
      //DLog(@"rendered %d items", rendered);
      [GetController addSkipBackupAttributeToItemAtPath:path];
      [self.page setPreviewRenderedForOrientation:currentOrientation];
      contentsCount = 0;
      currentContentIndex = 0;
      //[self prepareOtherOrientation];
      if(self.journal == nil && (![self.page previewRenderedForOrientation:Landscape] || ![self.page previewRenderedForOrientation:Portrait])){
        [self appendPage:self.page];
      }
      DLog(@"rendered page %@ in orientation %d", self.page, currentOrientation);
      self.page = nil;
      [self retry];
    });
  }
});
重试函数使用NSTimer在短暂延迟后使用不同的页面再次启动相同的函数。使用分配工具,堆只会不断增长。过了一会儿,应用程序崩溃后不久,我收到了内存警告

当我删除所有调度呼叫时,一切正常,但这当然不是我想要的。另外,当我将重试方法中的延迟增加到5秒时,问题也消失了,因此当事情快速连续处理时,内存似乎没有释放


我绝对保证这个方法不会一次运行超过一次。。。你知道这是怎么回事吗?

顺便说一句,你不需要在调度队列中创建一个自动释放池-唯一可能的情况是,如果你在循环中分配一堆对象。我同意Richard的观点。此外,自动释放池可能会将释放调用推迟到稍后。听起来好像在那里的某个地方,你正在递归地调用块。每次创建块时,它都会复制本地堆栈,其中可能包括复制其他块的块和复制其他块的块。。。是的,自动释放池只是一次试用,没有改变任何东西。我认为杰克是对的,但我不确定我是否明白,你有一个例子吗?重试函数再次调用此函数,这是问题所在吗?我怎样才能避免这种情况呢?试试这个:
[self-performselectornmainthread:@selector(retry)with-object:self-waitUntilDone:NO]。有了这段代码,我认为:1-您将始终在主线程上分配计时器。如果您在一个线程上创建一个计时器,然后在另一个线程中使其无效,这可能是一个问题(但我认为这不是您的情况,只是为了确保没有看到代码)。2-wait-until-done=NO应该让块自己“完成”(它转到下一条指令,即块的末尾),并从主线程开始另一次重试,而不需要周期。试着让我知道,不幸的是,没有做到,同样的问题。。。即使没有调用,因为我预先使用了dispatch_async(dispatch_get_main_queue()…),所以不应该让块“完成”并在主线程上执行所有内容吗?