Is it possible to create a keypath referencing a method? all examples are paths to variables.
I'm trying this:
class MyClass {
init() {
let myKeypath = \MyClass.handleMainAction
...
}
func handleMainAction() {...}
}
but it does not compile saying Key path cannot refer to instance method 'handleMainAction()
Because closures of the form: (Root Type ) -> Value are common in Swift, Key path as functions is one of the features added to swift 5.2. it allows keypath to automatically be promoted and used wherever a functions of the form (Root ) -> Value are expected.
Key paths essentially let us reference any instance property as a separate value. As such, they can be passed around, used in expressions, and enable a piece of code to get or set a property without actually knowing which exact property its working with. Key paths come in three main variants: KeyPath: Provides read-only access to a property.
WritableKeyPath works will Root of value types ( struct and enum ) and again allow us to read/write the keyPath property value of an instance taking into account the property should be var and the instance should be var also.
WritableKeyPath can use on both let and var for reference types. Constructing a key path using unsafe expressions can cause the same runtime error as using them on an instance. Here is an example using forced unwrapping expressions (!) and array subscript (index: Int) in key paths.
KeyPaths are for properties. However, you can do effectively the same thing. Because functions are first class types in swift, you can create a reference to handleMainAction and pass it around:
//: Playground - noun: a place where people can play
import UIKit
import XCTest
import PlaygroundSupport
class MyClass {
var bar = 0
private func handleMainAction() -> Int {
bar = bar + 1
return bar
}
func getMyMainAction() -> ()->Int {
return self.handleMainAction
}
}
class AnotherClass {
func runSomeoneElsesBarFunc(passedFunction:() -> Int) {
let result = passedFunction()
print("What I got was \(result)")
}
}
let myInst = MyClass()
let anotherInst = AnotherClass()
let barFunc = myInst.getMyMainAction()
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
This will work fine, and you can pass "barFunc" to any other class or method and it can be used.
You can use MyClass.handleMainAction
as an indirect reference. It gives you a block that take the class instance as the input parameter, and returns corresponding instance method.
let ref = MyClass.handleMainAction //a block that returns the instance method
let myInstance = MyClass()
let instanceMethod = ref(myInstance)
instanceMethod() //invoke the instance method
The point is you can pass around / store the method reference just like what you did with a key path. You just need to supply the actual instance when you need to invoke the method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With