Extend @objc protocol with comparison in Swift
I am trying to extend the Option
protocol to Comparable
to use the simple .sort()
method.
Below is a short example with Equatable
only for displaying errors.
@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 }
The Option
protocol must be marked as @objc
or inherited from NSObjectProtocol
because it will be used with UIKit
.
Errors:
@Objc protocol 'Option' cannot specify non-@objc 'Equatable' protocol
The Variant protocol can only be used as a general restriction because it has its own or related requirements like
Do you have any suggestion to solve this problem?
Equatable
lives only in the Swift world, so you cannot extend it to the protocol that Objective-C will use. Attempting to do this results in error # 1
Protocols requiring Self
(i.e., at least one method from a protocol declaration contains Self
) cannot be used as arguments for functions or for variable declarations only as arguments in a general sentence, for example. func doSomething<T: Option>(argument: T)
.
Removing Equatable
from the Option
protocol declaration, and declaring ==
as common in Option
will eliminate compilation errors. As for sorting, you can also overload the <
operator and sort it through this operator (without having to execute 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 }
This allows you to transfer objects that comply with the protocol to UIKit
, as well as compare them in your fast code.
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
One important note about the sort code described above: if you do not specify a type for c
, then the compiler will display its type as [NSObject]
, and the sort
call will not compile due to the ambiguity of <
. You need to explicitly declare c
as [Option]
in order to use the overloaded operator.
The problem can be fixed with new programming-oriented protocol features introduced in swift 2.0
The @objc "Option" protocol cannot specify the non @objc "Equatable" protocol
As the error says, the Equatable
protocol is a fast protocol that cannot be used for Obj C context
The Option protocol can only be used as a general restriction, since it has its own or related requirements such as
You can achieve this as follows:
@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 }
And your class and implementation looks like this:
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(<)