ios 如何在 Swift 协议中定义可选方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24032754/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:22:59  来源:igfitidea点击:

How to define optional methods in Swift protocol?

iosswiftswift-protocolsswift-extensions

提问by Selvin

Is it possible in Swift? If not then is there a workaround to do it?

在 Swift 中可以吗?如果没有,那么是否有解决方法来做到这一点?

回答by akashivskyy

1. Using default implementations (preferred).

1. 使用默认实现(首选)。

protocol MyProtocol {
    func doSomething()
}

extension MyProtocol {
    func doSomething() {
        /* return a default value or just leave empty */
    }
}

struct MyStruct: MyProtocol {
    /* no compile error */
}

Advantages

好处

  • No Objective-C runtime is involved(well, no explicitly at least). This means you can conform structs, enums and non-NSObjectclasses to it. Also, this means you can take advantage of powerful generics system.

  • You can always be sure that all requirements are metwhen encountering types that conform to such protocol. It's always either concrete implementation or default one. This is how "interfaces" or "contracts" behave in other languages.

  • 不涉及 Objective-C 运行时(好吧,至少没有明确的)。这意味着您可以使结构、枚举和非NSObject类符合它。此外,这意味着您可以利用强大的泛型系统。

  • 当遇到符合此类协议的类型时,您始终可以确保满足所有要求。它始终是具体实现或默认实现。这就是“接口”或“合同”在其他语言中的行为方式。

Disadvantages

缺点

  • For non-Voidrequirements, you need to have a reasonable default value, which is not always possible. However, when you encounter this problem, it means that either such requirement should really have no default implementation, or that your you made a mistake during API design.

  • You can't distinguish between a default implementation and no implementation at all, at least without addressing that problem with special return values. Consider the following example:

    protocol SomeParserDelegate {
        func validate(value: Any) -> Bool
    }
    

    If you provide a default implementation which just returns true— it's fine at the first glance. Now, consider the following pseudo code:

    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 */
            }
        }
    }
    

    There's no way to implement such an optimization — you can't know if your delegate implements a method or not.

    Although there's a number of different ways to overcome this problem (using optional closures, different delegate objects for different operations to name a few), that example presents the problem clearly.

  • 对于非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 */
            }
        }
    }
    

    没有办法实现这样的优化——你无法知道你的委托是否实现了一个方法。

    尽管有许多不同的方法可以解决这个问题(使用可选闭包,不同操作的不同委托对象等等),但该示例清楚地展示了这个问题。



2. Using @objc optional.

2. 使用@objc optional

@objc protocol MyProtocol {
    @objc optional func doSomething()
}

class MyClass: NSObject, MyProtocol {
    /* no compile error */
}

Advantages

好处

  • No default implementation is needed.You just declare an optional method or a variable and you're ready to go.
  • 不需要默认实现。您只需声明一个可选方法或变量,就可以开始使用了。

Disadvantages

缺点

  • It severely limits your protocol's capabilitiesby requiring all conforming types to be Objective-C compatible. This means, only classes that inherit from NSObjectcan conform to such protocol. No structs, no enums, no associated types.

  • You must always check if an optional method is implementedby either optionally calling or checking if the conforming type implements it. This might introduce a lot of boilerplate if you're calling optional methods often.

  • 要求所有符合标准的类型都与 Objective-C 兼容,从而严重限制了您的协议​​的功能。这意味着,只有继承自的类NSObject才能符合这样的协议。没有结构,没有枚举,没有关联的类型。

  • 您必须始终检查可选方法是否通过可选调用或检查符合类型是否实现它来实现。如果您经常调用可选方法,这可能会引入很多样板文件。

回答by Antoine

In Swift 2 and onwards it's possible to add default implementations of a protocol. This creates a new way of optional methods in protocols.

在 Swift 2 及以后的版本中,可以添加协议的默认实现。这在协议中创建了一种新的可选方法。

protocol MyProtocol {
    func doSomethingNonOptionalMethod()
    func doSomethingOptionalMethod()
}

extension MyProtocol {
    func doSomethingOptionalMethod(){ 
        // leaving this empty 
    }
}

It's not a really nice way in creating optional protocol methods, but gives you the possibility to use structs in in protocol callbacks.

这不是创建可选协议方法的好方法,但让您可以在协议回调中使用结构体。

I wrote a small summary here: https://www.avanderlee.com/swift-2-0/optional-protocol-methods/

我在这里写了一个小总结:https: //www.avanderlee.com/swift-2-0/optional-protocol-methods/

