如何在并发线程中停止预加载进程?

时间:2013-10-28 12:12:00

标签: ios objective-c concurrency

在我的游戏中,按下播放按钮后,会出现游戏视图控制器,并且几个资产开始在后台预加载以供以后在游戏中使用。

我的问题是,当按下主页按钮但我的预加载过程仍在运行时,如何停止预加载过程?

现在我要等到所有预加载完成才能正确解除分配...

ViewController.m

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{

    //  preload intro sequences
    dispatch_sync(concurrentQueue, ^{
        [weak_self.spaceSun prepareAnimationArrays];
    });

    dispatch_async(concurrentQueue, ^{
        [weak_self.sailor prepareAnimationArrays];
    });

SpaceSun,Sailor.m

- (void)prepareAnimationArrays
{
  _introArray = [NSMutableArray new];
  _introArray = [self.animator generateCachedImageArrayWithFilename:@"circleSun" extension:@".png" andImageCount:10];
  self.isAnimationArrayCached = YES;
}


- (NSMutableArray *)generateCachedLoopedImageArrayWithFilename:(NSString *)filename
                                                 extension:
                                                     (NSString *)extension
                                             andImageCount:
                                                 (int)count
{

_imagesArray = [[NSMutableArray alloc] init];
_fileExtension = extension;
_animationImageName = filename;
_imageCount = count;

for (int i = 0; i < _imageCount; i++)
{
    NSString *tempImageName = [NSString stringWithFormat:@"%@%i", filename, i];
    NSString *imagePath = [[NSBundle mainBundle] pathForResource:tempImageName ofType:extension];

    UIImage *frameImage = [self loadRetinaImageIfAvailable:imagePath];
    UIGraphicsBeginImageContextWithOptions(frameImage.size, NO, [UIScreen mainScreen].scale);
    CGRect rect = CGRectMake(0, 0, frameImage.size.width, frameImage.size.height);
    [frameImage drawInRect:rect];
    UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    [_imagesArray addObject:renderedImage];
    _precachedImagesCount++;
    if (_didPreCachePicture)
        _didPreCachePicture();

    if (_isDoublingFrames)
    {
        [_imagesArray addObject:renderedImage];
    }
    else if (_isTriplingFrames)
    {
        [_imagesArray addObject:renderedImage];
        [_imagesArray addObject:renderedImage];
    }

    if (i == _imageCount - 1)
    {
        //  we have 5 images
        //  12345 already in array
        //  let's add 432

        for (int j = _imageCount - 2; j > 0; j--)
        {
            tempImageName = [NSString stringWithFormat:@"%@%i", filename, j];
            imagePath = [[NSBundle mainBundle] pathForResource:tempImageName ofType:extension];

            frameImage = [self loadRetinaImageIfAvailable:imagePath];
            UIGraphicsBeginImageContextWithOptions(frameImage.size, NO, [UIScreen mainScreen].scale);
            rect = CGRectMake(0, 0, frameImage.size.width, frameImage.size.height);
            [frameImage drawInRect:rect];
            renderedImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();

            [_imagesArray addObject:renderedImage];
            _precachedImagesCount++;
            if (_didPreCachePicture)
                _didPreCachePicture();

            if (_isDoublingFrames)
            {
                [_imagesArray addObject:renderedImage];
            }
            else if (_isTriplingFrames)
            {
                [_imagesArray addObject:renderedImage];
                [_imagesArray addObject:renderedImage];
            }
        }
    }
}
return _imagesArray;
}

1 个答案:

答案 0 :(得分:1)

您无法取消已使用dispatch_async计划的块。您应该更喜欢更高级别的NSOperation API,而不是使用GCD。为您的任务创建多个NSOperation子类,并在NSOperationQueue上安排它们。

如果您的任务需要比其他任务更早完成,请指定与addDependency:的操作之间的依赖关系。

要取消预加载过程,只需致电:

[self.operationQueue cancelAllOperations];

为了从操作队列中公开的取消功能中受益,您应该定期检查isCancelled属性以获取更长时间运行的操作:

- (void)main
{

  for (int i = 0; i < _imageCount; i++) {

     if (self.isCancelled) break;

     // do your processing

  }
}