1

更新:这里也报告了这个问题,对原因进行了更详细的处理:

UIImageWriteToSavedPhotosAlbum 只保存 10 张图片中的 5 张。为什么?

在我的情况下,错误也是:“写忙” - 这似乎是与设备速度有关的问题。可能有一些涉及手动处理线程或类似的解决方案 - 但是,受以下 Tommy 回答的启发,我对图像的保存进行了序列化,并且可以解决该问题。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

情况:

我正在尝试使用 for 循环将大量图像保存到相机胶卷(图像数量取决于用户输入 - 可能是 1、2、3 或理论上数百个)。图像由 an 指向NSSet(尽管我可以很容易地做 an NSArray),并且在 for 循环完成后NSSet设置为。nil

UIImageWriteToSavedPhotosAlbum()用来保存分离线程上的图像(使用NSThread'sdetachNewThreadSelector:toTarget:withObject:类方法),并UIActivityIndicator在主线程上启动一个微调器。

问题:

当我尝试保存超过 ~5 个时,~5th 之后的任何图像都会在日志中输出此错误:

*** -[NSKeyedUnarchiver initForReadingWithData:]: data is NULL

例如,假设我导出了 9 张图像。for 循环将遍历所有 9 张图像(由 NSLogging 确认),但我将得到上述错误的大约 4 次迭代(并且只有 5 张图像保存到相机胶卷)。

但是,如果我在循环中添加一个断点并在每次迭代之间等待一两秒钟,它们都会正确保存而不会产生任何抱怨。所以..

理论:

根据我的日志和观察,UIImageWriteToSavedPhotosAlbum()显然是异步运行的,并且在某种程度上“太慢”无法跟上我的应用程序。

有没有一种简单的方法可以强制它同步运行(最好在主线程上)?我一直在尝试为要保存的图像添加引用计数,但是(1)这感觉很老套,(2)无论如何我都没有解决这个问题。

任何建议都会很棒。谢谢!

4

4 回答 4

6

我使用 ALAssetsLibrary 和 adispatch_queue来确保图像按顺序保存:

ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
dispatch_queue_t queue = dispatch_queue_create("com.myApp.saveToCameraRoll", NULL);

[images enumerateObjectsUsingBlock:^(UIImage *image, NSUInteger idx, BOOL *stop) {

    dispatch_async(queue, ^{

        dispatch_semaphore_t sema = dispatch_semaphore_create(0);

        [library writeImageToSavedPhotosAlbum:image.CGImage metadata:metaData completionBlock:^(NSURL *assetURL, NSError *writeError) {

            if (writeError) {
                // handle the error
            }
            else {
                if (image == [images lastObject]) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        // perhaps indicate to the user that save has finished
                    });
                }
            }

            dispatch_semaphore_signal(sema);

        }];

        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        dispatch_release(sema);
    });
}];
于 2013-07-12T11:54:59.873 回答
3

如果您不希望一次写入多个图像,那么您可以使用UIImageWriteToSavedPhotosAlbum' 完成目标和选择器来实现一种尾递归形式。就像是:

- (void)writeSetToSavedPhotosAlbum:(NSMutableSet *)images
{
    if(![images count]) return;

    UIImage *imageToSave = [[[images anyObject] retain] autorelease];
    [images removeObject:imageToSave];
    NSLog(@"I shall now write image %@", imageToSave);

    UIImageWriteToSavedPhotosAlbum(
            imageToSave,
            self,
            @selector(writeSetToSavedPhotosAlbum:),
            images);
}

编辑:可能还值得看看你是否得到与ALAssetsLibrary's相同的结果-writeImageToSavedPhotosAlbum:orientation:completionBlock:,这需要一个块来完成,因此使用起来更加简单。

于 2012-08-27T01:23:36.660 回答
0

文档确实提到您将收到异步通知。我想知道这是否可行:为每个要保存的图像创建一个块操作并将其添加到主操作队列。有一些像:

for (UIImage *toSave in imagesToSave)
{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        UIImageWriteToSavedPhotosAlbum(toSave, target, selector, ctx);
    }];
}

可能值得一试,如果有帮助,请告诉我!

于 2012-08-27T01:22:32.900 回答
0

在此代码工作保存图像中:

  UIImageWriteToSavedPhotosAlbum([self screenshot], nil, nil, nil);

UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"Save" message:@"Photo saved to album" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
[alert show];
于 2017-06-05T07:27:23.317 回答