回答by Eddie.Dou

Since there are some answers about how to use optional modifierand @objc attributeto define optional requirement protocol, I will give a sample about how to use protocol extensions define optional protocol.

由于有一些关于如何使用可选修饰符@objc 属性来定义可选需求协议的答案,我将给出一个关于如何使用协议扩展定义可选协议的示例。

Below code is Swift 3.*.

下面的代码是 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*

Please notice protocol extension methods can't invoked by Objective-C code, and worse is Swift team won't fix it. https://bugs.swift.org/browse/SR-492

请注意,Objective-C 代码无法调用协议扩展方法,更糟糕的是 Swift 团队不会修复它。https://bugs.swift.org/browse/SR-492

回答by Raphael

Here is a concrete example with the delegation pattern.

这是一个具有委托模式的具体示例。

Setup your Protocol:

设置您的协议:

@objc protocol MyProtocol:class
{
    func requiredMethod()
    optional func optionalMethod()
}

class MyClass: NSObject
{
    weak var delegate:MyProtocol?

    func callDelegate()
    {
        delegate?.requiredMethod()
        delegate?.optionalMethod?()
    }
}

Set the delegate to a class and implement the Protocol. See that the optional method does not need to be implemented.

将委托设置为一个类并实现协议。看到可选方法不需要实现。

class AnotherClass: NSObject, MyProtocol
{
    init()
    {
        super.init()

        let myInstance = MyClass()
        myInstance.delegate = self
    }

    func requiredMethod()
    {
    }
}

One important thing is that the optional method is optional and needs a "?" when calling. Mention the second question mark.

一件重要的事情是可选方法是可选的并且需要一个“?” 打电话的时候。提到第二个问号。

delegate?.optionalMethod?()

回答by Zag

The other answers here involving marking the protocol as "@objc" do not work when using swift-specific types.

此处涉及将协议标记为“@objc”的其他答案在使用 swift 特定类型时不起作用。

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"

In order to declare optional protocols that work well with swift, declare the functions as variables instead of func's.

为了声明与 swift 配合良好的可选协议,将函数声明为变量而不是 func。

protocol Health {
    var isInfoHealthy: (Info) -> (Bool)? { get set }
}

And then implement the protocol as follows

然后按如下方式实现协议

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)?
}

You can then use "?" to check whether or not the function has been implemented

然后您可以使用“?” 检查该功能是否已实现

func returnEntity() -> Health {
    return Human()
}

var anEntity: Health = returnEntity()

var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))? 
//"isHealthy" is true

回答by Gautam Sareriya

In Swift 3.0

Swift 3.0 中

@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}

It will save your time.

它会节省你的时间。

回答by Mehul Parmar

  • You need to add optionalkeyword prior to each method.
  • Please note, however, that for this to work, your protocol must be marked with the @objc attribute.
  • This further implies that this protocol would be applicable to classes but not structures.
  • 您需要optional在每个方法之前添加关键字。
  • 但是请注意,要使其工作,您的协议必须用@objc 属性标记。
  • 这进一步暗示该协议适用于类而不适用于结构。

回答by guenis

A pure Swift approach with protocol inheritance:

带有协议继承的纯 Swift 方法:

//Required methods
protocol MyProtocol {
    func foo()
}

//Optional methods
protocol MyExtendedProtocol: MyProtocol {
    func bar()
}

class MyClass {
    var delegate: MyProtocol
    func myMethod() {
        (delegate as? MyExtendedProtocol).bar()
    }
}

回答by eLillie

To illustrate the mechanics of Antoine's answer:

为了说明 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"

回答by emem

I think that before asking howyou can implement an optional protocol method, you should be asking whyyou should implement one.

我认为在询问如何实现可选协议方法之前,您应该先问为什么要实现一个。

If we think of swift protocols as an Interfacein classic object oriented programming, optional methods do not make much sense, and perhaps a better solution would be to create default implementation, or separate the protocol into a set of protocols (perhaps with some inheritance relations between them) to represent the possible combination of methods in the protocol.

如果我们把 swift 协议看作是经典的面向对象编程中的一个接口,可选的方法没有多大意义,也许更好的解决方案是创建默认实现,或者将协议分成一组协议(也许有一些继承关系)它们之间)来表示协议中方法的可能组合。

For further reading, see https://useyourloaf.com/blog/swift-optional-protocol-methods/, which gives an excellent overview on this matter.

如需进一步阅读,请参阅https://useyourloaf.com/blog/swift-optional-protocol-methods/,其中提供了有关此问题的出色概述。