Answers:
protocol MyProtocol {
func doSomething()
}
extension MyProtocol {
func doSomething() {
/* return a default value or just leave empty */
}
}
struct MyStruct: MyProtocol {
/* no compile error */
}
优点
不涉及Objective-C运行时(至少没有明确地涉及)。这意味着您可以NSObject
使其符合结构,枚举和非类。同样,这意味着您可以利用强大的泛型系统。
当遇到符合此类协议的类型时,您始终可以确保满足所有要求。它始终是具体实现或默认实现。这就是“接口”或“合同”在其他语言中的行为方式。
缺点
对于非Void
要求,您需要具有一个合理的默认值,这并非总是可能的。但是,当您遇到此问题时,这意味着该要求实际上应该没有默认实现,或者您在API设计期间犯了一个错误。
您无法区分默认实现和根本没有实现,至少没有用特殊的返回值解决该问题。考虑以下示例:
protocol SomeParserDelegate {
func validate(value: Any) -> Bool
}
如果您提供的默认实现只是返回 true
-乍一看就可以了。现在,考虑以下伪代码:
final class SomeParser {
func parse(data: Data) -> [Any] {
if /* delegate.validate(value:) is not implemented */ {
/* parse very fast without validating */
} else {
/* parse and validate every value */
}
}
}
无法实现这种优化-您不知道您的委托是否实现了一种方法。
尽管有多种方法可以解决此问题(使用可选的闭包,用于不同操作的不同委托对象等),但该示例清楚地提出了问题。
@objc optional
。@objc protocol MyProtocol {
@objc optional func doSomething()
}
class MyClass: NSObject, MyProtocol {
/* no compile error */
}
优点
缺点
它要求所有符合类型都必须与Objective-C兼容,从而严重限制了协议的功能。这意味着,仅继承自NSObject
该类的类才能符合此类协议。没有结构,没有枚举,没有关联的类型。
您必须始终通过可选调用或检查符合类型是否实现了可选方法来检查是否实现了可选方法。如果您经常调用可选方法,这可能会引入很多样板。
respondsToSelector
?
optional func doSomething(param: Int?)
在Swift 2及更高版本中,可以添加协议的默认实现。这在协议中创建了一种新的可选方法。
protocol MyProtocol {
func doSomethingNonOptionalMethod()
func doSomethingOptionalMethod()
}
extension MyProtocol {
func doSomethingOptionalMethod(){
// leaving this empty
}
}
这不是创建可选协议方法的真正好方法,但是使您可以在协议回调中使用结构。
我在这里写了一个小总结:https : //www.avanderlee.com/swift-2-0/optional-protocol-methods/
由于有一些关于如何使用的答案 可选修饰符和@objc属性定义可选需求协议的,因此我将给出一个有关如何使用协议扩展定义可选协议的示例。
下面的代码是Swift 3. *。
/// Protocol has empty default implementation of the following methods making them optional to implement:
/// `cancel()`
protocol Cancelable {
/// default implementation is empty.
func cancel()
}
extension Cancelable {
func cancel() {}
}
class Plane: Cancelable {
//Since cancel() have default implementation, that is optional to class Plane
}
let plane = Plane()
plane.cancel()
// Print out *United Airlines can't cancelable*
请注意,Objective-C代码无法调用协议扩展方法,更糟糕的是Swift团队不会对其进行修复。https://bugs.swift.org/browse/SR-492
使用Swift特定类型时,此处涉及将协议标记为“ @objc”的其他答案不起作用。
struct Info {
var height: Int
var weight: Int
}
@objc protocol Health {
func isInfoHealthy(info: Info) -> Bool
}
//Error "Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C"
为了声明与swift一起使用的可选协议,请将函数声明为变量而不是func。
protocol Health {
var isInfoHealthy: (Info) -> (Bool)? { get set }
}
然后实现协议如下
class Human: Health {
var isInfoHealthy: (Info) -> (Bool)? = { info in
if info.weight < 200 && info.height > 72 {
return true
}
return false
}
//Or leave out the implementation and declare it as:
//var isInfoHealthy: (Info) -> (Bool)?
}
然后可以使用“?” 检查功能是否已实现
func returnEntity() -> Health {
return Human()
}
var anEntity: Health = returnEntity()
var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))?
//"isHealthy" is true
这是委派模式的具体示例。
设置协议:
@objc protocol MyProtocol:class
{
func requiredMethod()
optional func optionalMethod()
}
class MyClass: NSObject
{
weak var delegate:MyProtocol?
func callDelegate()
{
delegate?.requiredMethod()
delegate?.optionalMethod?()
}
}
将委托设置为一个类并实现协议。看到不需要实现可选方法。
class AnotherClass: NSObject, MyProtocol
{
init()
{
super.init()
let myInstance = MyClass()
myInstance.delegate = self
}
func requiredMethod()
{
}
}
重要的一点是,可选方法是可选的,并且需要一个“?” 打电话时。提及第二个问号。
delegate?.optionalMethod?()
在Swift 3.0中
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
这样可以节省您的时间。
@objc
现在为什么所有成员都需要提供任何来源的信息?
required
标志的方法,但有错误:required
只能在'init'声明中使用。
optional
在每种方法之前添加关键字。@objc
,而不仅仅是协议。
为了说明Antoine回答的机理:
protocol SomeProtocol {
func aMethod()
}
extension SomeProtocol {
func aMethod() {
print("extensionImplementation")
}
}
class protocolImplementingObject: SomeProtocol {
}
class protocolImplementingMethodOverridingObject: SomeProtocol {
func aMethod() {
print("classImplementation")
}
}
let noOverride = protocolImplementingObject()
let override = protocolImplementingMethodOverridingObject()
noOverride.aMethod() //prints "extensionImplementation"
override.aMethod() //prints "classImplementation"
我认为在询问如何实现可选协议方法之前,您应该问为什么要实现一种可选协议。
如果我们将快速协议视为接口经典的面向对象编程中,那么可选方法就没有多大意义,也许更好的解决方案是创建默认实现或将协议分为一组协议(也许具有某些继承关系)它们之间)代表协议中方法的可能组合。
有关更多信息,请参见https://useyourloaf.com/blog/swift-optional-protocol-methods/,其中对此进行了很好的概述。
最初的问题与主题略有出入,但它建立在Antoine的想法基础上,我认为这可能会对某人有所帮助。
您还可以将计算属性对于带有协议扩展的结构是可选的。
您可以将协议的属性设为可选
protocol SomeProtocol {
var required: String { get }
var optional: String? { get }
}
在协议扩展中实现虚拟计算属性
extension SomeProtocol {
var optional: String? { return nil }
}
现在,您可以使用具有或没有实现可选属性的结构
struct ConformsWithoutOptional {
let required: String
}
struct ConformsWithOptional {
let required: String
let optional: String?
}
如何创建可选的和必需的委托方法。
@objc protocol InterViewDelegate:class {
@objc optional func optfunc() // This is optional
func requiredfunc()// This is required
}
这是一个非常简单的示例,仅用于快速类,而不用于结构或枚举。请注意,协议方法是可选的,有两个级别的可选链接在起作用。同样,采用该协议的类在其声明中也需要@objc属性。
@objc protocol CollectionOfDataDelegate{
optional func indexDidChange(index: Int)
}
@objc class RootView: CollectionOfDataDelegate{
var data = CollectionOfData()
init(){
data.delegate = self
data.indexIsNow()
}
func indexDidChange(index: Int) {
println("The index is currently: \(index)")
}
}
class CollectionOfData{
var index : Int?
weak var delegate : CollectionOfDataDelegate?
func indexIsNow(){
index = 23
delegate?.indexDidChange?(index!)
}
}
delegate?.indexDidChange?(index!)
?
protocol CollectionOfDataDelegate{ func indexDidChange(index: Int) }
那么您将在不带问号的情况下调用它: delegate?.indexDidChange(index!)
在协议中为方法设置可选要求时,将遵循该协议的Type可能不会实现该方法,因此?
使用来检查实现,如果没有,程序将不会崩溃。@Unheilig
weak var delegate : CollectionOfDataDelegate?
(确保参考力弱吗?)
delegate?
用法中添加用法说明吗?该信息将来确实应该属于其他人。我想对此表示赞同,但实际上应该是答案。
如果您想快速完成此操作,最好的方法是在返回Swift类型(例如带有Swift类型的struct)时提供默认的实现特殊信息
例如:
struct magicDatas {
var damagePoints : Int?
var manaPoints : Int?
}
protocol magicCastDelegate {
func castFire() -> magicDatas
func castIce() -> magicDatas
}
extension magicCastDelegate {
func castFire() -> magicDatas {
return magicDatas()
}
func castIce() -> magicDatas {
return magicDatas()
}
}
那么您可以实现协议而无需定义每个函数
您可以通过两种方法在swift协议中创建可选方法。
1-第一种选择是使用@objc属性标记您的协议。虽然这意味着只能由类采用,但这确实意味着您将各个方法标记为可选,如下所示:
@objc protocol MyProtocol {
@objc optional func optionalMethod()
}
2-更快的方法:此选项更好。编写不执行任何操作的可选方法的默认实现,如下所示。
protocol MyProtocol {
func optionalMethod()
func notOptionalMethod()
}
extension MyProtocol {
func optionalMethod() {
//this is a empty implementation to allow this method to be optional
}
}
Swift具有一个称为扩展的功能,该功能使我们能够为那些我们希望是可选的方法提供默认实现。
一种选择是将它们存储为可选函数变量:
struct MyAwesomeStruct {
var myWonderfulFunction : Optional<(Int) -> Int> = nil
}
let squareCalculator =
MyAwesomeStruct(myWonderfulFunction: { input in return input * input })
let thisShouldBeFour = squareCalculator.myWonderfulFunction!(2)
要Optional
Protocol
快速定义,您应在该协议内的声明@objc
之前Protocol
和attribute
/ method
声明之前使用关键字。下面是协议的可选属性的示例。
@objc protocol Protocol {
@objc optional var name:String?
}
class MyClass: Protocol {
// No error
}
将@optional
方法或属性放在前面。
@optional
甚至都不是正确的关键字。它是optional
,您必须使用属性声明类和协议@objc
。