2016-09-29 140 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