Я хочу иметь возможность находить и обновлять пользовательский объект в массиве этих объектов. Проблема заключается в том, что пользовательские объекты также могут быть дочерними объектами.
Пользовательский объект выглядит следующим образом:
class CustomObject: NSObject {
var id: String?
var title: String?
var childObjects: [CustomObject]?
}
Я хотел бы иметь возможность создать функцию, которая перезаписывает пользовательский объект с помощью fx определенного идентификатора, например:
var allCustomObjects: [CustomObject]?
func updateCustomObject(withId id: String, newCustomObject: CustomObject) {
var updatedAllCustomObjects = allCustomObjects
// ...
// find and update the specific custom object with the id
// ...
allCustomObjects = updatedAllCustomObjects
}
Я понимаю, что это должно быть довольно нормальной проблемой в отношении многомерных массивов/каталогов как в Swift, так и в других языках. Пожалуйста, дайте мне знать, какая обычная практика используется для этого вопроса.
Я думаю, что более быстрый, как и, вероятно, более простой способ реализовать такой алгоритм — это добавить рекурсивный метод, такой как update(at id: String), который мог бы возвращать логическое значение (это сработало?) или CustomObject? (либо один был затронут или нет). С этим вы начинаете рассматривать CustomObject как дерево, которое, кажется, соответствует вашему варианту использования. Я, вероятно, не могу привести хороший пример, так как я не практиковал Swift в течение многих лет, но просмотр BTree может быть хорошим началом en.wikipedia.org/wiki/B-дерево
@Sweeper, в этом примере идентификаторы всегда уникальны, да.
@Zyigh Понятно. Затем эта функция будет содержать цикл для вызова той же функции дочерних объектов и углубления в дерево?
Все ли дочерние объекты также находятся в allCustomObjects?



Как и в большинстве случаев, связанных с деревьями, рекурсия поможет. Вы можете добавить дополнительный параметр, который указывает, какой массив CustomObject вы просматриваете в данный момент, и возвращает Bool, указывающий, найден ли идентификатор, для целей короткого замыкания.
@discardableResult
func updateCustomObject(withId id: String, in objectsOrNil: inout [CustomObject]?, newCustomObject: CustomObject) -> Bool {
guard let objects = objectsOrNil else { return false }
if let index = objects.firstIndex(where: { $0.id == id }) {
// base case: if we can find the ID directly in the array passed in
objectsOrNil?[index] = newCustomObject
return true
} else {
// recursive case: we need to do the same thing for the children of
// each of the objects in the array
for obj in objects {
// if an update is successful, we can end the loop there!
if updateCustomObject(withId: id, in: &obj.childObjects, newCustomObject: newCustomObject) {
return true
}
}
return false
// technically I think you can also replace the loop with a call to "contains":
// return objects.contains(where: {
// updateCustomObject(withId: id, in: &$0.childObjects, newCustomObject: newCustomObject)
// })
// but I don't like doing that because updateCustomObject has side effects
}
}
Вы бы назвали это так, с параметром in: равным allCustomObjects.
updateCustomObject(withId: "...", in: &allCustomObjects, newCustomObject: ...)
Я предполагаю, что идентификаторы уникальны во всем дереве
CustomObjects? Для каждого заданного идентификатора где-то в дереве есть ровно одинCustomObjectс этим идентификатором? (В отличие от уникального только в пределах братьев и сестер объекта)