我有一个协议,以及协议的扩展,我想实现的协议扩展到排序与自定义对象的协议定义的数组的函数,但它不工作。
protocol MyProtocol {
var myArray: [MyObject] { get set }
}
extension MyProtocol {
func sortArrayByCreationTime() {
myArray.sort {
$0.created > $1.created
}
}
}
Xcode是告诉我,“排序”已更名为“排序(由:)”,但如果使用这种新的阵列IM2被创建,但我需要旧的阵列进行排序,而不是一个新的。
我究竟做错了什么?
这是一个误导性的错误-问题是,你需要标记您的sortArrayByCreationTime()
方法mutating
,以告诉它的变异属性(如协议可由两个值类型和引用类型通过)编译:
extension MyProtocol {
mutating func sortArrayByCreationTime() {
myArray.sort {
$0.created > $1.created
}
}
}
我创建了一个最小的,完整的,并且可验证的例子(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) })