Hello, I have a problem with using struct in Dictionary. Please take a look at this code first.
import Foundation
struct COWStruct {
class COWStorageClass { }
var s = COWStorageClass()
mutating func mutateSomething() {
print(isKnownUniquelyReferenced(&self.s) ? "unique" : "not unique")
}
}
var dict: [Int: COWStruct] = [:]
dict[0] = COWStruct()
let keysArray = dict.keys.map { $0 }
for key in keysArray {
dict.values[dict.index(forKey: key)!].mutateSomething() // not unique
}
for key in keysArray {
dict[key]?.mutateSomething() // not unique
}
for key in keysArray {
dict[key]!.mutateSomething() // not unique
}
It's simple. There is a struct with one mutating function to test that the storage property is uniquely referenced. This is used as a value in dict [Int: COWStruct]
As you see, all the mutating codes are failing to get the storage property uniquely referenced. They all print not unique
This problem occurs in Xcode 9.3, Swift 4.1
Am I doing something wrong?
2 Likes
The dictionary seems to be copying the object for some reason, because it works with an array:
struct COWStruct {
class COWStorageClass { }
var s = COWStorageClass()
mutating func mutateSomething() {
print(isKnownUniquelyReferenced(&self.s) ? "unique" : "not unique")
}
}
var dict = [0 : COWStruct()]
var array: [COWStruct?] = [COWStruct()]
dict[0]?.mutateSomething() // not unique
array[0]?.mutateSomething() // unique
There's some discussion of this behaviour on this Stack Overflow Q&A:
The main issue is that currently Dictionary's subscript(_:) uses a getter + setter (in contrast to Array's subscript(_:) which uses a getter + addressor).
There are some workarounds to this however, such as using Dictionary's subscript(_:default:) which (as of Swift 4.1) uses an addressor, or temporarily removing the value you want to mutate before re-inserting it into the dictionary.
It would be really nice if we could find a way to make Dictionary's subscript(_:) work with addressors though.
2 Likes
This is something we’re hoping to do with generalized accessors from the ownership manifesto.
2 Likes