Created
February 2, 2019 10:25
-
-
Save drewmccormack/b1c4487935cf3c3e0a5feaf488a95ebd to your computer and use it in GitHub Desktop.
Demonstrates how a Swift value constant can mutate when using Copy-on-Write (CoW) and multi-threading.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
struct NuclearPowerStationOperator { | |
class Storage { | |
var turnOffCores: Bool = false | |
func copy() -> Storage { | |
let new = Storage() | |
new.turnOffCores = turnOffCores | |
return new | |
} | |
} | |
private var storage: Storage = Storage() | |
var turnOffCores: Bool { | |
get { | |
return storage.turnOffCores | |
} | |
set { | |
if isKnownUniquelyReferenced(&storage) { | |
Thread.sleep(forTimeInterval: 1.0) // Sleep to simulate race condition | |
storage.turnOffCores = newValue | |
} else { | |
storage = storage.copy() | |
storage.turnOffCores = newValue | |
} | |
} | |
} | |
var description: String { | |
return "\(turnOffCores ? "We are in danger" : "We are safe")" | |
} | |
} | |
// Create a mutable value | |
var crazyOperator = NuclearPowerStationOperator() | |
DispatchQueue.global(qos: .background).async { | |
Thread.sleep(forTimeInterval: 0.5) // Sleep a little to give main thread time to start setting property | |
let saneOperator = crazyOperator // Create a constant copy of the operator from main thread | |
print(saneOperator.description) // Print our intial property value | |
Thread.sleep(forTimeInterval: 2.0) // Simulate race by waiting for setter on main thread to finish | |
print(saneOperator.description) // Test property (it will be different) | |
} | |
// Update the value. Note that the setter simulates a race condition by being very slow | |
crazyOperator.turnOffCores = true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You have to add
crazyOperator
to a capture list of the closure to get the behaviour you wanted. Without it, closure will have a reference to your variable, it will not copy it on creation.Change
into
To see the difference between a closure with and without a capture list, have a look at the following code: