【问题标题】:How to update an array with WritableKeyPath in Swift 4.0如何在 Swift 4.0 中使用 WritableKeyPath 更新数组
【发布时间】:2018-07-23 07:21:23
【问题描述】:

在 Swift 4.0 中,我有一个结构数组。有没有办法使用 keyPaths 来更新数组中的所有项目,而无需像 map 或 forEach 那样手动迭代?类似objc的东西[people makeObjectsPerformSelector: @selector(setName:) withObject: @"updated"];

struct Person {
    var name: String? = "Empty"
}
var people = [Person(), Person()]

//This only updates one person:
people[keyPath: \[Person].[0].name] = "single update"

//I'm looking to accomplish something like this without a map
let updatedPeople = people.map { (person: Person) -> Person in
    var copy = person
    copy[keyPath: \Person.name] = "updated"
    return copy
}

类似的东西 people[keyPath: \[People].all.name] = "无需手动迭代即可全部更新"

【问题讨论】:

  • people.indices.forEach { idx in people[idx][keyPath: \Person.name] = "updated" }
  • 据我所知,与关键路径无关。

标签: arrays swift struct updating keypaths


【解决方案1】:

变异为数组的成员需要一个左值。 Swift 的左值机制是下标,所以我们可以使用它:

for i in people.indices {
    people[i][keyPath: \Person.name] = updated
    // or more simply, just:
    // people[i].name = "updated"

    // This even works too, but I can't see any reason why it would be desirable
    // over the other 2 approaches:
    // people[keyPath: \[Person].[i].name] = "update"
}

你也可以使用forEach,但我通常只建议在for 上使用(Index) -> Void 类型的现有闭包/函数:

// meh
people.indices.forEach {
    people[$0][keyPath: \Person.name] = "updated"
}

【讨论】:

    【解决方案2】:

    编辑 回答您现在编辑的问题,询问与 [people makeObjectsPerformSelector: @selector(setName:) withObject: @"updated"] 等效的 Swift 在哪里,简单的答案是 map,您出于某种原因在您的问题中拒绝了它, 等价的。当然,要做到Objective-C所做的事情,我们必须使用Objective-C风格的对象类型,即一个类:

    class Person {
        var name: String? = "Empty"
    }
    var people = [Person(), Person()]
    people = people.map {$0.name = "updated"; return $0} // *
    

    星号线你如何让数组中的对象执行“选择器”。

    结构是一种值类型,因此正如您在问题中所说的那样,我们必须插入一个带有 var 引用的临时变量:

    struct Person {
        var name: String? = "Empty"
    }
    var people = [Person(), Person()]
    people = people.map {var p = $0; p.name = "updated"; return p}
    

    [原答案:]

    在您的问题中使用关键路径似乎是一个红鲱鱼。您只是在问如何设置数组中所有结构的属性。

    map 只是在数组中循环的一种方式。 如果没有在数组中循环,你不能神奇地做到这一点;如果你不显式地做,你必须隐式地做。

    这是一个明确的方法:

    struct Person {
        var name: String? = "Empty"
    }
    var people = [Person(), Person()]
    let kp = \Person.name
    for i in 0..<people.count {
        people[i][keyPath:kp] = "updated"
    }
    

    据我所知,这实际上并不比使用map 更有效;结构在适当的位置是不可变的,所以我们仍然用全新的 Person 对象填充数组,就像使用 map 时所做的一样。

    【讨论】:

    • 会推荐people.indicies 而不是0..&lt;people.count。我们得到了太多由常见拼写错误引起的索引越界错误:0...array.count
    • @Alexander 正确拼写会有所帮助,我想。
    • 嗯,是的。然而,点立场。
    • 嗯,你已经在你的回答中给出了这个,所以我想我会保持原样。
    • 不求魔法,问是否有任何我缺少的内置助手,如 obj-c 你可以[people makeObjectsPerformSelector: @selector(setName:) withObject: @"updated"];
    猜你喜欢
    • 2018-05-09
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-09
    • 1970-01-01
    相关资源
    最近更新 更多