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

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

ただいまの
回答率

88.82%

[Swift] Codableの挙動がデバイスによって変わる

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 360

komo_ta

score 263

はじめに

現在開発中のiPhoneアプリにて、WebAPIをリクエストし、jsonを取得し、Codableを使用して任意のモデルに変換しようとしており、その際に起こった問題です。

問題

デバイスによって、
The data couldn't be read because it isn't in the correct format.  
error が返されます。

下記のようなJSONを取得し

"hoges": [
{
   "name": "hogehoge",
   "link": "google.co.jp",
   "thumbnail": "hoge.jpg",
   "pubdate": "Fri, 15 Feb 2019 10:00:10 +0900"
}
{
.....

]

こちらのデータを変換するために下記のようなコードを書いています。(必要な箇所だけ書いてます)

class HogeManager {
   static func createModel() {
     APIClient.request(path: .hoge, completionHandler: { (str, err) -> (Void) in
        guard let str = str else { return }
        do {
              let data = str.data(using: .utf8)!
              let decoder = JSONDecoder()
              decoder.dateDecodingStrategy = .formatted({ return eeeddMMMyyyyFormatter }())
              let hoges = try decoder.decode([Hoge].self, from: data)
        } catch let err {

        }
     })
   }
}

public let eeeddMMMyyyyFormatter: DateFormatter = {
    let formatter: DateFormatter = DateFormatter()
    formatter.dateFormat = "EEE, dd MMM yyyy hh:mm:ss Z"
    return formatter
}()

class Hoge : Decodable {
    var name: String?
    var link: String?
    var thumbnail: String?
    var publishDate: Date? //Format: EEE, dd MMM yyyy hh:mm:ss

    private enum CodingKeys: String, CodingKey {
        case name
        case link
        case thumbnail
        case publishDate = "pubdate"
    }
}

自分が使用している実機iPhone 8 (iOS 12.2) では、上記のエラーが起きず正常にモデルへの変換ができましたが、同バージョンのシミュレータiPhoneXやiPhone8、現在の最新バージョンのiPhoneX実機では、モデルへ変換することができず上記のerrorが表示されます。

日本語、英語などのデバイスの言語の違いを調べましたが、そちらには依存しないようで、現状どこが原因かわかりません。どなたかアドバイスいただける方いらっしゃいましたら、お願いいたします。m(_ _)m

追記

上記の内容に誤りがあるので、追記します。
任意のクラスでAlamofireを使って、Stringでレスポンスを受け取り、そのStringをDataクラスに変換し、JSONDecoderを使用して、任意のモデルに変換しています。

モデルにおけるDate関連のプロパティを外すと、変換できていることはわかっていまして、現在その部分を調査中です。

class APIClient {

  static func request() {
     AF.request(url, method: .get, headers: headers, interceptor: nil).responseString { (response) in
            switch(response.result) {
            case .success(_):
                print("success reuest:::\(String(describing: response.request))")
                guard let resultStr = response.result.value else {
                    completionHandler(nil, APIError.jsonParseError)
                    return
                }
                completionHandler(resultStr, nil)
            case .failure(let error):
                print("failure request:::\(String(describing: response.request))")
                completionHandler(nil ,error)
            }
        }

  }

}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • komo_ta

    2019/05/16 11:34

    そちら配列で返されているものを変換しようとしておりまして、上記の内容変更しました。

    キャンセル

  • fuzzball

    2019/05/16 11:36

    たぶん formatter.locale = Locale(identifier: "en_US_POSIX") でいけるんじゃないかな。

    >>日本語、英語などのデバイスの言語の違いを調べましたが、そちらには依存しないようで
    これは検証ミスのような気がする。

    キャンセル

  • komo_ta

    2019/05/16 11:48

    @fuzzball さま
    上記試したところ、本来errorが発生してない実機でエラーが発生したので、こちら重点的に調べてみます。※エラーが発生していたデバイスはエラーが変わらず発生しました。
    ありがとうございます。

    キャンセル

回答 1

check解決した方法

0

上記のDateFormatterを以下のように修正したところ正常に動作しました。

public let eeeddMMMyyyyFormatter: DateFormatter = {
    let formatter: DateFormatter = DateFormatter()
    formatter.dateFormat = "EEE, dd MMM yyyy hh:mm:ss Z"
    /* 下記三行追加コード */
    formatter.locale = Locale.current
    formatter.timeZone = TimeZone.current
    formatter.calendar = Calendar(identifier: .gregorian)

    return formatter
}()

アドバイスいただけた方々ありがとうございましたm(_ _)m

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

  • ただいまの回答率 88.82%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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