我有一个协议以及一个协议扩展,我想在协议扩展中实现一个函数,用自定义对象对协议定义的数组进行排序,但它不起作用。
protocol MyProtocol {
var myArray: [MyObject] { get set }
}
extension MyProtocol {
func sortArrayByCreationTime() {
myArray.sort {
$0.created > $1.created
}
}
}
Xcode告诉我'sort'已经被重命名为'sorted(by :)',但是如果我正在使用它,则会创建一个新数组,但我需要对旧数组进行排序,而不是新数组。 / p>
我做错了什么?
答案 0 :(得分:1)
这是一个误导性错误 - 问题是您需要将sortArrayByCreationTime()
方法标记为mutating
,以告诉编译器它正在改变属性(因为协议可以被值和参考类型):
extension MyProtocol {
mutating func sortArrayByCreationTime() {
myArray.sort {
$0.created > $1.created
}
}
}
答案 1 :(得分:0)
我从原始代码中创建了一个Minimal,Complete和Verifiable示例(MCVE),并使其在Swift 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中,扩展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中,扩展序列。序列将允许您对作为数组的对象和其他类型(例如,词典)进行排序。更好的是,它不会创建一种变异方法。但老实说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) })