7

Swift arrays are value types that copy on write. If a the original array is not mutated then the “copy” points to the same memory location.

Supposed we have a class referenced by multiple threads

class Foo {
    var numbers: [Int] = [1, 2, 3]
}
let foo = Foo()

If thread A “copies” numbers

var numbers = foo.numbers

and then later thread B replaces numbers with a different array instance

foo.numbers = [4, 5, 6]

will the original numbers array ([1, 2, 3]) be deallocated, resulting in incorrect checksum for freed object - object was probably modified after being freed when thread B attempts to access its elements?

Steve Kuo
  • 61,876
  • 75
  • 195
  • 257
  • For which object you are getting that error/warning? – Santosh Jul 08 '16 at 01:27
  • Refer this : http://stackoverflow.com/questions/19840671/malloc-error-incorrect-checksum-for-freed-object-object-was-probably-mod – Santosh Jul 08 '16 at 01:41
  • I very much dislike how Swift arrays are pass by value instead of by pointer. That has hung me out to dry a couple times already. – Putz1103 Jul 08 '16 at 02:11

2 Answers2

1

var numbers = foo.numbers will always contain [1, 2, 3] until you modify var numbers.

let foo = Foo()
// Thread A
var numbers = foo.numbers

// Thread b
foo.numbers = [4, 5, 6]

// Thread A again - 'var numbers' still has a "reference" to [1, 2, 3]
print(numbers) // "[1, 2, 3]"

I think you're misunderstanding how structs in swift act as value types. The original [1, 2, 3] array will not overwritten when you reassign foo.numbers.

Example

Say you have 10 threads all of which "copy" foo.numbers, at this point the array's memory is not copied.

var myTheadNumbers = foo.numbers

Lets say thread 1 modifies the array

myThreadNumbers.append(4)

[1, 2, 3] is copied to a new array which is then modified by appending 4.

Thread 1 now has it's own a single array of [1, 2, 3, 4] while threads 2-10 are still sharing the original [1, 2, 3]. That's what copy-on-write means for structs - you only take the performance hit for copying when you modify a struct and someone else has an old copy laying around.

Each one of those 10 threads acts like they have their own copy of [1, 2, 3] which is the meaning of value types.

Kevin
  • 16,696
  • 7
  • 51
  • 68
0

First, consider what happens without concurrency:

The original array won't be released until all strong references are removed, so as long as numbers still holds the reference the original array will be in memory.

When you assign a new array to foo.numbers you remove one reference to the original array, but numbers still holds a reference so it isn't released. foo.numbers now holds a strong reference to the new array.

Even if I modify foo.numbers in place:

foo.numbers.append(4)

numbers will still hold a reference to the original array and foo.numbers will now hold a reference to a new array because it was copied when it was modified.

Once you introduce concurrency into all of this, it can get messy since, these copy and assignment operations may not be atomic. Concurrent updates of any object needs to have critical sections guarded to prevent corruption.

You could use a serial dispatch queue to manage any updates to the numbers array.

class Foo {

    private var _numbers: [Int] = [1,2,3];

    private let serialQ = dispatch_queue_create("serialQ", DISPATCH_QUEUE_SERIAL)

    var numbers: [Int] {
        set {
            dispatch_sync(self.serialQ) { 
                self._numbers = newValue
            }
        }
        get {
            return self._numbers
        }
    }
}
Paulw11
  • 108,386
  • 14
  • 159
  • 186