-1

I've been using Property Observers to manipulate UI and objects when a variable value has changed. With that in mind, I was wondering if it's possible to create my own Property Observers such as didSet and willSet for my own objects. what I'm looking for is to be able to write something like this:

var someArray: [String] {
    newElementAdded { *some code here* }
}

As you know didSet and willSet do not track for example adding an element to an array but however tracks changes of the entire array value. I'm looking forward to maybe extend that using the property observers. I looked into the documentation about closures and properties and I couldn't find any hints.

My question is, how could I create property observers ? I gave one of the use cases above as an example, but I'm aiming at creating my own observers.

HusseinB
  • 1,321
  • 1
  • 17
  • 41
  • 1
    `didSet` and `willSet` actually do track adding an element to an array – dan Oct 19 '18 at 20:19
  • @dan can you please elaborate on that? how could you know what's the newly added element? – HusseinB Oct 19 '18 at 20:24
  • You forgot to ask a question. – Joakim Danielson Oct 19 '18 at 20:24
  • @JoakimDanielson question added. Thought it could be inferred from the description. – HusseinB Oct 19 '18 at 20:28
  • Possible duplicate of [How can I observe a specific element with Swift collection types using property observers?](https://stackoverflow.com/questions/41120656/how-can-i-observe-a-specific-element-with-swift-collection-types-using-property) – Joakim Danielson Oct 19 '18 at 20:30
  • @JoakimDanielson thanks for the suggestion. Actually I was giving tracking an element to an array as an example here. My question is how to create property observers such as didSet. – HusseinB Oct 19 '18 at 20:35
  • You simply write the code. You can't attach property observers at runtime, if that is what you are asking. You could write a property observer that notified a list of objects that had registered at runtime, but you would need to implement that. – Paulw11 Oct 19 '18 at 20:37
  • @Paulw11 yes, basically I want to create my own observer like didSet which isn't attached at runtime. Any reference to follow in order to achieve that ? – HusseinB Oct 19 '18 at 20:39
  • It sounds to me like you want to re-invent something that already exists, didSet but with another name? Maybe you should look into key-value coding and key-value observing then although I don't understand why you can't use what is already there. – Joakim Danielson Oct 19 '18 at 20:49
  • @JoakimDanielson It's not reinventing. didSet and willSet both have different functionalities under the hood. My aim is not to rename didSet and maintain it's functionality, however I'm looking forward to create my own observer. – HusseinB Oct 19 '18 at 20:53
  • 1
    This is a good question. I have no idea how to add a custom property observer but I would be extremely interested in how its done. It would be a powerful way to extend a lot of things if it's possible. – rayepps Oct 19 '18 at 20:58
  • Fine but your question is still very unclear which you might judge from the comments. I think you need to give a concrete example of what you want to do and how you have tried to implement it, – Joakim Danielson Oct 19 '18 at 20:58
  • I still don't understand what you mean by "create your own observer". The code you write inside `didSet { }` *is your observer*. If you mean you want to able to specify some other keyword to introduce a closure that is a property observer, then no, you can't do that. – Paulw11 Oct 19 '18 at 20:59
  • @Paulw11 well technically according to the documentation, didSet/willSet are called observers and the code within them run after those observers get notified. Therefore, introducing a closure as a property observer that get notified on a certain event like didSet is what I'm looking for. So, it's a no on your side. – HusseinB Oct 19 '18 at 21:02
  • You could do it, but you would need to write the code yourself. For example, you could a closure property to your object `var someArrayObserver: ((Void)->Void)?` and then the `didSet` for `someArray` you would call `self.someArrayObserver?()` – Paulw11 Oct 19 '18 at 21:17

1 Answers1

0

The property observers are more than sufficient. You could use something like this:

var someArray: [String] = [] {
    didSet {
        stride(from: someArray.count, to: oldValue.count, by: 1).map {
            print("This index doesn't exist anymore:", $0)
        }

        stride(from: 0, to: min(oldValue.count, someArray.count), by: 1)
            .filter { oldValue[$0] != someArray[$0] }
            .forEach { print("The element at index", $0, "has a new value \"\(someArray[$0])\"") }

        stride(from: oldValue.count, to: someArray.count, by: 1).map {
            print("New value \"\(someArray[$0])\" in this index", $0)
        }
    }
}

someArray.append("Hello")
//New value "Hello" in this index 0

someArray.append("world")
//New value "world" in this index 1

someArray = ["Hello", "world"]
//Nothing is printed since no elements have changed

someArray.append("!")
//New value "!" in this index 2

someArray.remove(at: 1)
//This index doesn't exist anymore: 2
//The element at index 1 has a new value "!"

someArray.append(contentsOf: ["✋", ""])
//New value "✋" in this index 2
//New value "" in this index 3
ielyamani
  • 17,807
  • 10
  • 55
  • 90