Greetings, traveler!
In the previous article, we considered a variant of swizzling based on Objective-C methods. However, there is a more modern way to do this, taking advantage of the Swift language: type safety and simplicity.
For an entity to be dynamically replaced, it must be marked with the dynamic keyword. Let’s look at an example using functions.
dynamic func myFunction() {
print("1")
}
@_dynamicReplacement(for: myFunction)
func myFunction_dynamicReplacement() {
print("2")
}
myFunction() // "2"
Now, let’s try to change the behavior of the structure using the extension.
struct Object {
dynamic var name: String {
"name"
}
let strings: [String]
dynamic init(someData: [String]) {
strings = someData
}
}
extension Object {
@_dynamicReplacement(for: init(someData:))
init(strings: [String]) {
self.strings = strings.dropLast()
}
}
As you can see, we could replace the initializer implementation, even replacing the name of the parameters. However, their types should remain the same.
In addition, we can use the original entities to get a new value.
extension Object {
@_dynamicReplacement(for: name())
var computedName: String {
String(describing: self) + " " + name
}
}
However, there is a nuance that may take time to be noticeable. This approach with classes such as UIViewController will not work because its methods and properties are not marked with the dynamic keyword. Therefore, you must use the method described in the previous article for swizzling. Otherwise, we will get an endless loop of method calls.
Conclusion
Compared to the old Objective-C way of swizzling, this one looks much more straightforward and, importantly, type-safe. I hope you enjoyed this article. See you soon!