うるおいらんど

iOS12.0におけるCoreDataのバグをどうにか解決した話。

CoreDataSwift

こんにちは、Reoです。

前回の記事「ios12でCoreDataのExternal Storangeを利用しているデータが破損してしまう問題が発生した件」で、地獄のようなiOSのバグに見舞われてしまったアプリをどうにか復旧することができました。

わりと特殊な例な気もしますので役には立たないかもしれませんが、解決した方法について少し書いていこうと思います。

 

発生したバグ

前回の記事にも書きましたが、バグの内容は以下の通りです。

発生条件

  • iOS12.0.x
  • CoreDataでExternal Storageを利用している

この条件下でアプリを起動したところ、contextの2回ごとぐらいにデータが破損します。

DB内に外部ストレージへのパスが保存されていますが、そちらが別の値に書き換えられてしまい、参照ができなくなってしまいます。

つまり、「写真を特定するためのデータ」と「写真」の紐付けが切られてしまうというバグです。

このバグのせいでアプリが使い物にならなくなり完全にオワコンになっていました。

 

首の皮一枚

此方のバグですが、なんとか対応することができました。実際にはユーザーの環境で動くかどうかは多少心配していますが、きっと大丈夫なはず。天才<(_゚ー ゚_)>

やったことは結構しょうもないことです。1日あればできました。

 

「日付・ID等のデータ」 - × - 「写真」なわけですが、前者のデータには主に以下のものが含まれていました。

  • ID
  • 日付
  • サムネイル画像
  • オリジナル画像(外部ストレージへの参照)

破損したデータは一番最後のオリジナル画像だけになります。

サムネイル画像は残っているのです。つまり・・・

 

オリジナル画像を加工して判定

もしかして画像って同じ方法で加工したら一致するでは?と思い試してみたところ、ビンゴでした。

実は自分は一致しないだろうと思ってたんですけどね。ダメ元でやってみたらできちゃいました。

 

手順としては

  1. データ破損があった場合の判定
  2. External Storageにある写真(Data)をUIImageに変換する
  3. 2をサムネイルと同じ大きさに加工する
  4. 3のUIImageをDataに変換する
  5. 4のDataと、サムネイルDataを比較する
  6. 一致すれば参照を保存し直す。一致しなければ2へ。
  7. 2を返す

こんな風な処理をしました。

static func getLostPhotoData(thumbnailData: Data, imageID: String, completion: @escaping (Data)->()) {
    // External Storageのパスを取得
    guard let externalStorage: URL = AppDelegate().applicationDocumentsDirectory.appendingPathComponent(".SingleViewCoreData_SUPPORT/_EXTERNAL_DATA") else {
        return
    }
    
    do {
        let filePaths = try FileManager.default.contentsOfDirectory(at: externalStorage, includingPropertiesForKeys: nil
            , options: [])
        for filePath in filePaths {
            autoreleasepool {
                let data = try! Data(contentsOf: filePath) // 2
                let image = UIImage(data: data)            // 2
                
                let resizeImg = ImageManager.resizeImage(image: image!)     // 3
                let resizeData = UIImageJPEGRepresentation(resizeImg, 0.7)  // 4
                if  resizeData == thumbnailData {                           // 5
                    StoreManager.saveLostPhotoData(data: data, imageID: imageID)  // 6
                    completion(data)  // 7
                }
            }
        }
        
    } catch {
        print("error\(error)")
    }
}

 

これが一致したから本当助かった。

ユーザーに紐付けを全部直してもらうところでしたわ。何百枚とってるかもしれんのにw

 

しかし一時しのぎ

お察しかもしれませんが、写真枚数が多ければ多いほど処理は重くなります。なので正直パフォーマンスは最悪です。

いつ破損しているのかがハッキリしていませんし、紐付けを直したところでまたすぐ破損してしまうっていう状態です。せめて先に破損しているデータを探してきてから、加工処理して判定すればもう少し軽くなったかな・・・

 

iOS12.1が今月末リリースされるという噂があったので、それまではどうにか凌いで欲しいところです。現在審査待ち中で、不備がなければ明日には出るかなって感じです。(メタデータリジェクト食らったんで本当は今日出せるはずだったんですけどね・・・)

ちなみにリジェクト内容は以下の通り。

Your app contains references to test, trial, demo, beta, pre-release or other incomplete content.

Specifically, your What’s New text contains beta references (beta版を利用して確認致しました).

iOS12.1ではバグが直っているのを丁寧にbeta版を利用して確認したよって書いただけなのに・・・安心感を与えたかっただけなのに・・・・

 

アプリ内にも同じ文言があるわけですが、まぁそっちは大丈夫でしょう。他に不備がなければ多分明日出ます。

 

でもまぁ、来月中にはRealmかなんかにでも移行しようとは思っています。

CoreDataを使う1番の理由と言っても過言ではない、Apple純正の安心感は失われてしまいましたからねー。Apple製だからiOSのバージョンが上がっても特に何もしなくても使えて当たり前だと思っていたのにネ。

ほいではでは。

Comments

コメントはありません。

現在コメントフォームは工事中です。