学习如何在线程之间分配任务,或者异步调度。我知道任何“触及”视图的操作都必须在主线程上完成。怎么样:UIImageWriteToSavedPhotosAlbum
? 我认为这可以在后台线程上完成,但我错了吗?
另外,如果它应该在后台线程上完成,下面这两个调用之间是否存在差异,因为一个保存UIImage而另一个从视图中保存UIImage?
UIImageWriteToSavedPhotosAlbum(_someUIImage ,nil,nil,nil);
UIImageWriteToSavedPhotosAlbum(_imageView.image ,nil,nil,nil);
顺便说一句,我使用此设置在主线程中运行HUD,在后台运行任务,这是我的意图。
[HUD_code showMessage:@"saving image"];
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
UIImageWriteToSavedPhotosAlbum(someUIImage ,nil,nil,nil);
dispatch_async(dispatch_get_main_queue(), ^{
[HUD_code dismiss];
});
});
答案 0 :(得分:5)
UIKit classes are documented to be usable from the main thread only,除非另有说明。 (例如,UIFont
is documented to be thread-safe。)
关于UIKit 函数(与类不同)的线程安全性没有明确的一揽子声明,所以假设它们通常是线程安全的并不安全。某些UIKit函数(如UIGraphicsBeginImageContext
)明确记录为线程安全,这意味着UIKit函数不通常是线程安全的。
由于UIImageWriteToSavedPhotosAlbum
可以发送异步完成消息,您应该在主线程上调用它并使用其完成支持来执行[HUD_code dismiss]
。
答案 1 :(得分:3)
以下是我阅读答案后的最新代码,如果有人关心,或评论(赞赏)。
-(void)saveToLibrary {
if (_imageView.image != NULL) {
messageHUD = @"Saving Image...";
[SVProgressHUD showWithStatus:messageHUD];
UIImageWriteToSavedPhotosAlbum(_imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
UIAlertView *alert;
// Unable to save the image
if (error) {
alert = [[UIAlertView alloc] initWithTitle:@"Error"
message:@"Unable to save image to Photo Album."
delegate:self cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
}else {// All is well
messageHUD = @"Success!\nImage Saved.";
[SVProgressHUD showSuccessWithStatus:messageHUD];
[self myPerformBlock:^{[SVProgressHUD dismiss];} afterDelay:0.5];
}
}
myPerformBlock来自以下链接https://gist.github.com/955123
答案 2 :(得分:1)
我认为这可以在后台线程上完成,但我错了吗?
老实说,我也会假设它,因为这与更新UI完全无关,它只是一些文件操作。但是,Apple的文档说每次调用UIKit都需要在主线程上执行(除非明确说明其他内容)。这个函数也不例外,你必须在主线程上调用它。
顺便说一下,这个函数本身就是异步的。它会在保存图像时通知作为第2和第3个参数提供的回调对象/选择器,因此它不会阻止UI。