可选值上的 Swift KeyPath

4
如果我有

class Info {
    var name: String?
}

class User {
    var info: Info?
}

class WrappedClass {
    var user: User = User()
}


let nameKeyPath = \WrappedClass.user.info?.name //Gets me KeyPath
let referencedNameKeyPath = \WrappedClass.user.info!.name //Gets me ReferenceWritableKeyPath
nameKeyPath 会返回一个无法用于修改名称值的 KeyPath,但是如果我强制解包它,就会得到一个 ReferenceWritableKeyPath,这正是我想要的。
不幸的是,如果使用空值调用 referencedNameKeyPath,则会出现预期崩溃,因为找到了 nil。
我的问题是是否有一种方法可以将 KeyPath 转换为 ReferenceWritableKeyPath 或者在途中进行解包?

1
尽可能使用非可选类型。在类中使用可选类型作为不编写初始化程序的托辞是一个相当糟糕的习惯。 - vadian
很遗憾,在我的情况下这是不可能的。 - Andrew
2个回答

7
你还可以在键路径上使用可选链。在info中创建两个键路径,一个用于user,另一个用于name。
let infoKeyPath = \WrappedClass.user.info

let nameKeyPath = \Info.name

现在,使用可选链和keypath,它将产生 String? 作为结果。
let name = wrappedInstance[keyPath: infoKeyPath]?[keyPath: nameKeyPath]

这就是我要找的。谢谢! - Andrew

2

尝试将关键路径作为计算的可选变量。像这样:

class WrappedClass {
  var user: User = User()

  var nameKeyPath: ReferenceWritableKeyPath<WrappedClass, String?>? {
    guard let _ = user.info else { return nil }
    return \WrappedClass.user.info!.name
  }
}

您仍然会使用force unwrap符号,但它不应该引起任何问题,因为您专门进行了保护。

这样,您就可以安全而方便地使用计算的关键路径:

let instance = WrappedClass()

if let nameKeyPath = instance.nameKeyPath {
  instance[keyPath: nameKeyPath] = "Nikola"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接