Swift 3: Is there a way to cast an object to a class and protocol at the same time?

假如想象 提交于 2019-12-01 16:12:22

No, this isn't possible... yet.

The next Swift release (version 4) might bring what you are looking for, a new feature called Class and Subtype Existentials:

This proposal brings more expressive power to the type system by allowing Swift to represent existentials of classes and subtypes which conform to protocols.

The proposal keeps the existing & syntax but allows one of the elements to be either AnyObject or of class type (e.g., SomeClass & SomeProtocol).

You could then say:

var cell = tableView.dequeueReusableCell(withIdentifier: reuseID, for: indexPath) 
           as! UITableViewCell & RLMEntityCapableCell

But, of course, you won't be able to use this to add a superclass requirement to your RLMEntityCapableCell protocol (as you initially wished). We may need to wait for Swift 5 for that :)


Some other examples using the above Class and Subtype Existentials (Swift 4) feature:

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

and:

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

UITableViewCell doesn't have an item property, so what you probably want to do is create a subclass of it that conforms to your protocol, and then cast cell as that.

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

class RLMCell: UITableViewCell, RLMEntityCapableCell {
    var item: Object
}

 public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCell(withIdentifier: reuseID, for: indexPath) as? RLMCell ?? RLMCell() 
    cell.item = items[indexPath.row]
    return cell
}

Notes:
1. dequeueReusableCell returns an optional and will almost certainly return nil in some cases, so don't force unwrap it.
2. You'll need to do at least one of the following: make item optional, provide a default value, or add an initializer function.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!