强制异步任务按顺序运行

Dul*_*gon 0 objective-c ios alassetslibrary

我正在使用图像将图像保存到照片库ALAssetsLibrary.当它进入循环时,它同时运行并导致内存问题.如何在不引起内存问题的情况下运行它

ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
for(UIImage *image in images){
    [library writeImageToSavedPhotosAlbum:[image CGImage] 
                              orientation:(ALAssetOrientation)[image imageOrientation]       
                          completionBlock:^(NSURL *assetURL, NSError *error) 
    {
        ... //
    }];
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 5

如果要确保这些写入是串行发生的,可以在启动下一次写入之前使用信号量等待映像完成:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

for (UIImage *image in images) {
    [library writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error) {
        dispatch_semaphore_signal(semaphore);                  // signal when done
    }];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // wait for signal before continuing
}
Run Code Online (Sandbox Code Playgroud)

而且,由于您可能不想在此过程中阻止主队列,因此您可能希望将整个事件分配到某个后台队列:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    for (UIImage *image in images) {
        [library writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error) {
            dispatch_semaphore_signal(semaphore);                  // signal when done
        }];
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // wait for signal before continuing
    }
});
Run Code Online (Sandbox Code Playgroud)

或者,你可以将它包装writeImageToSavedPhotosAlbum在一个自定义中NSOperation,isFinished直到完成块才会发布,但这对我来说似乎有些过分.


话虽如此,我还是担心这个数组images,你UIImage同时在内存中保存所有对象.如果它们很大,或者你有很多图像,那可能会有问题.通常,您只想维护一组图像名称,然后一次一个地实例化图像,例如:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    for (NSString *path in imagePaths) {
        @autoreleasepool {
            ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

            UIImage *image = [UIImage imageWithContentsOfFile:path];

            [library writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error) {
                dispatch_semaphore_signal(semaphore);                  // signal when done
            }];

            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // wait for signal before continuing
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

人们通常应该警惕任何编码模式,这些编码模式假设同时在存储器中保持一组大对象,如图像.

如果您需要经常访问这些图像,但并不总是希望每次都从持久存储中重新检索它,您可以使用一种NSCache模式(例如尝试从缓存中检索图像;如果找不到,则从持久存储中检索并添加它在缓存中;在内存压力下,空缓存),这样你就可以享受在内存中保存图像的性能优势,但能够优雅地处理图像缓存占用过多内存的情况.