简体   繁体   中英

Extend @objc protocol with Comparable in Swift

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:

  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

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 (ie 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, eg 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(<)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM