2017-03-29 165 views
1

在斯威夫特3:想象一下,你希望你的模型是值类型(结构),通过了您的应用程序。但是你也希望使用Core Data/Realm来持久化这些模型,这需要你创建类。然后,你可以使用JSON(这需要结构和类都支持JSON反序列化和序列化)的结构转换成类,反之亦然。默认初始化器需要不需要可变的特性

岂不是整齐的,如果你没有写反序列化JSON(以及类似的序列化,但我在这里集中在反序列化)在两个地方,但在协议使用放反序列化,即你的结构和类都使用。

使用结构,我们希望我们的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

只需在'UserModel'中设置'init(username:String)'而不是'init()'。 – Hamish

+0

感谢您的建议,我更新@Hamish它使代码重复的问题... – Sajjon

+0

使用'struct's的好处是,你可以仅仅依靠在这种情况下,默认按成员初始化器:)所以,你可以只是删除'UserStruct'的初始化程序。 – Hamish

回答

0

感谢@hamish指出,最好的解决方案是(其中struct JSONprotocol JSONDeserializable保持与问题中相同)。这不是一个完美的解决方案,因为你必须实现类的初始化器。整洁的部分是你不必为结构实现任何初始化器,因为它有一个隐含的。

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"