What is the purpose of willSet and didSet in Swift?
The point seems to be that sometimes, you need a property that has automatic storage and some behavior, for instance to notify other objects that the property just changed. When all you have is get
/set
, you need another field to hold the value. With willSet
and didSet
, you can take action when the value is modified without needing another field. For instance, in that example:
class Foo {
var myProperty: Int = 0 {
didSet {
print("The value of myProperty changed from \(oldValue) to \(myProperty)")
}
}
}
myProperty
prints its old and new value every time it is modified. With just getters and setters, I would need this instead:
class Foo {
var myPropertyValue: Int = 0
var myProperty: Int {
get { return myPropertyValue }
set {
print("The value of myProperty changed from \(myPropertyValue) to \(newValue)")
myPropertyValue = newValue
}
}
}
So willSet
and didSet
represent an economy of a couple of lines, and less noise in the field list.
Accessing actor properties synchronously from task-less context
I found a way to do it by using Combine
, like this:
import Combine
actor Foo {
nonisolated let valuePublisher = CurrentValueSubject<Int, Never>(0)
var value: Int = 0 {
didSet {
valuePublisher.value = value
}
}
}
By providing an non-isolated publisher, we can propagate the actor value safely to the outside, since Publisher
s are thread safe.
Callers can either access foo.valuePublisher.value
or subscribe to it from the outside, without requiring an async context.
Property Observers on NSUserDefaults
The easiest way to do that is to combine both user defaults and animations on a computed variable as follow:
var defaultName:String{
get {
var returnValue: NSString? = NSUserDefaults.standardUserDefaults().objectForKey("defaultName") as? NSString
if returnValue == nil //Check for first run of app
{
returnValue = ""
}
return returnValue!
}
set (newValue) {
NSUserDefaults.standardUserDefaults().setObject(newValue, forKey: "defaultName")
NSUserDefaults.standardUserDefaults().synchronize()
// start your animations here
}
}
Next on button click just change the defaultName value so both newValue will be stored and animations will trigger
Are Swift variables atomic?
It's very early to assume as no low-level documentation is available, but you can study from assembly. Hopper Disassembler is a great tool.
@interface ObjectiveCar : NSObject
@property (nonatomic, strong) id engine;
@property (atomic, strong) id driver;
@end
Uses objc_storeStrong
and objc_setProperty_atomic
for nonatomic and atomic respectively, where
class SwiftCar {
var engine : AnyObject?
init() {
}
}
uses swift_retain
from libswift_stdlib_core
and, apparently, does not have thread safety built in.
We can speculate that additional keywords (similar to @lazy
) might be introduced later on.
Update 07/20/15: according to this blogpost on singletons swift environment can make certain cases thread safe for you, i.e.:
class Car {
static let sharedCar: Car = Car() // will be called inside of dispatch_once
}
private let sharedCar: Car2 = Car2() // same here
class Car2 {
}
Update 05/25/16: Keep an eye out for swift evolution proposal https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md - it looks like it is going to be possible to have @atomic
behavior implemented by yourself.
Thread safe singleton in swift
Thanks to @rmaddy comments which pointed me in the right direction I was able to solve the problem.
In order to make the property foo
of the Singleton
thread safe, it need to be modified as follows:
class Singleton {
static let shared = Singleton()
private init(){}
private let internalQueue = DispatchQueue(label: "com.singletioninternal.queue",
qos: .default,
attributes: .concurrent)
private var _foo: String = "aaa"
var foo: String {
get {
return internalQueue.sync {
_foo
}
}
set (newState) {
internalQueue.async(flags: .barrier) {
self._foo = newState
}
}
}
func setup(string: String) {
foo = string
}
}
Thread safety is accomplished by having a computed property foo
which uses an internalQueue
to access the "real" _foo
property.
Also, in order to have better performance internalQueue
is created as concurrent. And it means that it is needed to add the barrier
flag when writing to the property.
What the barrier
flag does is to ensure that the work item will be executed when all previously scheduled work items on the queue have finished.
Related Topics
Using Auto Layout to Orientate Stack Views Vertically in Portrait and Horizontally in Landscape
Leaving Equal Width Gap Spacing Before and Between Menu Buttons
Swift Getnameinfo Unreliable Results for Ipv6
Xcode 6.1 Swift Extensions - Sourcekit Service Crash
Appdelegate#Applicationdidfinishlaunching Not Called for Swift 4 Macos App Built from Command Line
How to Change an Inout Parameter from Within a Escaping Closure
Swift Auto Completion Not Working in Xcode 6 Beta
I Am Loading Videos in Avplayer in Collection View But It Repeats Some Cells Data
Swift: How to Catch Exception When Parsing a Numeric String
How to Use This Fetchrequest() in Swift
How to Build a Recursive Function in Swift to Return a String
How to Query Firebase Data Childbyautoid
How to Horizontally Center Content of Horizontal Scrollview
Stripe API Response: The Data Couldn't Be Read Because It Isn't in The Correct Format
Swiftui Published Updates Not Refreshing
Querying Geohashes in Firestore Returns Nothing
Swiftui JSON Won't Print Title in Scrollview Hstack (But Will in List)