setter with array questions.

so, swift has a simplified but way more efficient setter/getter function workflow than cocoa does. And the way I read it


if you have an array property, and you write a setter:


var anArray : [objs] {

set(newArray){


}
...


then your setter function is called when the array gets an entirely new value:

anArray = [obj01, obj02]


I think I did some tests, which showed that the setter is also called when you append or remove a value from the array:

anarray.append(newObj)

but that was a long time ago, and I'm not certain that it was even supposed to do that.


my question is: is there a setter/getter that I can override that ONLY gets called when my array has been appended, or a value removed? one in which the incoming value is the change, and not the entire array? or am I missing something fundamental? I swear up and down that I have read and re-read the docs.


why? well, when I add a new object to a particular array, I need to add some supporting objects to another array. I could easily write a method, and require the use of that method. But it would be nice to be able to leverage the power of swift in this instance.

Answered by OOPer in 18974022

The answer to your question is : NO.

In Swift, Array is a value type, so any modifications to a single element (append, remove, replace,...) would invoke setter, when you made the property as computed, as well as the entire array replacement.


To achieve your goal, using KVO is the best way I think, but it's not the power of swift, but the power of Objective-C runtime.


Addition: if you can easily write the method, it may be easier than using KVO.

Accepted Answer

The answer to your question is : NO.

In Swift, Array is a value type, so any modifications to a single element (append, remove, replace,...) would invoke setter, when you made the property as computed, as well as the entire array replacement.


To achieve your goal, using KVO is the best way I think, but it's not the power of swift, but the power of Objective-C runtime.


Addition: if you can easily write the method, it may be easier than using KVO.

i went with a method.

It's a darned shame, I would really like to be able to use code that looks like this:


myArray += newObject


rather than code that looks like this:


myArraysParentObject.addChildToSpecificArray(newObject)


and still have the option of tweaking internals in the parent object to align with the contents of the array.


KVO is awesome. It's a little draining to support, bc the design pattern is a bit non-swift. since i'm at a prototyping stage... probably not the best choice. meanwhile... had an oddity: built a getter ONLY property, and tried to invoke it from another object. the compiler flagged the call, saying the property did not exist. I may stay away from getters/setters for a bit.

thanks btw. exactly what I needed to know.

There are some ways you could use a += syntax, if any of them fit your design and preferences.


If the reference to the parent class is internal and can safely be a var, you can define += to take the Parent and array element type as parameters. You wouldn't be able to modify a Parent instance declared with let, though.

class Parent
{
    var array01: Array<Int> = []
    var array02: Array<String?> = []

    /* ... */
}

func += (inout left: Parent, right: Int)
{
    left.array01.append(right)
    left.array02.append("\(right)")
}

func -= (inout left: Parent, right: Int)
{
    if let index = left.array01.indexOf(right)
    {
        left.array01.removeAtIndex(index)
        left.array02.removeAtIndex(index)
    }
}


You could wrap the info into a struct instead of storing it in different arrays, and override += to take that specific array type and the primary element type as arguments.

struct Thing
{
    var id: Int
    var name: String?
}

func += (inout left: Array<Thing>, right: Int)
{
    left.append(Thing(id: right, name: "\(right)"))
}

func -= (inout left: Array<Thing>, right: Int)
{
    var index: Int = 0
    let count = left.count
    for (index = 0; index < count; ++index){if left[index].id == right {break}}
    if index < count {left.removeAtIndex(index)}
}


class Parent
{
    var array: Array<Thing> = []

    /* ... */
}


This third way is similar to the first, but the Parent class instance can be declared using let for a constant pointer since it's no longer the direct target of += and -=. But when you access the arrays, you will need to prefix them with the struct property name too.

struct Thing
{
    var array01: Array<Int> = []
    var array02: Array<String?> = []
}

class Parent
{
    var stored: Thing = Thing()
   
    /* ... */
}


func += (inout left: Thing, right: Int)
{
    left.array01.append(right)
    left.array02.append("\(right)")
}

func -= (inout left: Thing, right: Int)
{
    if let index = left.array01.indexOf(right)
    {
        left.array01.removeAtIndex(index)
        left.array02.removeAtIndex(index)
    }
}
setter with array questions.
 
 
Q