Key-Value Coding (Kvc) with Array/Dictionary in Swift

Key-Value Coding (KVC) with Array/Dictionary in Swift

It seems that KVC on native Swift objects is just not supported. Here's the most elegant workaround I've found:

var swiftarray: Array = []
// Fill the array with objects
var array: NSArray = (swiftarray as NSArray).valueForKeyPath("key.path") as NSArray

What's the difference between Key-Value Coding and NSDictionary?

Key Value Coding is a set of conventions for accessing the contents of an object using string identifiers. KVC compliant classes have properties that follow the KVC naming convention. A number of different technologies are layered on top of KVC and depend on it to function. KVC is implemented as an informal protocol on NSObject. KVC can can be used with all descendants of NSObject, as long as the object's properties are compliant with the KVC naming conventions.

NSDictionary, in contrast, is a Foundation collection class representing a class cluster.

KVC is a fundamental concept in Cocoa, the more you know about it the better your applications will be.

How do I use Key-Value Coding in Swfit 4.0?

To implement KVC support for a property in Swift 4, you need two things:

  1. Since the current implementation of KVC is written in Objective-C, you need the @objc annotation on your property so that Objective-C can see it. This also means that the property's type needs to be compatible with Objective-C.

  2. In addition to exposing the property to Objective-C, you will need to set up your notifications in order for observers to be notified when the property changes. There are three ways to do this:

For stored properties, the easiest thing to do is to add the dynamic keyword like so:

@objc dynamic var foo: String

This will allow Cocoa to use Objective-C magic to automagically generate the needed notifications for you, and is usually what you want. However, if you need finer control, you can also write the notification code manually:

@objc private static let automaticallyNotifiesObserversOfFoo = false
@objc var foo: String {
willSet { self.willChangeValue(for: \.foo) }
didSet { self.didChangeValue(for: \.foo) }
}

The automaticallyNotifiesObserversOf<property name> property is there to signify to the KVC/KVO system that we are handling the notifications ourselves and that Cocoa shouldn't try to generate them for us.

Finally, if your property is not stored, but rather depends on some other property or properties, you need to implement a keyPathsForValuesAffecting<your property name here> method like so:

@objc dynamic var foo: Int
@objc dynamic var bar: Int

@objc private static let keyPathsForValuesAffectingBaz: Set<String> = [
#keyPath(foo), #keyPath(bar)
]
@objc var baz: Int { return self.foo + self.bar }

In the example above, an observer of the baz property will be notified when the value for foo or the value for bar changes.

From array of dictionaries, make array containing values of one key

Yes, use the NSArray -valueForKey: method.

NSArray *extracted = [sourceArray valueForKey:@"a key"];

Accessing values from Dictionaries that are part of an Array in Swift

The way I see it, you would populate a new array of Strings from the cities listed before.

var locations = [String]()

for dictionary in arrayOfDictionaries{
locations.append(dictionary["location"]!)
}

println(locations)

Generate a complete list of key-value coding paths for nested NSDictionary's?

You could recurse through allKeys. A key is a key path, obviously, and then if the value is an NSDictionary you can recurse and append.

- (void) obtainKeyPaths:(id)val intoArray:(NSMutableArray*)arr withString:(NSString*)s {
if ([val isKindOfClass:[NSDictionary class]]) {
for (id aKey in [val allKeys]) {
NSString* path =
(!s ? aKey : [NSString stringWithFormat:@"%@.%@", s, aKey]);
[arr addObject: path];
[self obtainKeyPaths: [val objectForKey:aKey]
intoArray: arr
withString: path];
}
}
}

And here is how to call it:

NSMutableArray* arr = [NSMutableArray array];
[self obtainKeyPaths:d intoArray:arr withString:nil];

Afterwards, arr contains your list of key paths.

Collection Object operator for @firstObject Key-value coding KVC

Currently there's no way to define custom collection operators. However, due to some internal magic there is a funny solution:

    NSSet *testSet = [NSSet setWithArray:@[@"one", @(1)]];

id object = [testSet valueForKey:@"@anyObject"];
NSLog(@"anyObject (%@): %@", NSStringFromClass([object class]), object);

UPD: Forgot to mention another handy trick: you can use @lastObject on NSArray!



Related Topics



Leave a reply



Submit