2016-09-29 139 views
2

我想創建一個協議,它有一個返回泛型類型的靜態方法。在大多數情況下,我似乎工作得很好。當我想使用擴展來返回這個通用值時,挑戰就出現了。這是我的。此代碼可以放置在操場上。與泛型類型的Swift協議

這裏的第一個協議,我想它包含associatedtype

protocol AWSerializable { 
    associatedtype T 

    static func deserialize(dictionary: [String : Any]) -> T? 
    func serialize() -> [String : Any] 
} 

然後,我創建了另一個協議,它允許我創建做反序列化的操作實例:

protocol AWDeserializer { 
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? 
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? 
} 

下面是一個例子愉快地實施AWSerializable協議:

class FooBar: AWSerializable { 

    typealias T = FooBar 

    var foo = "" 
    var bar = "" 

    static func deserialize(dictionary: [String : Any]) -> FooBar? { 
     let fooBar = FooBar() 

     fooBar.foo = (dictionary["foo"] as? String) ?? "" 
     fooBar.bar = (dictionary["bar"] as? String) ?? "" 

     return fooBar 
    } 

    func serialize() -> [String : Any] { 
     var serialized = [String : Any]() 

     serialized["foo"] = foo 
     serialized["bar"] = bar 

     return serialized 
    } 

} 

到目前爲止好。當我想在UserDefaults上創建extension來實現AWDeserializer協議時,挑戰就出現了。

extension UserDefaults: AWDeserializer { 
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? { 
     if let serialized = UserDefaults.standard.object(forKey: key) as? [String : Any] { 
      return T.deserialize(dictionary: serialized) 
     } 

     return nil 
    } 

    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? { 
     if let data = UserDefaults.standard.array(forKey: key) as? [[String : Any]] { 
      var values = [T]() 

      for entry in data { 
       if let value = T.deserialize(dictionary: entry) { 
        values.append(value) 
       } 
      } 

      return values 
     } 

     return nil 
    } 
} 

這裏的問題是與T.deserialize(dictionary: serialized)。我得到以下錯誤:

enter image description here

這很容易通過應用建議的解決方法固定,最好通過改變線路return T.deserialize(dictionary: serialized) as? T

但我不喜歡的事實,這可選演員陣容需要開始。有沒有辦法定義不需要這種轉換的協議?

回答

1

也許是更好的使用這個協議AWDeserializer

protocol AWDeserializer { 
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? where T.T == T 
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? where T.T == T 
} 

相反的:

protocol AWDeserializer { 
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? 
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? 
} 

這裏是代碼的其餘部分:

protocol AWSerializable { 
    associatedtype T 

    static func deserialize(dictionary: [String : Any]) -> T? 
    func serialize() -> [String : Any] 
} 

protocol AWDeserializer { 
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? where T.T == T 
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? where T.T == T 
} 

class FooBar: AWSerializable { 

    typealias T = FooBar 

    var foo = "" 
    var bar = "" 

    static func deserialize(dictionary: [String : Any]) -> FooBar? { 
     let fooBar = FooBar() 

     fooBar.foo = (dictionary["foo"] as? String) ?? "" 
     fooBar.bar = (dictionary["bar"] as? String) ?? "" 

     return fooBar 
    } 

    func serialize() -> [String : Any] { 
     var serialized = [String : Any]() 

     serialized["foo"] = foo 
     serialized["bar"] = bar 

     return serialized 
    } 

} 

extension UserDefaults: AWDeserializer { 
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? where T.T == T { 
     if let serialized = UserDefaults.standard.object(forKey: key) as? [String : Any] { 
      return T.deserialize(dictionary: serialized) 
     } 

     return nil 
    } 

    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? where T.T == T { 
     if let data = UserDefaults.standard.array(forKey: key) as? [[String : Any]] { 
      var values = [T]() 

      for entry in data { 
       if let value = T.deserialize(dictionary: entry) { 
        values.append(value) 
       } 
      } 

      return values 
     } 

     return nil 
    } 
} 
+0

這是一個可能性,我原本是有這個的。我遇到了兩個問題。首先是我無法在擴展類上實現此協議。就我所知,'init'要求使得這個不可能。另一個問題是擴展一個類時,'init'方法可能會在超類中具有所需的初始化器的一些副作用。 – jervine10

+1

如果是這樣的話? T'是必需的,因爲'AWSerializable.T'和'AWSerializable'可能是不同的類型,所以使用''AWSerializable.T'就可以'AWSerializable'。 – beeth0ven

+0

這是宣佈這些協議的唯一方法嗎?是否有更好的方法來聲明'AWDeserializer',以便不需要強制轉換? – jervine10