import Foundation
let mock = NSNumber(integerLiteral: 6)
let count = 10
let array = Array<NSNumber>(unsafeUninitializedCapacity: count) { (buffer, initCount) in
for index in 0..<count {
buffer[index] = mock
}
initCount = count
}
print(array)
But it crashes my Xcode 99% of the time. When I run this with debugging enabled, I get the following error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x20)
When I run the same code but disable "Debug executable" in Xcode, it works fine.
What am I doing wrong or how can I prevent these BAD_ACCESS errors while debugging?
mock is just a placeholder to simplify my code. In reality I want to convert a linked list to an array, so I think I cannot use buffer.initialize(repeating: mock). And since my linked list is linked from end to start I think I cannot use buffer.initialize(from:) either.
What do you mean by:
and whatever was there already needs to be uninitialized
Every element in buffer starts with uninitialized state. The subscript requires that the element you’re pointing is in initialized state, hence the crash (I’m still worried about that 1%).
You need to initialize each element with the pointer APIs. initialize(from:) is one of them. You can also extract buffer.baseAddress and use initialize(to:) and/or its siblings.
Note also that init(unsafeUninitializedCapacity:initializingWith:) requires the first count elements to be initialized, and the rest to be uninitialized (or the Element is trivial type) when the closure returns.
How come we need to manually initialise these addresses when you assign reference types (NSNumber) and not when you assign value types (Int)? For example why does this work in contrast to the NSNumber example?
let count = 10
let array = Array<Int>(unsafeUninitializedCapacity: count) { (buffer, initCount) in
for index in 0..<count {
buffer[index] = index
}
initCount = count
}
print(array)
Do not mistake what you need to do for what works. You always need to initialize the memory. It just so happens that with trivial types nothing bad happens if you assume it’s initialized because the compiler isn’t doing anything wrong. But your program should not rely on that behaviour.
@lukasa do you mean that we also have to use the initialize(to:) to assign trivial types like Ints?
Because when I looked at the first code sample in the proposal, I saw noinitialize(to:). That causes a bit confusion. Maybe we can improve the docs a bit on how or when to initialize?
The documentation is actually pretty consistent: it says you must call an initializing method. This particular pitch, however, relied on more subtle knowledge of Swift to note that in practice you can avoid trouble when using trivial types.
The first order answer is to always initialize memory. The second order answer is that, if you know your type is trivial you can skip that and just use subscript assignment. But if you always do the first, you won’t get burned.