提问人:CentrumGuy 提问时间:10/16/2023 最后编辑:CentrumGuy 更新时间:10/16/2023 访问量:77
成功将 KVC 与 Swift Structs 结合使用
Successfully using KVC with Swift Structs
问:
我面临着一个非常小众的问题,但希望有人可以帮助我。我在我的项目中使用 KVC 来设置类中的值。此类包含属性,包括一些结构。我能够使用该协议使这些结构兼容(我知道这并不理想,但这是我为此找到的最佳方法)。现在,当我尝试在父类上使用为结构中的一个属性设置值时,它不起作用。经过一些调试,我了解到它将结构桥接到其 Objective-C 等效类并在该 Objective-C 等效类上设置值,但它不会将 Objective-C 类转换回结构并更新父类上的结构。@objc
_ObjectiveCBridgeable
setValue(_:forKeyPath:)
我认为这应该是可能的,如 https://stackoverflow.com/questions/23216673/how-can-i-animate-the-height-of-a-calayer-with-the-origin-coming-from-the-bottom#:~:text=Then%20for%20the%20animation%2C%20you%20simply%20animate%20the%20bounds%20(or%20even%20better%2C%20you%20can%20animate%20%22bounds.size.height%22%2C%20since%20only%20the%20height%20is%20changing)%3A中所说的您可以进行动画处理,您可以在bounds.size.height
CABasicAnimation
这是我的代码(可以在 Swift playground 中运行):
@available(iOS 2.0, *)
@objc public class TestClass: NSObject {
@objc public var x: Int
@objc public var y: Int
@objc public var testStruct = TestStruct(z: 0)
init(x:Int, y: Int) {
self.x = x
self.y = y
}
}
@available(iOS 2.0, *)
public struct TestStruct: _ObjectiveCBridgeable {
public typealias _ObjectiveCType = NSTestStruct
public var z: Int
public init(z: Int) { self.z = z }
public func _bridgeToObjectiveC() -> NSTestStruct {
return NSTestStruct(z: z)
}
public static func _forceBridgeFromObjectiveC(_ source: NSTestStruct, result: inout TestStruct?) {
result = TestStruct(z: source.z)
}
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSTestStruct?) -> TestStruct {
return TestStruct(z: source?.z ?? 0)
}
public static func _conditionallyBridgeFromObjectiveC(_ source: NSTestStruct, result: inout TestStruct?) -> Bool {
result = TestStruct(z: source.z)
return true
}
}
@available(iOS 2.0, *)
@objc public class NSTestStruct: NSObject {
@objc public var z: Int // Updates to "12"
@objc public init(z: Int) {
self.z = z
}
}
var testClass = TestClass(x: 0, y: 0)
testClass.setValue(12, forKeyPath: "testStruct.z")
print(testClass.testStruct.z) // Prints "0", expected "12"
答:
正如 Martin R 所提到的,CABasicAnimation 有一个自定义,允许您设置嵌套属性。我编写了一个自定义程序,它对包含结构体的通用 keyPath 执行相同的操作,这些结构体的类型可直接转换为 Objective-C(相同的属性名称和类型)。这是我的解决方案:setValue(_:forKeyPath:)
setValue(_:forKeyPath:)
public extension NSObject {
func setValueRecursively(_ value: Any?, forKeyPath keyPath: String) {
var currentKeyPath = keyPath
var currentValue: Any? = value
while true {
guard let lastPeriodIndex = currentKeyPath.lastIndex(of: ".") else {
self.setValue(currentValue, forKey: currentKeyPath)
return
}
let parentKeyPath = String(currentKeyPath[currentKeyPath.startIndex ..< lastPeriodIndex])
guard let parentValue = self.value(forKeyPath: parentKeyPath) as? NSObject else { return }
parentValue.setValue(currentValue, forKey: String(currentKeyPath.suffix(currentKeyPath.count-parentKeyPath.count-1)))
currentValue = parentValue
currentKeyPath = parentKeyPath
}
}
}
使用与问题相同的代码,
testClass.setValueRecursively(12, forKeyPath: "testStruct.z")
按预期工作:)
注意:这不适用于 、 和表示为CGSize
CGRect
NSValue
评论
setValue(forKeyPath:)