gpt4 book ai didi

swift - 使用反射设置对象属性而不使用 setValue forKey

转载 作者:IT王子 更新时间:2023-10-29 05:13:24 26 4
gpt4 key购买 nike

在 Swift 中不可能使用 .setValue(..., forKey: ...)

  • Int 之类的可空类型字段?
  • 具有 enum 类型的属性
  • 可空对象数组,如 [MyObject?]

对此有一种解决方法,即覆盖对象本身的 setValue forUndefinedKey 方法。

因为我正在编写一个基于反射的通用对象映射器。参见 EVReflection我想尽可能减少这种手动映射。

是否有其他方法可以自动设置这些属性?

可以在我的库中的单元测试中找到解决方法 here这是代码:

class WorkaroundsTests: XCTestCase {
func testWorkarounds() {
let json:String = "{\"nullableType\": 1,\"status\": 0, \"list\": [ {\"nullableType\": 2}, {\"nullableType\": 3}] }"
let status = Testobject(json: json)
XCTAssertTrue(status.nullableType == 1, "the nullableType should be 1")
XCTAssertTrue(status.status == .NotOK, "the status should be NotOK")
XCTAssertTrue(status.list.count == 2, "the list should have 2 items")
if status.list.count == 2 {
XCTAssertTrue(status.list[0]?.nullableType == 2, "the first item in the list should have nullableType 2")
XCTAssertTrue(status.list[1]?.nullableType == 3, "the second item in the list should have nullableType 3")
}
}
}

class Testobject: EVObject {
enum StatusType: Int {
case NotOK = 0
case OK
}

var nullableType: Int?
var status: StatusType = .OK
var list: [Testobject?] = []

override func setValue(value: AnyObject!, forUndefinedKey key: String) {
switch key {
case "nullableType":
nullableType = value as? Int
case "status":
if let rawValue = value as? Int {
status = StatusType(rawValue: rawValue)!
}
case "list":
if let list = value as? NSArray {
self.list = []
for item in list {
self.list.append(item as? Testobject)
}
}
default:
NSLog("---> setValue for key '\(key)' should be handled.")
}
}
}

最佳答案

当我试图解决一个类似的问题时,我找到了解决这个问题的方法——KVO 无法设置纯 Swift 协议(protocol)字段的值。该协议(protocol)必须标记为@objc,这给我的代码库带来了太多痛苦。解决方法是使用 objective-c 运行时查找 Ivar,获取字段偏移量,然后使用指针设置值。此代码适用于 Swift 2.2 中的 Playground :

import Foundation

class MyClass
{
var myInt: Int?
}

let instance = MyClass()

// Look up the ivar, and it's offset
let ivar: Ivar = class_getInstanceVariable(instance.dynamicType, "myInt")
let fieldOffset = ivar_getOffset(ivar)

// Pointer arithmetic to get a pointer to the field
let pointerToInstance = unsafeAddressOf(instance)
let pointerToField = UnsafeMutablePointer<Int?>(pointerToInstance + fieldOffset)

// Set the value using the pointer
pointerToField.memory = 42

assert(instance.myInt == 42)

注意事项:

编辑:https://github.com/wickwirew/Runtime 现在有一个名为Runtime 的框架。它提供了 Swift 4+ 内存布局的纯 Swift 模型,允许它在不调用 Obj C 运行时的情况下安全地计算 ivar_getOffset 的等价物。这允许设置如下属性:

let info = try typeInfo(of: User.self)
let property = try info.property(named: "username")
try property.set(value: "newUsername", on: &user)

在等效功能成为 Swift 本身的一部分之前,这可能是一个很好的前进方式。

关于swift - 使用反射设置对象属性而不使用 setValue forKey,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31589405/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com