bugfix> json > 投稿

JSONがあります

{
"tvShow": {
    "id": 5348,
    "name": "Supernatural",
    "permalink": "supernatural",
    "url": "http://www.episodate.com/tv-show/supernatural",
    "description": "Supernatural is an American fantasy horror television series created by Eric Kripke. It was first broadcast on September 13, 2005, on The WB and subsequently became part of successor The CW's lineup. Starring Jared Padalecki as Sam Winchester and Jensen Ackles as Dean Winchester, the series follows the two brothers as they hunt demons, ghosts, monsters, and other supernatural beings in the world. The series is produced by Warner Bros. Television, in association with Wonderland Sound and Vision. Along with Kripke, executive producers have been McG, Robert Singer, Phil Sgriccia, Sera Gamble, Jeremy Carver, John Shiban, Ben Edlund and Adam Glass. Former executive producer and director Kim Manners died of lung cancer during production of the fourth season.<br>The series is filmed in Vancouver, British Columbia and surrounding areas and was in development for nearly ten years, as creator Kripke spent several years unsuccessfully pitching it. The pilot was viewed by an estimated 5.69 million viewers, and the ratings of the first four episodes prompted The WB to pick up the series for a full season. Originally, Kripke planned the series for three seasons but later expanded it to five. The fifth season concluded the series' main storyline, and Kripke departed the series as showrunner. The series has continued on for several more seasons with Sera Gamble and Jeremy Carver assuming the role of showrunner.",
    "description_source": "http://en.wikipedia.org/wiki/Supernatural_(U.S._TV_series)#Spin-off_series",
    "start_date": "2005-09-13",
    "end_date": null,
    "country": "US",
    "status": "Running",
    "runtime": 60,
    "network": "The CW",
    "youtube_link": "6ZlnmAWL59I",
    "image_path": "https://static.episodate.com/images/tv-show/full/5348.jpg",
    "image_thumbnail_path": "https://static.episodate.com/images/tv-show/thumbnail/5348.jpg",
    "rating": "9.6747",
    "rating_count": "249",
    "countdown": null
}
}

rating の値別の連載では Int ( "評価":0)または String (「評価」:「9.6747」)。

Codable/DecodableプロトコルでJSONを解析しています:

struct DetailModel : Decodable {
var id : Int?
var name : String?
var permalink : String?
var url : String?
var description : String
var description_source : String?
var start_date : String?
var end_date : String?
var country : String?
var status : String?
var runtime : Int?
var network : String?
var youtube_link : String?
var image_path : String?
var image_thumbnail_path : String?
var rating: String
var rating_count : String?
var countdown : String?
var genres : [String]?
var pictures : [String]?
var episodes : [EpisodesModel]?
}

rating == Stringの場合、コードは機能し、JSONのすべての変数がありますが、rating == Intの場合、すべて nil です 。すべてのタイプの変数 rating を解析するにはどうすればよいですかすぐに Int および String

私のデコード可能な機能:

   func searchSerialDetail(id: Int, completion: @escaping (DetailModel?) -> Void){
    let parameters: [String: Any] = ["q": id]
    Alamofire.request(DetailNetworkLayer.url, method: .get, parameters: parameters).response { (jsonResponse) in
        if let jsonValue =  jsonResponse.data {
            let jsonDecoder = JSONDecoder()
                let detail = try? jsonDecoder.decode(DetailModel.self, from: jsonValue)
                completion(detail)
        }
    }
}

ありがとうございました。

回答 1 件
  • 独自の func encode(to encoder: Encoder) throws を実装する必要があります  および init(from decoder: Decoder) throws  どちらも Codable のプロパティです  プロトコル。次に、 rating を変更します  に変数列挙型

    次のようになります:

    enum Rating: Codable {
        case int(Int)
        case string(String)
        func encode(to encoder: Encoder) throws {
            var container = encoder.singleValueContainer()
            switch self {
            case .int(let v): try container.encode(v)
            case .string(let v): try container.encode(v)
            }
        }
        init(from decoder: Decoder) throws {
            let value = try decoder.singleValueContainer()
            if let v = try? value.decode(Int.self) {
                self = .int(v)
                return
            } else if let v = try? value.decode(String.self) {
                self = .string(v)
                return
            }
            throw Rating.ParseError.notRecognizedType(value)
        }
        enum ParseError: Error {
            case notRecognizedType(Any)
        }
    }
    
    

    次に、 DetailModel で   rating: String を変更するだけ   rating: Rating

    これは機能し、これらのJSON文字列でテストしました。

    // int rating
    {   
        "rating": 200,
        "bro": "Success"
    }
    // string rating
    {
        "rating": "200",
        "bro": "Success"
    }
    
    

    編集init(from decoder: Decoder) throws を実装するより迅速な方法を見つけました 、これはより良いエラーメッセージを生成します。これを使用することで、 ParseError を省略できます。  列挙型。

    init(from decoder: Decoder) throws {
        let value = try decoder.singleValueContainer()
        do {
            self = .int(try value.decode(Int.self))
        } catch DecodingError.typeMismatch {
            self = .string(try value.decode(String.self))
        }
    }
    
    

あなたの答え