Reputation: 127
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?
Upvotes: 7
Views: 3416
Reputation: 32814
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.
Upvotes: 6
Reputation: 107131
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(<)
Upvotes: 2