2017-03-29 11 views
1

スウィフト3:あなたのモデルをあなたのアプリケーションから値型(構造体)にしたいとします。しかし、Core Data/Realmを使用してモデルを永続化することもできます。これは、クラスを作成する必要があります。 JSON(JSONの逆シリアル化とシリアライゼーションの両方をサポートする構造体とクラスが必要です)を使用して、構造体をクラスとその逆に変換できます。プロトコルの初期イニシャライザで望ましくない可変プロパティが必要です

あなたはJSONの直列化復元を記述する必要はありません(と同様に直列化のために、私はここに、逆シリアル化に焦点を当てています)2つの場所ではなく、プロトコルに入れて直列化復元を使用している場合、それはきちんとしたことはないでしょう、そのあなたの構造体とクラスの両方を使用します。

構造体を使用して、JSONモデルに不変フィールドを持たせて、すべてのプロパティがletの定数になるようにします。しかし、デシリアライズを実装したを使用しても、このAFAIKは許可されません。

次のコード例は、に動作しますが、それは理由コード内のコメントに記載されているすべての不要な要件(UR)の、醜いです。

struct JSON { 
    let json: [String: Any] 
    func value<Value>(_ key: String) throws -> Value { 
     guard let value = json[key] as? Value else { throw NSError() } 
     return value 
    } 
} 

protocol JSONDeserializable { 
    init(json: JSON) throws 
} 

protocol UserModel: JSONDeserializable { 
    var username: String { get set } // Unwanted requirement (UR) #1: property needs "set" so that it can be initialized within protocol 
    init() // UR2: needs empty init, because of default implementation of `init(json: JSON)` in `extension UserModel` 
} 

extension UserModel { 
    init(json: JSON) throws { 
     self.init() // UR3: Needs to call this otherwise compilation error: `'self' used before chaining to another self.init requirement` 
     username = try json.value("username") 
    } 
} 

struct UserStruct: UserModel { 
    // UR4: property cannot be `let`, beause of `set` in protocol. 
    var username: String = "" // UR5: Property have to have default value because of it being a empty init 
    init() {} 
} 

final class UserClass: NSObject, UserModel { 
    // UR6: analogue with UR4 
    var username: String = "" // UR7: analogue with UR5 
} 

let json: JSON = JSON(json: ["username": "Sajjon"]) 
let u1 = try UserStruct(json: json) 
let u2 = try UserClass(json: json) 
print(u1.username) // prints "Sajjon" 
print(u2.username) // prints "Sajjon" 

これを達成する別の方法が、不要な要件を少なくしていますか?または、URがゼロの最適解?

+1

'init()'の代わりに 'UserModel'に' init(username:String) 'を指定するだけです。 – Hamish

+0

提案をお寄せいただきありがとうございます。私は@Hamishという質問を更新してコードを繰り返しました... – Sajjon

+0

'struct'sを使う利点は、この場合にはデフォルトのmemberwise initialiserに頼ることができるということです。 'UserStruct'の初期化子です。 – Hamish

答えて

0

@hamishが指摘したことのおかげで、最良の解決策は(struct JSONprotocol JSONDeserializableは質問と同じです)。これは、クラスの初期化子を実装する必要があるため、完璧な解決策ではありません。素朴な部分は、構造体に初期化子を実装する必要がないということです。なぜなら、それは暗黙のうちに1つを持つからです。

protocol UserModel: JSONDeserializable { 
    var username: String { get } 
    var firstname: String { get } 
    var country: String { get } 
    init(
     username: String, 
     firstname: String, 
     country: String 
    ) 
} 

extension UserModel { 
    init(json: JSON) throws { 
     self.init(
      username: try json.value("username"), 
      firstname: try json.value("firstname"), 
      country: try json.value("country") 
     ) 
    } 
} 

struct UserStruct: UserModel { 
    let username: String 
    let firstname: String 
    let country: String 
    // struct has default initializer 
} 

final class UserClass: UserModel { 
    let username: String 
    let firstname: String 
    let country: String 
    init(
     username: String, 
     firstname: String, 
     country: String 
     ) { 
     self.username = username 
     self.firstname = firstname 
     self.country = country 
    } 
} 

let json: JSON = JSON(json: [ 
    "username": "Sajjon", 
    "firstname": "Alexander", 
    "country": "Sweden" 
    ]) 
let u1 = try UserStruct(json: json) 
let u2 = try UserClass(json: json) 
print(u1.username) // prints "Sajjon" 
print(u2.username) // prints "Sajjon" 
関連する問題