运行包含块的后台线程

时间:2013-08-20 22:16:41

标签: ios objective-c multithreading thread-safety

我有一个单例,当我的应用程序启动时会加载一堆ALAssets。这会导致主线程冻结超过10秒,同时将每个图像加载到内存中。显然是一个大不,没有。

我试图将它放在后台线程上,但它只是部分执行。

+ (CCPhotos*) sharedPhotos
{
    static CCPhotos* shared = nil;

    if (!shared)
    {
        shared = [[CCPhotos alloc] init];

        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

        dispatch_async(queue, ^{
            [shared loadPhotosArray];
        });

    }

    return shared;
}


- (void) loadPhotosArray
{
    NSLog(@"Loading photos");
    _photos = [[NSMutableArray alloc] init];

    NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey: @"savedImages"];
    if (data)
    {
        NSArray* storedUrls = [[NSArray alloc] initWithArray: [NSKeyedUnarchiver unarchiveObjectWithData: data]];

        // reverse array
        NSArray* urls = [[storedUrls reverseObjectEnumerator] allObjects];

        for (NSURL* assetUrl in urls)
        {
            NSLog(@"Looking up %@", assetUrl);

            // Block to handle image handling success
  // This initializes, but doesn't get called
 ////-->>      
           ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
            {
                ALAssetRepresentation *rep = [myasset defaultRepresentation];
                CGImageRef iref = [rep fullScreenImage];
                if (iref) {
                    UIImage* tempImage = [UIImage imageWithCGImage:iref];
                    UIImage* image = [[UIImage alloc] initWithCGImage: tempImage.CGImage scale: 1.0 orientation: UIImageOrientationUp];

                    // Set image in imageView
                    [_photos addObject: image];
                    NSLog(@"Added photo with url: %@", [rep url]);
                    [[NSNotificationCenter defaultCenter] postNotificationName: @"PhotosChanged" object: self];
                }
            };

            // Handles failure of getting image
            ALAssetsLibraryAccessFailureBlock failureblock  = ^(NSError *myerror)
            {
                NSLog(@"Can't get image - %@",[myerror localizedDescription]);
            };

            // Load image then call appropriate block
            ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
            [assetslibrary assetForURL: assetUrl
                           resultBlock: resultblock
                          failureBlock: failureblock];
        }
    }
    else
    {
        NSLog(@"Photo storage is empty");
    }
}

我已将问题缩小到ALAssetsLibraryAssetForURLResultBlock resultblock,但不会被调用。多个线程在开始时生成,每个线程都到达此行,初始化结果块,但不调用它。我认为这与块上的线程安全有关。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

发布通知时尝试执行此操作:

dispatch_async(dispatch_get_main_queue(), ^{
    [[NSNotificationCenter defaultCenter] postNotificationName: @"PhotosChanged" object: self];
});

我认为它不适合你的原因是因为没有在主线程上调用它。必须在主线程上执行所有UI更改/更新(我假设这会导致)。这将强制通知在必要的线程上发生,并且应该正常工作!

这是很常见的事情。我实际上创建了一个代码片段,因为我发现自己经常输入它:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    <#on back thread#>
    dispatch_async(dispatch_get_main_queue(), ^{
        <#on main thread#>
    });
});

然后我将完成快捷方式设置为dispatch_async

答案 1 :(得分:0)

根据我的理解,你正在掀起你的单身人士的多个实例。在这种情况下,您可能希望在其中放置@synchronized块。例如:

+ (CCPhotos*) sharedPhotos
{
  static CCPhotos* shared = nil;

  @synchronized ([CCPhotos class])
  {
     if (!shared)
     {
         shared = [[CCPhotos alloc] init];

         dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

         dispatch_async(queue, ^{
            [shared loadPhotosArray];
         });

     }
  }

  return shared;
}

希望有所帮助。