1

更新:この問題はここでも報告されており、原因のより詳細な処理が含まれています。

UIImageWriteToSavedPhotosAlbumは、10個のうち5個の画像のみを保存します。なぜですか。

私の場合も、エラーは「書き込みビジー」でした。これは、デバイスの速度に関連する問題のようです。おそらく、スレッドなどを手動で処理することを含むいくつかの解決策がありますが、以下のTommyの回答に触発されて、画像の保存をシリアル化し、問題を回避します。

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

状況:

forループを使用して大量の画像のコレクションをカメラロールに保存しようとしています(画像の数はユーザー入力によって異なります。理論的には数百になります)。画像はNSSet(私も同じように簡単に実行できますがNSArray)によってポイントされ、forループが完了した後ににNSSet設定されます。nil

私は(のクラスメソッドUIImageWriteToSavedPhotosAlbum()を使用して)切り離されたスレッドに画像を保存するために使用しており、メインスレッドでスピナーを起動しています。NSThreaddetachNewThreadSelector:toTarget:withObject:UIActivityIndicator

問題:

〜5を超えて保存しようとすると、〜5日以降の画像は、次のエラーをログに出力します。

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

たとえば、9枚の画像をエクスポートしたとします。forループは9つの画像すべてを実行します(NSLoggingによって確認されます)が、上記のエラーが約4回繰り返されます(カメラロールに保存される画像は5つだけです)。

ただし、ループにブレークポイントを追加し、各反復の間に1〜2秒待つと、問題なくすべて正しく保存されます。それで..

仮説:

私のログと観察に基づくと、UIImageWriteToSavedPhotosAlbum()明らかに非同期で実行されており、アプリケーションに追いつくにはどういうわけか「遅すぎる」。

同期的に(理想的にはメインスレッドで)実行するように強制する簡単な方法はありますか?保存しようとしている画像に参照カウントを追加することを試みてきましたが、(1)これはハッキーだと感じ、(2)それでも問題を解決できませんでした。

どんなアドバイスも素晴らしいでしょう。ありがとう!

4

4 に答える 4

6

ALAssetsLibraryとを使用dispatch_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 に答える