Swift 3:有没有办法同时将对象转换为类和协议?

the*_*wan 8 existential-type ios swift swift-protocols swift3

我已经阅读了Apple的Swift iBook(类型转换和协议)的相关部分,但我似乎找到了一种方法来指定对象是符合特定协议的特定类的实例.

作为一个例子tableView(_: , cellForRowAt: )我希望将由返回的单元格转换tableView.dequeueReusableCell(withIdentifier: reuseID, for: indexPath)UITableViewCell符合RLMEntityCapableCell协议的子类(只是指定构造item函数有一个变量,称为该实例Object,或其子类之一).

这条路线有效,但双重铸造似乎过度:

protocol RLMEntityCapableCell: class  {
     var item: Object { get set }
}

 public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCell(withIdentifier: reuseID, for: indexPath) as! RLMEntityCapableCell // Cast here so we can set item
    cell.item = items[indexPath.row]
    return cell as! UITableViewCell // Cast again so the return type is right…
}
Run Code Online (Sandbox Code Playgroud)

另一种方法:

var cell = tableView.dequeueReusableCell(withIdentifier: reuseID, for: indexPath) 
           as! RLMEntityCapableCell, UITableViewCell
Run Code Online (Sandbox Code Playgroud)

给出了这个错误:

模式中缺少类型注释

所以显然也不是正确的方法.

我宁愿指定,为了符合的对象具有从任一继承协议UITableViewCellUICollectionViewCell而是一个协议的基础只能被限制在类类型并没有进一步.

编辑:

这里的想法是有境界的对象,充分利用仿制药很像一个通用数据源ArrayDictionary做.每个表视图中使用的单元格将特定于要显示的实体,但数据源只知道该单元格将是UITableViewCell符合的子类RLMEntityCapableCell.所有数据源需要担心的是告诉单元格Object需要显示哪个实例(它总是一个子类),单元格将从那里获取它并根据需要进行自我配置.

Pau*_*tos 6

不,这是不可能的……然而

下一个 Swift 版本(版本 4)可能会带来您正在寻找的东西,一个名为Class and Subtype Existentials的新功能:

该提案通过允许 Swift 表示符合协议的类和子类型的存在,为类型系统带来了更多的表达能力。

该提案保留了现有的&语法,但允许元素之一AnyObject是类类型(例如,SomeClass & SomeProtocol)。

然后你可以说:

var cell = tableView.dequeueReusableCell(withIdentifier: reuseID, for: indexPath) 
           as! UITableViewCell & RLMEntityCapableCell
Run Code Online (Sandbox Code Playgroud)

但是,当然,您将无法使用它向您的协议添加超类要求RLMEntityCapableCell(正如您最初希望的那样)。我们可能需要等待 Swift 5 :)


使用上述Class 和 Subtype Existentials (Swift 4) 功能的其他一些示例:

protocol P {}
struct S {}
class C {}
class D : P {}
class E : C, P {}

let u: S & P // Compiler error: S is not of class type
let v: C & P = D() // Compiler error: D is not a subtype of C
let w: C & P = E() // Compiles successfully
Run Code Online (Sandbox Code Playgroud)

和:

protocol P {}
class C {}
class D : C { }
class E : C { }
class F : D, P { }

let t: C & D & P = F() // Okay: F is a subclass of D and conforms to P
let u: D & P = t       // Okay: D & P is equivalent to C & D & P
let v: C & D & P = u   // Okay: C & D & P is equivalent to D & P
let w: D & E & P       // Compiler error: D is not a subclass of E or vice-versa
Run Code Online (Sandbox Code Playgroud)