我想創建一個例程來簡化綁定一個屬性到另一個,一個非常常見的操作。我使用基於國際志願者組織在斯威夫特4和9的XCode使用keyPath綁定2屬性(觀察)
我希望能夠寫出下面的使用綁定兩個變量及其相應的keyPath
塊:
self.bind(to: \BindMe.myFirstName, from: \BindMe.person.firstName)
這是一個簡化的例子,正在產生各種我無法解決的編譯錯誤。這可能是密鑰路徑的錯誤傳遞到func bind
,但使用keyPath的setValue
也無法編譯。請參閱代碼中的註釋以瞭解我遇到的編譯錯誤。
class Person : NSObject
{
init(firstName:String, lastName:String)
{
self.firstName = firstName
self.lastName = lastName
}
@objc dynamic var firstName:String
@objc dynamic var lastName:String
}
class BindMe : NSObject
{
var observers = [NSKeyValueObservation]()
let person:Person
var myFirstName:String = "<no first name>"
var myLastName:String = "<no last name>"
init(person:Person)
{
self.person = person
self.setupBindings()
}
func setupBindings()
{
self.bind(to: \BindMe.myFirstName, from: \BindMe.person.firstName)
self.bind(to: \BindMe.myLastName, from: \BindMe.person.lastName)
}
// this func declaration is likely incorrect
func bind<T,Value,Value2>(to targetKeyPath:KeyPath<T,Value>, from sourceKeyPath:KeyPath<T,Value2>)
{
// Error: Generic parameter 'Value' could not be inferred
self.observers.append(self.observe(sourceKeyPath, options: [.initial,.new], changeHandler: { (object, change) in
// Error: Cannot convert value of type 'KeyPath<T, Value>' to expected argument type 'String'
self.setValue(change.newValue, forKeyPath: targetKeyPath)
}))
}
}
編輯
的answer below有助於初始編譯問題。然而,爲了實現這個功能,我需要能夠將管道插入到超類中,如下所示。這將使用它很簡單的把課,但我仍然編譯錯誤掙扎:
Cannot invoke 'bind' with an argument list of type '(to: WritableKeyPath<PersonWatcher, PersonWatcher>, from: WritableKeyPath<PersonWatcher, PersonWatcher>)'
如果我通過一個通用的類型T的綁定程序,我得到這個錯誤,而不是:
Type 'BindBase' has no subscript members
class BindBase :NSObject
{
var observers = [NSKeyValueObservation]()
func bind<Value>(to targetKeyPath: ReferenceWritableKeyPath<BindBase, Value>, from sourceKeyPath: KeyPath<BindBase, Value>)
{
self.observers.append(self.observe(sourceKeyPath, options: [.initial, .new], changeHandler: { (object, change) in
self[keyPath: targetKeyPath] = change.newValue!
}))
}
}
class PersonWatcher : BindBase
{
@objc dynamic var person: Person
@objc var myFirstName: String = "<no first name>"
@objc var myLastName: String = "<no last name>"
init(person: Person) {
self.person = person
super.init()
self.bind(to: \PersonWatcher.myFirstName, from: \PersonWatcher.person.firstName)
self.bind(to: \PersonWatcher.myLastName, from: \PersonWatcher.person.lastName)
}
}
這需要我更加接近。它現在編譯並且爲這個級別的類工作,但不幸的是我不需要完成最終的遊戲。我真的想把這個管道推到一個超類中,所以使用變得非常簡單。我會在上面更新我的問題,以顯示我想要實現的更詳細的結構。 –
BindBase的更新很好,現在允許我使用一個非常簡單的單線程綁定調用。 –