質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • Xcode

    5024questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

  • Swift 2

    1339questions

    Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

  • iOS 9

    215questions

    iOS 9は、アップル社のモバイルOSであるiOSシリーズのバージョン。特徴として検索機能の強化、Siriの機能改良、iPad向けマルチタスクなどがあります。マルチウィンドウ機能をサポートし、iPad向けマルチタスクもサポートされています。

複数のUIImageを一括でカメラロールに保存したい

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 1,534

kawakam

score 5

最近プログラミングを始めた者で、初めての投稿になります。どうぞ宜しくお願い致します。

ネットから取得した画像データを一括でiPhoneのカメラロールに保存するアプリを作っております。
画像データ自体は何とか取得が出来て、空のUIImage型の配列に取得した順番で追加出来たのですが、それをカメラロールに保存する作業でエラーが出てしまっています。
40枚近いデータがあるはずなのですが、毎回6枚ほどしか保存できていない状況です。配列自体をprint()で出力してみても、ちゃんと40枚前後のデータがデバックエリアに出力される為、配列に保存すること自体は出来ていると思います。

エラー文にある「リソースがビジー」とは、配列のデータをバッファ(?)に書き込んだあと、そのデータを保存する前にバッファが上書きされているということなのでしょうか…?上書きのタイミングが早すぎて保存が追いついていない…?


自分なりに調べては見たのですがどうしても以下のエラーが解決できません。
何卒お力添えいただきますよう、心よりお願いいたします。



エラー文

Xcodeで出力されたエラー文です

NSLocalizedFailureReason=There was a problem writing this asset because the writing resources are busy.}}, NSLocalizedDescription=Write busy, NSLocalizedRecoverySuggestion=Try to write again, NSLocalizedFailureReason=There was a problem writing this asset because the writing resources are busy.}



ソースコード

どうやらこのメソッド部分ででエラーが出てしまう様です。imageManaインスタンスのプロパティであるimages配列に画像データが入っていて、.imgの部分がUIimage型の要素です。

カメラロールに保存するメソッドは以下のURLを参考にしました。
http://qiita.com/kitanoow/items/995d254fa6cd89f066cb


func saveAllImages() {
        for fetch in imageMana.images {
            UIImageWriteToSavedPhotosAlbum(fetch.img, self, "image:didFinishSavingWithError:contextInfo:", nil)
        }
}



補足情報

質問者としても右も左も分からない状態で、「質問者として何々が書き足りない」「この情報だけじゃエラーの原因が分からない」など、そのような点もご指摘頂けたらありがたいです。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+2

ストレージ容量不足だけでなく、別の原因で複数同時書き込みが失敗する可能性があるのですね。
1枚ずつ画像を保存するなら、例えば
保存中の画像を保持した配列を以下のようなプロパティで定義し、
    
var savingImages : [UIImage] = []

以下のような保存メソッドを作成し
    func saveImage() {
        if savingImages.count > 0 {
            UIImageWriteToSavedPhotosAlbum(savingImages[0], self, "image:didFinishSavingWithError:contextInfo:", nil)
            savingImages.removeAtIndex(0)
        } else {
            print("all completed.")
        }
    }

    func image(image: UIImage, didFinishSavingWithError error: NSError!, contextInfo: UnsafeMutablePointer<Void>) {
        if error != nil {
            print("save error \(image)")
            print(error.description)
        } else {
            print("save completed \(image)")
            saveImage()
        }
    }
保存を開始したいところで、保存したいイメージの配列をsavingImagesに格納した上で、saveImage()を呼び出せば良いです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/11/03 16:37

    お陰様で無事解決しました!質問自体初めての経験で投稿時は非常に不安でしたが、丁寧に解説して頂けてとても感謝しています。教えていただいたsampleのソースコードも非常に助かりました。fuzzballさんTakeOneさん本当にありがとうございました!

    キャンセル

0

