ios编程:使用线程将多个图像添加到库中

Posted

技术标签:

【中文标题】ios编程:使用线程将多个图像添加到库中【英文标题】:ios programming: Using threads to add multiple images to library 【发布时间】:2013-12-18 16:05:33 【问题描述】:

在 Xcode 中,当我尝试向我的库中添加 超过 5 张图片 时,出现以下错误:

Error Domain=ALAssetsLibraryErrorDomain Code=-3301 "Write busy" UserInfo=0xa706aa0 NSLocalizedRecoverySuggestion=Try to write again, NSLocalizedFailureReason=There was a problem writing this asset because the writing resources are busy., NSLocalizedDescription=Write busy, NSUnderlyingError=0xa770110 "Write busy"

为了解决这个问题,我想出线程可以解决我的问题。文档说明我可以使用 POSIX 线程或NSThreads。当我尝试使用 POSIX 线程时,我将线程设置为可连接的,并且我正在创建一个 void * 函数:

void * myFunc (void * image)

       UIImageWriteToSavedPhotosAlbum((__bridge UIImage *)(image),self,nil,nil);
       pthread_exit(NULL);
       return NULL;

我也在等待线程结束。但仍然只写了 5 张图片。

我尝试过使用NSThreads 并做到了:

[self performSelectorOnMainThread:@selector(myFunc:) withObject:image waitUntilDone:YES];

但还是不行。

我的问题有答案了吗?这对我的工作至关重要。

谢谢。

编辑:

也尝试了 dispatch_async。错了吗?

dispatch_queue_t myQueue = dispatch_queue_create("com.cropr.myqueue", 0);

for (UIImage * image in images) 

        dispatch_async(myQueue, ^

            [self.library saveImage:image toAlbum:@"Cropr" withCompletionBlock:^(NSError *error) 
                if (error!=nil) 
                    NSLog(@"Big error: %@", [error description]);
                
            ];

        );

    

我需要添加什么?

【问题讨论】:

你试过异步调度吗? 这里是 dispatchAsync jeffreysambells.com/2013/03/01/…的指南 是的。我已经做了。使用了上面的指南,这很有意义,但仍然没有雪茄...... 甚至尝试在 dispatchAsync 中放置一个 while 条件,告诉它一遍又一遍地尝试写入,从而导致无限循环!我知道为什么?? 好的,只需用代码更新您的问题(当您使用 GCD 时),我会给您一个答案(使其正常工作)。 【参考方案1】:

您可以尝试随后写入所有图像,而不是同时。下面的代码利用ALAssetsLibrary,并实现了一个“异步循环”,它在序列中调用许多异步方法。

typedef void (^completion_t)(id result);

- (void) writeImages:(NSMutableArray*)images 
          completion:(completion_t)completionHandler 
    if ([images count] == 0) 
        if (completionHandler) 
            // Signal completion to the call-site. Use an appropriate result,
            // instead of @"finished" possibly pass an array of URLs and NSErrors 
            // generated below  in "handle URL or error".
            completionHandler(@"finished");  
        
        return;
    

    UIImage* image = [images firstObject];
    [images removeObjectAtIndex:0];

    [self.assetsLibrary writeImageToSavedPhotosAlbum:image.CGImage 
                                         orientation:ALAssetOrientationUp
                                     completionBlock:^(NSURL *assetURL, NSError *error)
    
        // Caution: check the execution context - it may be any thread,
        // possibly use dispatch_async to dispatch to the main thread or
        // any other queue.

        // handle URL or error
        ...
        // next image:
        [self writeImages:images completion:completionHandler];
    ];

用法:

[foo writeImages:[foo.images mutableCopy] completion:^(id result)
    // Caution: check the execution context - it may be any thread
    NSLog(@"Result: %@", result);   
];

【讨论】:

猜我是菜鸟,但是: typedef (^completion_t)(id result);不工作。它无法识别“completion_t”。我应该包括其他东西吗? 呃,抱歉:应该是typedef void (^completion_t)(id result) 成功了!谢谢 CouchDeveloper!【参考方案2】:

我建议使用NSOperationQueue 并使用maxConcurrentOperationCount 的值。通过这种方式,您可以控制同时写入库的数量,而不会使其不堪重负。

如果您使用线程,甚至 GCD,您需要自己实现此逻辑。更多代码 --> 更多引入错误的机会。

【讨论】:

使用 NSOperationQueue 时,需要创建一个 NSOperation,它必须是并发的,因为实际任务已经是异步的。 UIImageWriteToSavedPhotosAlbum 函数中“回调选择器”的奇怪组合并没有使 NSOperation 子类的实现更容易。事实上,为这种情况创建一个适当的并发子类是复杂的、容易出错的和棘手的。所以,我不鼓励使用 NSOperationQueue。【参考方案3】:

Dispatch_async 是在后台做的事情,所以我把你的for 和函数调用放在dispatch_async 正文中 因此将for 放入dispatch async 中会将您的图像存储在相册中,就像运行for 一样。但在单独的线程上。

    dispatch_queue_t myQueue = dispatch_queue_create("com.cropr.myqueue", 0);
    dispatch_async(myQueue, ^

      for (UIImage * image in images) 
          UIImageWriteToSavedPhotosAlbum((__bridge UIImage *)(image),self,nil,nil);
    );


你也可以试试这个。我认为会更好,看看它是否有效,然后添加你想要处理的错误。

我也认为这是您想要的答案:ios: dispatch_async and UIImageWriteToSavedPhotosAlbum

【讨论】:

以上是关于ios编程:使用线程将多个图像添加到库中的主要内容,如果未能解决你的问题,请参考以下文章

IOS开发 多线程编程 - NSThread

在 iOS 中以编程方式将图像集添加到 images.xcassets 目录?

iOS 7 / Xcode 5:以编程方式访问设备启动图像

在 iOS 中以编程方式在标签栏上添加图像

并发编程---协程

LINUX网络编程 IO 复用