的.sort在协议扩展是不工作(.sort in protocol extension is not

2019-09-26 05:50发布

我有一个协议,以及协议的扩展,我想实现的协议扩展到排序与自定义对象的协议定义的数组的函数,但它不工作。

protocol MyProtocol {
    var myArray: [MyObject] { get set }
}

extension MyProtocol {
    func sortArrayByCreationTime() {
        myArray.sort {
            $0.created > $1.created
        }
    }
}

Xcode是告诉我,“排序”已更名为“排序(由:)”,但如果使用这种新的阵列IM2被创建,但我需要旧的阵列进行排序,而不是一个新的。

我究竟做错了什么?

Answer 1:

这是一个误导性的错误-问题是,你需要标记您的sortArrayByCreationTime()方法mutating ,以告诉它的变异属性(如协议可由两个值类型和引用类型通过)编译:

extension MyProtocol {
    mutating func sortArrayByCreationTime() {
        myArray.sort {
            $0.created > $1.created
        }
    }
}


Answer 2:

我创建了一个最小的,完整的,并且可验证的例子(MCVE)出来的原代码,和我做了它在斯威夫特3游乐场工作

import UIKit
import XCTest

extension Date
{
    init?(year: Int, month: Int, day: Int) {
        var dateComponents = DateComponents()
        dateComponents.day = day
        dateComponents.month = month
        dateComponents.year = year
        guard let date = Calendar.current.date(from: dateComponents)
        else { return nil }
        self = date
    }
}

struct MyObject {
    var created: Date
}

protocol MyProtocol {
    var myArray: [MyObject] { get set }
}

extension MyProtocol {
    mutating func sortArrayByCreationTime() {
        myArray.sort {
            $0.created > $1.created
        }
    }
}

struct ArrayContainer: MyProtocol {
    var myArray: [MyObject]
}

let objects = [
    MyObject(created: Date(year: 2016, month: 9, day: 1)!),
    MyObject(created: Date(year: 2016, month: 11, day: 1)!),
    MyObject(created: Date(year: 2016, month: 4, day: 1)!),
    MyObject(created: Date(year: 2016, month: 8, day: 1)!),
]
var container = ArrayContainer(myArray: objects)

var dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMdd"

XCTAssertEqual(["0901", "1101", "0401", "0801"],
               container.myArray.map { dateFormatter.string(from: $0.created) })
container.sortArrayByCreationTime()
XCTAssertEqual(["1101", "0901", "0801", "0401"],
               container.myArray.map { dateFormatter.string(from: $0.created) })

让我举两个选项:

选项1:改进

在方案1,扩展Array结构,这样就可以创造变异的方法sortByCreationDate 。 存在需要被拉出,以便帽子的一招延长[MyObject来](为MyObject的阵列)

protocol MyObjectProtocol { var created: Date { get set } }
extension MyObject: MyObjectProtocol { }
extension Array where Element: MyObjectProtocol {
    mutating func sortByCreationTime() {
        self.sort {
            $0.created > $1.created
        }
    }
}

var container2 = ArrayContainer(myArray: objects)
XCTAssertEqual(["0901", "1101", "0401", "0801"],
               container2.myArray.map { dateFormatter.string(from: $0.created) })
container2.myArray.sortByCreationTime()
XCTAssertEqual(["1101", "0901", "0801", "0401"],
               container2.myArray.map { dateFormatter.string(from: $0.created) })

选项2:更好

在方案2,延伸序列。 序列将允许您是数组,和其他类型,例如对象字典进行排序。 更妙的是,它不创建一个不同诱变方法。 但说实话MyProtocol是一个令人困惑的API。 使用这种方法, MyProtocol不再是必要的。

extension Sequence where Iterator.Element == MyObject {
    func sortedByCreationTime() -> [Iterator.Element] {
        return self.sorted {
            $0.created > $1.created
        }
    }
}
var container3 = ArrayContainer(myArray: objects)
XCTAssertEqual(["0901", "1101", "0401", "0801"],
               container3.myArray.map { dateFormatter.string(from: $0.created) })
XCTAssertEqual(["1101", "0901", "0801", "0401"],
               container3.myArray.sortedByCreationTime().map { dateFormatter.string(from: $0.created) })


文章来源: .sort in protocol extension is not working