I am trying to extend my protocol Option
with Comparable
to use simple .sort()
method.
Below short example only with Equatable
to show 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 inherit from NSObjectProtocol
because it will be used with UIKit
.
Errors:
@objc protocol 'Option' cannot refine non-@objc protocol 'Equatable'
Protocol 'Option' can only be used as a generic constraint because it has Self or associated type requirements
Do you have any suggestion how to solve this problem?
Equatable
lives in the Swift world only, thus you cannot extend it to a protocol that will be used by Objective-C. Trying to do this results in error #1
Protocols that have a Self
requirement (i.e. at least one method from the protocol declaration contains Self
) cannot be used as arguments to functions, or to variable declarations, only as arguments to a generic clause, e.g. func doSomething<T: Option>(argument: T)
.
Removing Equatable
from the Option
protocol declaration, and declaring ==
as generic on Option
will solve the compile errors. As for sorting, you can also overload the <
operator, and sort via that operator (without needing to implement 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 pass objects that conform to the protocol to UIKit
, and to also compare them within your swift 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 regarding the sorting code above: if you don't specify the type for c
, then the compiler infers its type as [NSObject]
, and the sort
call will not compile due to ambiguity of the <
operator. You need to explicitly declare c
as [Option]
to take advantage of the overloaded operator.
The issue can be fixed by the new protocol oriented programming features introduced in swift 2.0
@objc protocol 'Option' cannot refine non-@objc protocol 'Equatable'
As the error states, the Equatable
protocol is a swift protocol that you can't to Obj C context
Protocol 'Option' can only be used as a generic constraint because it has Self or associated type requirements
You can achieve this in the following way:
@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:
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(<)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With