Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 目标-C:UIImageWriteToSavedPhotosAlbum();异步=问题_Objective C_Ios_Cocoa Touch - Fatal编程技术网

Objective c 目标-C:UIImageWriteToSavedPhotosAlbum();异步=问题

Objective c 目标-C:UIImageWriteToSavedPhotosAlbum();异步=问题,objective-c,ios,cocoa-touch,Objective C,Ios,Cocoa Touch,更新:此处也报告了此问题,并对原因进行了更详细的处理: 在我的例子中,错误是:“写忙”-这似乎是一个与设备速度有关的问题。可能有一些解决方案涉及到手动处理线程或类似的问题——但是,受Tommy下面回答的启发,我序列化了图像的保存,这解决了这个问题 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 情况: 我正在尝试使用for循环将大量图像保存到相机卷中(图像数量取决于用户输入-可能是1、2、3或理论上是数百)。图像由NSSet指向(尽管我可以轻松地执行NSArray),

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

在我的例子中,错误是:“写忙”-这似乎是一个与设备速度有关的问题。可能有一些解决方案涉及到手动处理线程或类似的问题——但是,受Tommy下面回答的启发,我序列化了图像的保存,这解决了这个问题

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

情况:

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

我正在使用
UIImageWriteToSavedPhotosAlbum()
保存分离线程上的图像(使用
NSThread
detachNewThreadSelector:toTarget:withObject:
class方法),并在主线程上启动
UIActivityIndicator
微调器

问题:

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

***-[NSKeyedUnarchiver initForReadingWithData:]:数据为空

例如,假设我导出了9幅图像。for循环将运行所有9个图像(通过NSLogging确认),但我将得到上述错误的4次迭代(并且只有5个图像保存到相机卷)

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

理论:

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

有没有简单的方法强制它同步运行(理想情况下在主线程上)?我一直在尝试将引用计数添加到我试图保存的图像中,但是(1)这感觉很粗糙,(2)无论如何我都没有解决这个问题


任何建议都很好。谢谢

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

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

也许值得一试,如果有帮助,请告诉我

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

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

也许值得一试,如果有帮助,请告诉我

如果您不想一次写入多个图像,那么可以使用
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);
}

编辑:还值得一看的是,您是否可以使用
AlassetLibrary
获得相同的结果,它需要一个块来完成,因此使用起来更加简单。

如果您不想一次写入多个图像,那么可以使用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);
}

编辑:还值得一看的是,使用
AlassetLibrary
是否会得到相同的结果,它需要一个块来完成,因此使用起来更简单。

我使用AlassetLibrary和
调度队列来确保图像按顺序保存:

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

我使用AlassetLibrary和
调度队列
确保按顺序保存图像:

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

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

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

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

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

锁定主线程意味着您的活动指示器将不会设置动画。您的应用程序将显示为挂起。是的,
UIImageWriteToSavedPhotosAlbum
以异步方式运行。错误日志听起来像是您要保存的图像为空,请检查您的图像数据。@danielbeard-是的,正确,抱歉-在本文的第二段中澄清了我的线程Situation@fannheyward-我已确认数据具有良好的断点。如果我正常运行8个图像,5个可以工作,3个失败。但是,如果我在循环结束时(在
UIImageWriteToSavedPhotosAlbum()
之后)添加一个断点,并在每个循环中“继续”循环之前等待1-2秒,它将正确导出所有8个图像,而不会出现投诉或错误。如果您使用iOS8或更高版本,请使用照片框架。它将处理这种情况。锁定主线程意味着您的活动指示器将不会设置动画。您的应用程序将显示为挂起。是的,
UIImageWriteToSavedPhotosAlbum
以异步方式运行。错误日志听起来像是您要保存的图像为空,请检查您的图像数据。@danielbeard-是的,正确,抱歉-在本文的第二段中澄清了我的线程Situation@fannheyward-我已确认数据具有良好的断点。如果我正常运行8个图像,5个可以工作,3个失败。但是,如果我在循环结束时(在
UIImageWriteToSavedPhotosAlbum()
之后)添加一个断点,并在每个循环中“继续”循环之前等待1-2秒,它将正确导出所有8个图像,而不会出现投诉或错误。如果您使用iOS8或更高版本,请使用照片框架。它会处理这种情况。我将对此进行一点试验,但只是为了确认:我100%可以同时写入所有图像。你的回答意味着可能有办法做到这一点?循环仅仅是我将所有图像传递给
UIImageWriteToSavedPhotosAlbum()
的实现。对不起,我的意思是不允许
UIImageWriteToSave一次写入多个图像