Different ways to observe properties in Swift
source link: https://www.jessesquires.com/blog/2021/08/08/different-ways-to-observe-properties-in-swift/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Different ways to observe properties in Swift
08 August 2021
After I wrote and released Foil, my library for implementing a property wrapper for UserDefaults
, one of the criticisms on Twitter was that a mechanism for observing such properties should have been included. I disagreed. In the post I argued that this was easy enough for clients to handle on their own, but more importantly that there are too many options for how to do this and I didn’t think Foil should impose any one of them on clients.
Shortly after releasing Foil, Basem Emara opened an issue to ask about observing property changes using Combine. No code changes were required for the library, and instead we merged some updates to the documentation to explain how to use Foil and Combine together. This gave me confidence that I made the correct choice to omit observation in Foil.
Today, I want to review the various methods for observing properties in Swift. I will use Foil for the example code in this post. Consider the following snippet, where we define some settings for our app.
final class AppSettings {
static let shared = AppSettings()
@WrappedDefault(keyName: "flagEnabled", defaultValue: false)
var flagEnabled: Bool
}
What are our options for observing the flagEnabled
property?
Swift property observers
The simplest but least flexible way to observe properties is built-in to the Swift language itself. We can add Swift’s property observers willSet
and didSet
.
@WrappedDefault(keyName: "flagEnabled", defaultValue: false)
var flagEnabled: Bool {
willSet {
print("will set")
}
didSet {
print("did set")
}
}
Observing changes this way would make the most sense if you decentralize your @WrappedDefault
properties by defining them on classes that utilize them, rather than a shared AppSettings
class. For example, you could add a @WrappedDefault
property to a view controller. To make use of the property observers within a centralized class like AppSettings
, you would need to pass in a closure to execute in the observers or post a Notification
— neither of which are ideal.
Key-Value Observing
The next option is to use key-value observing from Foundation, which has new and improved Swift APIs that utilize Key-Path expressions. This works well with a centralized AppSettings
class. However, it requires inheriting from NSObject
and making the properties that you wish to observe @objc
and dynamic
.
final class AppSettings: NSObject {
static let shared = AppSettings()
@WrappedDefault(keyName: "flagEnabled", defaultValue: false)
@objc dynamic var flagEnabled: Bool
}
Then, from elsewhere in our code we can observe changes:
let observer = AppSettings.shared.observe(\.flagEnabled, options: [.new]) { settings, change in
print("property changed")
}
Combine
Similar to KVO, we can use a Publisher if our app is using Combine.
var cancellable = Set<AnyCancellable>()
AppSettings.shared
.publisher(for: \.flagEnabled, options: [.new])
.sink { newValue in
print("property changed")
}
.store(in: &cancellable)
You can simplify this further by using the @Published
propperty wrapper.
Third-party libraries
Finally, there are a handful of open source reactive extension libraries available for Swift that you may already be using. I won’t dive into these, but the implementations and concepts would be similar to using Combine.
Conclusion
These are the primary ways to observe property changes in Swift. I think I made the right decision to omit this feature from Foil and instead allow clients to choose their own method of observation. It takes very little code to implement any of these methods, and you could streamline it even more with a few small extensions.
Recommend
-
93
Object.observe() 引爆数据绑定革命
-
36
In this post, I would like to explore coroutines, from the perspective of backend application use cases. Most of the posts about coroutines I saw were either not specific to platform or…
-
40
Istio An open platform to connect, manage, and secure microservices. In addition, here are some other documents you may wish to read: I...
-
17
您的连接不是私密连接 攻击者可能会试图从 www.jackpu.com 窃取您的信息(例如:密码、通讯内容或信用卡信息)。了解详情
-
12
A Better Way to Check in Than ‘How Are You’Why observations are more powerful than questions
-
7
Different ways to sort an array of strings in Swift How to sort an array of strings There are two ways to sort in Swift, The one that mutates the original array and the one that don't. Both of them...
-
7
Different ways to check if a string contains another string in Swift 11 Jan 2021 ⋅ 8 min read ⋅ Swift
-
7
Different ways to compare string in Swift 08 Jan 2021 ⋅ 3 min read ⋅ Swift St...
-
5
Different ways to catch throwing errors from Swift do-catch 09 Aug 2021 ⋅ 9 min read ⋅ Swift Table of...
-
4
When talking about a map function over a Dictionary, there are many ways to think about it. You might want to do either one of these three things. Transform a value, but keep the
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK