在 Swift 中使用 Comparable 扩展 @objc 协议

Extend @objc protocol with Comparable in Swift

我正在尝试使用 Comparable 扩展我的协议 Option 以使用简单的 .sort() 方法。

下面的简短示例仅使用 Equatable 来显示错误。

@objc protocol Option: Equatable {
    var title: String { get }
    var enabled: Bool { get }
    var position: Int { get }
}

func ==(lhs: Option, rhs: Option) -> Bool {
    return lhs.position == rhs.position
}

Option 协议必须标记为 @objc 或从 NSObjectProtocol 继承,因为它将与 UIKit.

一起使用

错误:

  1. @objc protocol 'Option' cannot refine non-@objc protocol 'Equatable'

  2. Protocol 'Option' can only be used as a generic constraint because it has Self or associated type requirements

你对如何解决这个问题有什么建议吗?

Equatable 仅存在于 Swift 世界中,因此您不能将其扩展到 Objective-C 将使用的协议。尝试这样做会导致错误 #1

具有 Self 要求的协议(即协议声明中至少有一个方法包含 Self)不能用作函数或变量声明的参数,只能用作通用条款,例如func doSomething<T: Option>(argument: T).

Option 协议声明中删除 Equatable,并在 Option 上将 == 声明为通用将解决编译错误。至于排序,您还可以重载 < 运算符,并通过该运算符进行排序(无需实现 Comparable):

@objc protocol Option {
    var title: String { get }
    var enabled: Bool { get }
    var position: Int { get }
}

func ==<T: Option>(lhs: T, rhs: T) -> Bool {
    return lhs.position == rhs.position
}

func <<T: Option>(lhs: T, rhs: T) -> Bool {
    return lhs.position < rhs.position
}

这允许您将符合协议的对象传递给 UIKit,并在您的 swift 代码中比较它们。

class A: NSObject, Option { .. }
class B: NSObject, Option { ... }

let a = A()
let b = B()
a == b  // compiles, and returns true if a and b have the same position
let c: [Option] = [a, b]
c.sort(<) // returns a sorted array by the `position` field

关于上述排序代码的一个重要注意事项:如果您没有为 c 指定类型,则编译器将其类型推断为 [NSObject],并且 sort 调用由于 < 运算符的歧义,将无法编译。您需要将 c 显式声明为 [Option] 以利用重载运算符。

此问题可以通过 swift 2.0

中引入的新的面向协议的编程功能来解决

@objc protocol 'Option' cannot refine non-@objc protocol 'Equatable'

如错误所述,Equatable 协议是一个 swift 协议,您不能将其用于 Obj C 上下文

Protocol 'Option' can only be used as a generic constraint because it has Self or associated type requirements

您可以通过以下方式实现:

@objc protocol Option {
    var title: String { get }
    var enabled: Bool { get }
    var position: Int { get }
}

extension Equatable where Self : Option
{

}

extension Comparable where Self : Option
{

}

func ==(lhs: Option, rhs: Option) -> Bool
{
    return lhs.position == rhs.position
}

func <(lhs: Option, rhs: Option) -> Bool
{
    return lhs.position < rhs.position
}

func >(lhs: Option, rhs: Option) -> Bool
{
    return lhs.position > rhs.position
}

你的 class 和实现看起来像:

class MyClass: Option
{
    @objc var title: String = ""
    @objc var enabled: Bool = true
    @objc var position: Int = 0

    init()
    {
    }

    convenience init(title : String, enabled : Bool, position: Int)
    {
        self.init()
        self.title    = title
        self.enabled  = enabled
        self.position = position
    }
}

let firstObj               = MyClass()
let secondObj              = MyClass()
let optionArray : [Option] = [firstObj, secondObj]

// Sort array of options
optionArray.sort(<)