首页 > 解决方案 > KVC的优势

问题描述

我一直试图弄清楚这一点,但无法理解 KVC 的优势,除了:

  1. 编译器检查(从而避免字符串类型的代码)
  2. 与 KVO 一起使用

我不确定除了上面提到的 2 个案例(我知道我可能错了)之外,使用 KVC 是否有任何优势,但我找不到一个!

就像考虑以下代码:

class Profile: NSObject {
    
    @objc var firstName: String
    var lastName: String
    
    init(firstName: String,lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
        super.init()
    }
    
}

let profile1 = Profile(firstName: "John", lastName: "Doe")

profile1.firstName // returns String "John"

profile1.value(forKey: "firstName") // returns Optional<Any> 

let firstNameKey = \Profile.firstName
profile1[keyPath: firstNameKey] /* returns String "John" */

我的意思是我为什么要使用:

让 firstNameKey = \Profile.firstName

profile1[keyPath: firstNameKey] /* 返回字符串 "John" */

代替 :

profile1.firstName // 返回字符串“John”

如果有人有一些代码示例/示例,那么如果他们可以使用 swift 进行解释,那就太好了(因为我的 Objective-C 不好)

标签: swiftswift-keypath

解决方案


您使用的示例不是使用KVCkeyPath本身的最佳情况。

当您使用协议时, keyPath的真正力量 IMO会被释放出来。让我给你举个例子 -

假设您有一个Identifiable只有一个成员的协议 - id. 符合此的每种类型都必须使用id唯一标识它的属性。

protocol Identifiable {
    var id: Int { get }
}

struct Person: Identifiable {
    var id: Int
    var name: String
}

在这里,Person有成员的类型id听起来不太好。考虑另一个 -

struct Book: Identifiable {
    var id: Int
    var title: String
    var author: String 
}

在这里,一本书也可以唯一标识,id但听起来不太好。

这就是keyPath发挥作用的地方。

您可以使用某个名称在协议中定义成员,并让符合的类型为该特定协议成员编写自己的名称。符合类型可以映射或告诉编译器它们的特定成员是使用keyPath替换协议内部的成员。

protocol Identifiable {
    associatedtype ID
    static var id: WritableKeyPath<Self,ID> { get }
}

struct Person: Identifiable {
    static var id = \Person.socialSecurityNumber

    var socialSecurityNumber: Int
    var name: String
}

struct Book: Identifiable {
    static var id = \Book.isbn

    var isbn: String
    var title: String
    var author: String
}

func printID<T: Identifiable>(aType: T) {
    print(aType[keyPath: T.id])
}

printID(aType: Person(socialSecurityNumber: 1234, name: "Shubham Bakshi"))
printID(aType: Book(isbn: "qwertyui", title: "The Theory of Everything", author: "Stephen W. Hawking"))

作为一个额外的优势,您的符合类型可以具有id任何类型 , StringIntInt不仅仅是(如前一种情况)

如果你只想给一个特定的类型id,只说Int,你可以用这个替换我们协议的定义 -

protocol Identifiable {
    static var id: WritableKeyPath<Self,Int> { get }
}

这将强制符合标准的类型Int用作它们的id替代品。

源 - Swift KeyPath - Paul Hudson


推荐阅读