首页 \ 问答 \ 在Swift中,如何声明一个符合一个或多个协议的特定类型的变量?(In Swift, how can I declare a variable of a specific type that conforms to one or more protocols?)

在Swift中,如何声明一个符合一个或多个协议的特定类型的变量?(In Swift, how can I declare a variable of a specific type that conforms to one or more protocols?)

在Swift中,我可以通过如下声明来显式设置变量的类型:

var object: TYPE_NAME

如果我们想要进一步说明一个符合多个协议的变量,我们可以使用protocol声明:

var object: protocol<ProtocolOne,ProtocolTwo>//etc

如果我想声明符合一个或多个协议的对象,并且还具有特定的基类类型? Objective-C等效物将如下所示:

NSSomething<ABCProtocolOne,ABCProtocolTwo> * object = ...;

在斯威夫特,我希望它看起来像这样:

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

这会返回一个错误,因为表视图单元格不符合协议...

我想要指定该单元格是一个UITableViewCell并符合MyProtocol在变量声明中?

理由

如果您熟悉工厂模式 ,则在能够返回实现特定接口的特定类的对象的上下文中,这是有意义的。

就像我的例子一样,有时我们喜欢定义在应用于特定对象时有意义的接口。 我的示例视图单元格是一个这样的理由。

虽然提供的类型不完全符合上述接口,但是工厂返回的对象也是如此,因此我希望与基类类型和声明的协议接口进行交互的灵活性


In Swift I can explicitly set the type of a variable by declaring it as follows:

var object: TYPE_NAME

If we want to take it a step further and declare a variable that conforms to multiple protocols we can use the protocol declarative:

var object: protocol<ProtocolOne,ProtocolTwo>//etc

What if I would like to declare an object that conforms to one or more protocols and is also of a specific base class type? The Objective-C equivalent would look like this:

NSSomething<ABCProtocolOne,ABCProtocolTwo> * object = ...;

In Swift I would expect it to look like this:

var object: TYPE_NAME,ProtocolOne//etc

This gives us the flexibility of being able to deal with the implementation of the base type as well as the added interface defined in the protocol.

Is there another more obvious way that I might be missing?

Example

As an example, say I have a UITableViewCell factory that is responsible for returning cells conforming to a protocol. We can easily setup a generic function that returns cells conforming to a protocol:

class CellFactory {
    class func createCellForItem<T: UITableViewCell where T:MyProtocol >(item: SpecialItem,tableView: UITableView) -> T {
        //etc
    }
}

later on I want to dequeue these cells whilst leveraging both the type and the protocol

var cell: MyProtocol = CellFactory.createCellForItem(somethingAtIndexPath) as UITableViewCell

This returns an error because a table view cell does not conform to the protocol...

I would like to be able to specify that cell is a UITableViewCell and conforms to the MyProtocol in the variable declaration?

Justification

If you are familiar with the Factory Pattern this would make sense in the context of being able to return objects of a particular class that implement a certain interface.

Just like in my example, sometimes we like to define interfaces that make sense when applied to a particular object. My example of the table view cell is one such justification.

Whilst the supplied type does not exactly conform to the mentioned interface, the object the factory returns does and so I would like the flexibility in interacting with both the base class type and the declared protocol interface


原文:https://stackoverflow.com/questions/26401778
更新时间:2019-07-05 04:25

最满意答案

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

var myVariable: MyClass & MyProtocol & MySecondProtocol

或作为方法的参数:

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

苹果在WWDC 2017年在第402期宣布了这一点:斯威夫特的新功能

第二,我想谈论组合类和协议。 所以,这里我介绍了一个UI元素的可抖动协议,可以给出一点点的震动效果来引起人们的注意。 而且我已经开始扩展了一些UIKit类来实际提供这个摇动功能。 现在我想写一些看似简单的东西。 我只是想编写一个功能,它需要一堆可以摇动的控件,并且可以摇动那些能够引起注意力的控件。 我可以在这个数组中写什么类型的 这实际上是令人沮丧和棘手的。 所以,我可以尝试使用UI控件。 但是并不是所有的UI控件在这个游戏中都是可以摇摆的。 我可以尝试抖动,但并不是所有的摇晃是UI控件。 实际上没有什么好的方法可以在Swift 3中进行表示。Swift 4引入了使用任意数量协议组合类的概念。


