为了账号安全,请及时绑定邮箱和手机立即绑定

在Swift中,如何声明符合一个或多个协议的特定类型的变量?

在Swift中,如何声明符合一个或多个协议的特定类型的变量?

12345678_0001 2019-10-09 14:54:51
在Swift中,我可以通过声明如下来显式设置变量的类型:var object: TYPE_NAME如果我们想更进一步,并声明一个符合多种协议的变量,可以使用protocol声明式:var object: protocol<ProtocolOne,ProtocolTwo>//etc如果我想声明一个符合一个或多个协议并且也是特定基类类型的对象,该怎么办?相当于Objective-C的样子如下:NSSomething<ABCProtocolOne,ABCProtocolTwo> * object = ...;在Swift中,我希望它看起来像这样:var object: TYPE_NAME,ProtocolOne//etc这使我们能够灵活处理基本类型的实现以及协议中定义的添加接口。还有其他更明显的方式可能会让我丢失吗?例例如,假设我有一家UITableViewCell工厂负责返回符合协议的单元。我们可以轻松地设置一个泛型函数来返回符合协议的单元格:class CellFactory {    class func createCellForItem<T: UITableViewCell where T:MyProtocol >(item: SpecialItem,tableView: UITableView) -> T {        //etc    }}稍后我想在利用类型和协议的同时使这些单元出队var cell: MyProtocol = CellFactory.createCellForItem(somethingAtIndexPath) as UITableViewCell由于表视图单元格不符合协议,因此返回错误。我想能够指定单元格是a UITableViewCell并符合MyProtocol变量声明中的?理由如果您熟悉工厂模式,那么在能够返回实现特定接口的特定类的对象的背景下,这将是有意义的。就像在我的示例中一样,有时我们希望定义在应用于特定对象时有意义的接口。我关于表格视图单元格的示例就是这样一种证明。尽管提供的类型与所提到的接口不完全一致,但是工厂返回的对象却与之一致,因此我希望在与基类类型和声明的协议接口交互时具有灵活性
查看完整描述

3 回答

?
元芳怎么了

TA贡献1798条经验 获得超7个赞

在Swift 4中,现在可以声明一个变量,该变量是类型的子类,并且可以同时实现一个或多个协议。


var myVariable: MyClass & MyProtocol & MySecondProtocol

或作为方法的参数:


func shakeEm(controls: [UIControl & Shakeable]) {}

苹果在WWDC 2017 大会402上宣布了这一点:Swift的新增功能


第二,我想谈谈组成类和协议。因此,在这里,我为UI元素引入了这种可晃动的协议,该协议可以给人一点震动效果,从而引起人们的注意。而且,我继续并扩展了一些UIKit类,以实际提供此震动功能。现在,我想写一些看起来很简单的东西。我只想编写一个函数,该函数需要一堆可摇晃的控件,并摇晃那些能够引起人们注意的控件。我可以在此数组中写什么类型?这实际上是令人沮丧和棘手的。因此,我可以尝试使用UI控件。但并非所有UI控件在此游戏中都是可摇晃的。我可以尝试使用shakable,但并非所有的shakable都是UI控件。实际上,在Swift 3中没有很好的方式来表示这一点。Swift 4引入了用任何数量的协议组成一个类的概念。


查看完整回答
反对 回复 2019-10-09
?
喵喵时光机

TA贡献1846条经验 获得超7个赞

你不能像这样声明变量


var object:Base,protocol<ProtocolOne,ProtocolTwo> = ...

也不要像这样声明函数返回类型


func someFunc() -> Base,protocol<MyProtocol,Protocol2> { ... }

您可以像这样声明为函数参数,但基本上是向上转换。


func someFunc<T:Base where T:protocol<MyProtocol1,MyProtocol2>>(val:T) {

    // here, `val` is guaranteed to be `Base` and conforms `MyProtocol` and `MyProtocol2`

}


class SubClass:BaseClass, MyProtocol1, MyProtocol2 {

   //...

}


let val = SubClass()

someFunc(val)

到目前为止,您所能做的就像:


class CellFactory {

    class func createCellForItem(item: SpecialItem) -> UITableViewCell {

        return ... // any UITableViewCell subclass

    }

}


let cell = CellFactory.createCellForItem(special)

if let asProtocol = cell as? protocol<MyProtocol1,MyProtocol2> {

    asProtocol.protocolMethod()

    cell.cellMethod()

}

这样,在技术上cell就等同于asProtocol。


但是,对于编译器来说,cell只有接口UITableViewCell,而asProtocol只有协议接口。因此,当您要调用UITableViewCell的方法时,必须使用cell变量。当您要调用协议方法时,请使用asProtocol变量。


如果您确定单元格符合协议,则不必使用if let ... as? ... {}。喜欢:


let cell = CellFactory.createCellForItem(special)

let asProtocol = cell as protocol<MyProtocol1,MyProtocol2>


查看完整回答
反对 回复 2019-10-09
  • 3 回答
  • 0 关注
  • 1069 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信