4

I have been trying to figure this out for a while but cannot understand the advantage of KVC other than :

  1. Compiler checks (thus avoiding stringly typed code)
  2. Used with KVO

I am not sure if there is any advantage of using KVC other than the 2 cases said above (i know i might be wrong) but i could not find one !

Like consider the following code :

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" */

I mean why would i use :

let firstNameKey = \Profile.firstName

profile1[keyPath: firstNameKey] /* returns String "John" */

instead of :

profile1.firstName // returns String "John"

And if someone has some code sample/examples, then if they can explain it using swift , it would be great (as my Objective-C is not good)

Community
  • 1
  • 1
user121095
  • 697
  • 2
  • 6
  • 18
  • Please read [About Key-Value Coding](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/index.html) in the KVC Programming Guide. Most of the aspects are covered there – vadian May 16 '19 at 10:59

1 Answers1

6

The example that you have used is not the optimal case of using KVC or keyPath itself.

The true power, IMO, of keyPath is unleashed when you're working with protocols. Let me give you an example -

Say you have a protocol Identifiable which has only one member - id . Each type that conforms to this, must use id property which uniquely identifies it.

protocol Identifiable {
    var id: Int { get }
}

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

Here, a Person type having a member id doesn't sound too good. Consider another one -

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

Here, as well , a book can be uniquely identified by id but it doesn't sound good.

Here's where keyPath comes into play.

You can define member inside a protocol with some name and let the conforming types write their own name for that particular protocol member. The conforming types can map or tell the compiler that their particular member is the replacement of the one inside the protocol using 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"))

As an added advantage , your conforming type can have id of any type , String, Int rather than Int only (as was in previous case)

If you want to give only a specific type to id, say Int only, you can replace the definition of our protocol with this one -

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

This will force the conforming types to use Int for their id substitute.

Source - Swift KeyPath - Paul Hudson

Shubham Bakshi
  • 552
  • 3
  • 10
  • 1
    How is this better than having `protocol Identifiable{var id:Any{get}}` with `struct Book : Identifiable{var id : Any{return isbn}; var isbn:String}` ? – Ricky Mo May 24 '19 at 05:30
  • Yeah we can have that, but the question was not a comparison , but more use cases of _KVC_ and _keyPath_ – Shubham Bakshi May 24 '19 at 05:40
  • If the use case is not inevitable or superior, what's the point? I too want to see some use cases that KVC is really necessary as I am also wondering the same question. – Ricky Mo May 24 '19 at 05:49
  • Inevitable? Sir, there are not many things in the world of programming that has only one way to do it, there can be many. And if there had been only one way to do a certain thing, would programming be this much fun? We usually use KVC to access a property when we don't know which property we want to access until runtime.You want use cases of KVC, Core data(when not subclassing NSManagedObject), Dictionaries, KeyValuePairs, KVO, UserDefaults – Shubham Bakshi May 24 '19 at 06:16
  • And if you want to learn KVC in depth, I would recommend [this](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107-SW1) . But the complete documentation is in ObjectiveC – Shubham Bakshi May 24 '19 at 06:17
  • So the true answer is "to access a property when we don't know which property we want to access until runtime". As OP (and I) want to know the advantage of KVC and this is it. Thanks. – Ricky Mo May 24 '19 at 07:20