0

我有一个单例,当我的应用启动时会加载一堆 ALAsset。这导致主线程在将每个图像加载到内存时冻结超过 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没有被调用的问题。开始时会产生多个线程,每个线程都到达这一行,初始化结果块,但不调用它。我认为这与块上的线程安全有关。有什么想法吗?

4

2 回答 2

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;
}

希望有帮助。

于 2013-08-21T02:18:31.043 回答
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

于 2013-08-20T22:26:03.140 回答