UIImageWriteToSavedPhotosAlbumは非同期関数ですので、
正常終了にせよエラーにせよ終了を待たないといけません。
(参照された記事は正常終了処理が書かれていませんね)
if error != nil {
    //エラー → 止める or リトライ or スキップ
} else {
    //正常終了 → 次の画像へ
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

私も以前同様の問題に遭遇し、調べたことがあります。

UIImageWriteToSavedPhotosAlbumは非同期関数なので、画像の書き込みが完了する前にその画像にアクセスするとエラーになると思いますが、複数の新しい画像(別々の画像)の同時書き込みはできるはずです。私が調べた限り、このエラーが発生するのは空きストレージ量が不足している場合です。

設定アプリの[一般]-[ストレージとiCloudの使用状況]で、使用可能な空きストレージ量を確認してみてください。
私の感触的には、一度に保存しようとしている画像の合計データサイズの2倍以上ストレージの空きがないとエラーが発生するケースが出てくる感じです。(あくまで感触であり、公式のドキュメントに書かれているような正確な情報ではありません。)

なお、ストレージの空きを増やすために、写真アプリで写真を削除するだけではダメです。
写真アプリで写真を削除した場合、実際には「最近削除した項目」のフォルダに写真が移動するだけで空きストレージ量は増えません。「最近削除した項目」のフォルダで[選択]ボタンをタップして[全て削除]を実施することで空きストレージ量が増えます。この点も、今回の問題が空きストレージ量の問題ではないと勘違いしがちになるところです。(毎回不要な写真を削除してからテストしているので空きストレージ量は問題ないと思いがち)

ただ、このように複数の画像を一度に同時保存しようとすると、同時処理のために同時に必要なストレージが増えるのも確かで、空き容量が少ない状態でもできるだけ保存できるようにしたいなら、保存完了通知を受信しながら1枚ずつ保存する処理もありだと思います。

同時保存するなら、どの画像が保存成功し、どの画像が保存失敗したかユーザーにわかるようにし、保存失敗した分については、ユーザーが不要なデータを整理してから、失敗した分の保存を後で再実行できるようにするユーザーインターフェースを合わせて作る必要があると思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/11/02 14:25

    ごく小さな画像(10x10pixel)を10枚連続で保存しようとしても同様のエラーが発生しますので、空き容量の問題では無いと思います。

    キャンセル

  • 2015/11/02 15:26

    私の場合、3414x2560サイズのJPEG画像(約2MB)を60枚連続(合計120MB)でUIImageWriteToSavedPhotosAlbumを実行しましたが、空きストレージが320MBある時はエラーは発生せず、空きが200MBの時は60枚中1〜2枚で質問のエラーメッセージのエラーが発生しました。また、空きがない場合は、ほとんどの画像が同様のエラーになりました。
    このことから、このエラーは空き容量の問題が影響していると考えましたが、どこか正式なドキュメントに記載された仕様を説明したものではなく、こちらの環境で調査した結果を参考にお伝えしたものです。fuzzballさんがおっしゃるように、同時保存を実行した時にエラーとなる要因が空き容量の問題とは別に何かあるのかもしれません。

    キャンセル

  • 2015/11/02 16:10

    「空き容量の問題では無い」ではなく「空き容量の問題だけではない」ということですね。検証結果を否定するような書き方をして申し訳ありませんでした。

    キャンセル

  • 2015/11/02 23:04

    お二人ともコメント本当にありがとうございます。ストレージの空きを増やす為に最近消去した項目も全て消去してから試してみたのですが、同様のエラーが表示されてしまいました。なので今回はお二人に指摘して頂いた非同期通信の部分に原因がある可能性が高そうです。しかし今後別の保存処理などで同じ様なエラーが出た時にはTakeOneさんにご指摘頂いたストレージの容量不足でのエラーを真っ先に疑ってみたいと思います。

    非同期通信ということで、画像を保存する(書き込む?)処理の終了を待たずに次の画像を読み込んでしまうのが原因、ということはお二人のコメントから理解しました。そこでそれを回避する為にif文を用いて、1つの画像の読み取りと書き込みの処理が終わるタイミングで一旦保存処理の動作を止めてやる(?)ことの必要性も理解したつもりなのですが、恥ずかしながらerror処理の文の書き方が分からない状態でして…

    if error != nil {
    //エラー → 止める or リトライ or スキップ
    } else {
    //正常終了 → 次の画像へ
    }

    このif文は、保存処理のメソッド内に書けば良いのでしょうか?
    それともこのif文の中に画像を保存するメソッドを記述すべきなのでしょうか。

    参考書などでSwiftやプログラミングの基礎の基礎は学んだのですが、error処理等の知識がまだ追いついていない状況です。ネット等でも検索してみたのですが、今の自分が理解出来る範囲でerror処理を解説してくれている記事を探し当てることが出来ませんでした。厚かましいお願いにはなるのですが、この処理をどの様に記述すれば良いかアドバイス頂けるとありがたいです。重ね重ね申し訳ありません。

    キャンセル

同じタグがついた質問を見る

  • Xcode

    5024questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

  • Swift 2

    1339questions

    Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

  • iOS 9

    215questions

    iOS 9は、アップル社のモバイルOSであるiOSシリーズのバージョン。特徴として検索機能の強化、Siriの機能改良、iPad向けマルチタスクなどがあります。マルチウィンドウ機能をサポートし、iPad向けマルチタスクもサポートされています。