问题
Inspired when answering the question of How do I know if a value of an element inside an array was changed?, The answer was using a Property Observer for checking if an array has been modified.
However, How can I determine what is/are the updated element(s) in a collection type in a property observer? For example:
class MyClass {
var strings: [String] = ["hello", "world", "!"] {
didSet(modifiedStrings) {
print("strings array has been modified!!:")
print(modifiedStrings)
}
}
}
let myClass = MyClass()
myClass.strings.append("a string")
myClass.strings[0] = "Hello"
myClass.strings.removeLast()
Note that the didSet
code has been called for each of adding, updating or deletion operation, but how can I exactly know what are the effected elements? is there even a way to achive this by decalring strings
array as a Property Observer?
I am asking about all collection types in Swift because I assume that it should be the same behavior for all of them, it is about the observing.
Thanks.
回答1:
Thanks for @hnh, based on his answer, I ended up with:
class MyNumber: NSObject {
// NOTE that it works in both "willSet" and "didSet"
/// Array ///
var arrayNumbers: [String] = ["one", "two", "three"] {
willSet {
let oldStrings = Set(arrayNumbers)
let newStrings = Set(newValue)
print("removed from array: \(oldStrings.subtracting(newStrings))")
print("added to array: \(newStrings.subtracting(oldStrings))")
print("----------")
}
}
/// Set ///
var setNumbers: Set = ["one", "two", "three"] {
didSet(newSet) {
print("removed from set: \(newSet.subtracting(setNumbers))")
print("added to set: \(setNumbers.subtracting(newSet))")
print("----------")
}
}
var dictionaryNumbers = ["1": "one", "2": "two", "3": "three"] {
didSet(modified) {
let oldKeys = Set(dictionaryNumbers.keys)
let newKeys = Set(modified.keys)
let oldValues = Set(dictionaryNumbers.values)
let newValues = Set(modified.values)
print("removed from dictionary (keys): \(newKeys.subtracting(oldKeys)) (values): \(newValues.subtracting(oldValues))")
print("added to dictionary (keys): \(oldKeys.subtracting(newKeys)) (values): \(oldValues.subtracting(newValues))")
print("----------")
// print("removed (values): \(newValues.subtracting(oldValues))")
// print("added (values): \(oldValues.subtracting(newValues))")
}
}
}
Execution:
let myNumber = MyNumber()
/// Array ///
// adding:
myNumber.arrayNumbers.append("four")
/* Logging:
removed: [] means that nothing has been removed form the array
added: ["four"]
----------
*/
// updating:
myNumber.arrayNumbers[0] = "One"
/* Logging:
removed: ["one"]
added: ["One"]
----------
*/
// deleting:
myNumber.arrayNumbers.removeLast()
/* Logging:
removed: ["four"]
added: [] means that nothing has been added to the array
----------
*/
/// Set ///
// adding:
myNumber.setNumbers.insert("four")
/* Logging:
removed from set: [] means that nothing has been removed form the set
added to set: ["four"]
----------
*/
// deleting:
myNumber.setNumbers.removeFirst()
/* Logging:
removed from set: ["three"] // sets are unsorted...
added to set: [] means that nothing has been added to the set
----------
*/
/// Dictionary ///
// adding:
myNumber.dictionaryNumbers["4"] = "four"
/* Logging:
removed from dictionary (keys): [] (values): []
added to dictionary (keys): ["4"] (values): ["four"]
----------
*/
// updating:
myNumber.dictionaryNumbers["1"] = "One"
/* Logging:
removed from dictionary (keys): [] (values): ["one"]
added to dictionary (keys): [] (values): ["One"]
----------
*/
// deleting:
myNumber.dictionaryNumbers.removeValue(forKey: "2")
/* Logging:
removed from dictionary (keys): ["2"] (values): ["two"]
added to dictionary (keys): [] (values): []
----------
*/
This shows how to deal with array, set and dictionary.
回答2:
You can use the willSet
observer to calculate changes before they are applied. Like so:
struct YourStruct {
var strings : [ String ] = [ "Hello", "World", "!" ] {
willSet {
// in here you have `newValue` containing the new array which
// will be set. Do any comparison operations you want, like:
let oldStrings = Set(strings)
let newStrings = Set(newValue)
print("removed: \(oldStrings.substract(newStrings))")
print("added: \(newStrings.substract(oldStrings))")
// (Just for demonstration purposes, if they are Sets, they
// should be Sets in the first place, obviously.)
}
}
}
来源:https://stackoverflow.com/questions/41120656/how-can-i-observe-a-specific-element-with-swift-collection-types-using-property