KVC in swift

Hi,


I have tried below code snippet in a playground and it crashes. Does it is compulsory to add @objc attribute to class?


class SomeClass: NSObject {

var name: String = "Test"

}

var object = SomeClass()

print(object.value(forKey: "name"))



As per Apple doc it says

Reference Link: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107-DontLinkElementID_5


Key-Value Coding with Swift

Swift objects that inherit from

NSObject
or one of its subclasses are key-value coding compliant for their properties by default.


Any input for same will help to clarify core concept.


Thanks in advance.

You must add "@objc" to the property "name", because in Swift 4+, individual properties and methods are not @objc by default (unless they're forced to be: for example, when they implement conformance to an @objc protocol).


If you want your property to also be KVO-compliant so you can observe it, you also need to declare it "dynamic". If it's not declared dynamic, Swift may optimize property access, and KVO change notifications may not be generated.


So, your class should look like this:


class SomeClass: NSObject {
  @objc dynamic var name: String = "Test"
}


Note that you don't have to add @objc to the class, because inheriting from NSObject does that automatically.


There is some information under the heading "Key-Value Observing" here:


https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html


along with some discussions of other common Obj-C design patterns.

Thanks for details.

Hi,


One more thing just wanted to clarify, is this same concept in case of enums? Is there any better way to support KVC using protocol oriented concept throughout the application?



@objc

enum SomeEnum: Int {

case a, b, c

}


class SomeClass: NSObject {

@objc var name: String = "Test"

@objc var category : SomeEnum = .b

}


var object = SomeClass()

print(object.value(forKey: "name"))

print(object.value(forKey: "category"))



Thanks in advance.

It doesn't work, but for an unrelated reason ("Property cannot be marked @objc because its type cannot be represented in Objective-C").


What you do in a situation like this depends on what you need KVC (and KVO) for. You can declare a second property with type Int that contains the rawValue of the enum, and arrange to keep the two properties in sync. That would allow you to share the Int value via KVC/KVO, but you would need to "reconstruct" the enum at the other end, if that's what you want.


KVC/KVO doesn't map very well to Swift, except in a few specific APIs that have work naturally or have been tuned (like the new Swift observer API). That means your code is going to be ugly, if you do anything that happens not to fit.

KVC in swift
 
 
Q