In Swift 4 it is now possible to declare a variable that is a subclass of a type and implements one or more protocols at the same time.

var myVariable: MyClass & MyProtocol & MySecondProtocol

or as the parameter of a method:

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

Apple announced this at WWDC 2017 in Session 402: Whats new in Swift

Second, I want to talk about composing classes and protocols. So, here I've introduced this shakable protocol for a UI element that can give a little shake effect to draw attention to itself. And I've gone ahead and extended some of the UIKit classes to actually provide this shake functionality. And now I want to write something that seems simple. I just want to write a function that takes a bunch of controls that are shakable and shakes the ones that are enabled to draw attention to them. What type can I write here in this array? It's actually frustrating and tricky. So, I could try to use a UI control. But not all UI controls are shakable in this game. I could try shakable, but not all shakables are UI controls. And there's actually no good way to represent this in Swift 3. Swift 4 introduces the notion of composing a class with any number of protocols.

2017-07-24

相关问答

更多

声明作为子类的元类型,并符合Swift 4中的协议(Declare metatype that is a subclass and conforms to a protocol in Swift 4)

要声明一个类型是一个子类并且符合Swift 4中的协议,你可以使用下面的语法: var classForCell: (UICollectionViewCell & AdditionalHeightable).Type To declare a type that is a subclass and conforms to a protocol in Swift 4 you can use this syntax: var classForCell: (UICollectionViewCell & ...

在swift中,如何返回符合协议的相同类型的对象(In swift, how do I return an object of the same type that conforms to a protocol)

自动完成功能对您有所帮助,但基本上,如果Foo是一个类,您只需要一个与协议中方法的确切签名相匹配的方法: class Foo {} protocol JSONInitializable { static func initialize(fromJSON: [String : AnyObject]) throws -> Self? } extension Foo: JSONInitializable { static func initialize(fromJSON: [Stri ...

协议的Swift扩展存储(Swift extension storage for protocols)

任何协议对象都可以转换为类型擦除类。 构建一个AnySomeProtocol并存储它。 private var sourceKey: UInt8 = 0 final class AnySomeProtocol: SomeProtocol { func getData() -> String { return _getData() } init(_ someProtocol: SomeProtocol) { _getData = someProtocol.getData } ...

在Swift中声明和使用位域枚举(Declaring and using a bit field enum in Swift)

您可以构建一个符合RawOptionSet协议的结构,并且您可以像使用内置enum类型一样使用它,但也可以使用它。 这里的答案显示了: Swift NS_OPTIONS风格的位掩码枚举 。 You can build a struct that conforms to the RawOptionSet protocol, and you'll be able to use it like the built-in enum type but with bitmask functionality a ...

如何动态地将其转换为在Swift 2.0中以字符串命名的Type?(How is it possible to dynamically cast to a Type that is named in a string with Swift 2.0?)

你不能这样做,因为斯威夫特(故意)错过了两个谜题: 你不能把一个字符串变成一个类。 更重要的是,你不能将其转换为表达为变量的类。 要抛弃的类必须是一个文字类,即它必须在编译时知道。 编译器需要知道这个转换是合法的,而且它在编译时需要知道如何处理这个变量。 如果您希望能够将MyCoolTableCell实例消息发送到此单元格,则需要在代码中使用文字MyCoolTableCell名称 - 不是字符串,也不是包含类型的变量,而是类型本身 。 You can't do it, because Swift ...

为什么建议在Swift协议中使用static作为属性需求的前缀?(Why is it recommended to prefix property requirements with static in Swift protocols?)

后来在文档中,静态并不总是存在 本节讨论类型要求 ,即要求符合类型具有特定名称和类型的static属性。 换句话说,当你写这个 protocol MyProtocol { static var myProperty: Int { get set } } 符合要求的班级必须这样做 class MyClass : MyProtocol { static var myProperty: Int }// ^^^^^^ 它还有一个选项: class MyClass : MyProtoco ...

如何比较两个协议数组在Swift中的相等性?(How to compare two arrays of protocols for equality in Swift?)

我有两个符合协议的对象数组,我想检查它们是否相等。 所以你想说如果它们中的所有元素都相等并且元素都符合模式,那么这两个数组是相等的。 即 如果a,b,c和d都是符合Pattern的所有东西,就是你想要的 a == c a != b a != d b != d let array1: [Pattern] = [a, b, c] let array2: [Pattern] = [a, b, a] let array3: [Pattern] = [a, d, c] array1 == array2 ...

Swift语法,并理解语言的某些部分(Swift syntax, and understanding certain parts of the language [closed])

好吧,因为你的问题没有被过多地关闭,而且因为它有赞成,我会试着至少给你一个我认为你真正要求的开始...... 在哪里找出这些东西意味着什么: 首先,对于Swift,您想要阅读Swift编程语言:快速浏览 。 这将为您提供一个非常好的初学者的语言概述以及如何使用它。 它包括一个可下载的Swift游乐场 ,其中包括整个游览,并允许您尝试并练习您正在学习的内容。 接下来,当您看到某些内容(例如URLRequest ,您可以在开发人员文档中查找它。 要获得此文档,您可以搜索名称和文本“开发人员文档”。 或 ...

相关文章

更多

最新问答

更多
  • Android宽度:100%修复(网站接管问题)(Android width:100% fix (website takeover issue))
  • C ++函数/方法设计的良好实践(Good practice in C++ function/method design)
  • 计算其他表中不存在的所有记录 - SQL查询(Count all records that does not exist to other table - SQL Query)
  • 为什么我要用JPA共享ID?(Why do I get shared Ids with JPA?)
  • asp.net - 如何显示来自html格式的数据行的字段(asp.net - how to display a field from data row that is in html format)
  • 我们如何使用ActiveRecord从连接表中删除行?(How can we delete rows from a join table by using ActiveRecord?)
  • ng-class搞乱了类的顺序(ng-class messing with the order of classes)
  • oracle 12g无效数字错误(oracle 12g invalid number error)
  • 更改ng-src值onclick(Change ng-src value onclick)
  • 如何在android中自动添加自定义依赖项以创建新项目?(How to add custom dependencies automatically in android for ever a new project is created?)
  • datetime函数在PHP中(datetime function in php)
  • 在javascript中获取会话数组的值(in javascript get the value of a session array)
  • 如何在UTF8中编译LaTeX?(How can I compile LaTeX in UTF8? [closed])
  • Rspec:“array.should == another_array”,但不用担心订单(Rspec: “array.should == another_array” but without concern for order)
  • Logcat错误:无法在android片段中加载视图(Logcat error: unable to load view in android fragments)
  • JavaFX的。(JavaFX. Adding items to the list in different threads is not working)
  • 从GDATA日历资源迁移到Google Calendar Resource api(Migrate from GDATA calendar resource to Google Calendar Resource api)
  • SSRS 2008 - 以零情景处理分割(SSRS 2008 - Dealing with division by zero scenarios)
  • 我如何以编程方式添加一个listView列标题的点击事件(How can I add a listView column header a click event programmatically)
  • Wxpython:无法检索有关列表控件项XXX的信息(Wxpython: Couldn't retrieve information about list control item XXX)
  • 使用Tortoise SVN在SVN存储库中移动目录(Move Directory across SVN repository using Tortoise SVN)
  • 天蓝色服务结构集群中的web api无状态服务是否在一段时间不活动后进入休眠状态?(Do web api stateless services in azure service fabric cluster go to sleep after a period of inactivity?)
  • 我可以设置intelliJ来突出显示PHP编码风格吗?(Can I set intelliJ to highlight php coding style?)
  • 用javafx创建一个Truetype字体文件(Creating a Truetype Font file with javafx)
  • Spring ftp配置错误(Spring ftp configuration is wrong)
  • 使用gsub去除多个字符(Using gsub to strip multiple characters)
  • 续订推送证书并保持当前的App Store App正常工作(Renew Push certificate and keep current App Store App working)
  • js:ES5和ES6之间关于'this'关键字用法的一个令人困惑的观点(js: one confusing point about 'this' keyword usage between ES5 and ES6)
  • window.onload vs $(document).ready()(window.onload vs $(document).ready())
  • 在Swift中,如何声明一个符合一个或多个协议的特定类型的变量?(In Swift, how can I declare a variable of a specific type that conforms to one or more protocols?)