在Swift中是否有可能实现?如果不能,是否有解决方法可以实现?
在Swift中是否有可能实现?如果不能,是否有解决方法可以实现?
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
的类可以符合这样的协议。没有结构体、枚举、关联类型。
你必须经常检查是否实现了可选方法,通过可选调用或检查符合类型是否实现它。如果经常调用可选方法,这可能会引入很多模板代码。
在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 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?()
由于有一些关于如何使用可选修饰符和@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*
当使用 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 Health: AnyObject {...
- tontonCD在 Swift 3.0 中
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
它会节省您的时间。
@objc
的原因是什么? - DevAndArtistrequired
标志,但是出现了错误:required
只能用于 'init' 声明。 - Benoptional
关键字。@objc
,而不仅仅是协议本身。 - Johnathon Sullinger你可以使用两种方法在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有一个叫做扩展(extension)的特性,它允许我们为那些想要成为可选方法的方法提供默认实现。
使用纯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()
}
}
为了说明安东尼的答案的原理:
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"