Skip to content

Instantly share code, notes, and snippets.

@Koze
Created March 15, 2020 12:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Koze/2ab02e4f249ce00242f2948f186a3fda to your computer and use it in GitHub Desktop.
Save Koze/2ab02e4f249ce00242f2948f186a3fda to your computer and use it in GitHub Desktop.
Type-safe CKRecord with dynamicMemberLookup
extension CKRecord {
subscript<Root, Value: CKRecordValueProtocol>(dynamicMember keyPath: WritableKeyPath<Root, Value>) -> Value? {
get {
let key = NSExpression(forKeyPath: keyPath).keyPath
return self[key]
}
set {
let key = NSExpression(forKeyPath: keyPath).keyPath
// Fatal error: Could not extract a String from KeyPath Swift.ReferenceWritableKeyPath
self[key] = newValue
}
}
}
@objc protocol MyRecord {
var aaa: Bool { get set }
var bbb: String { get set }
}
@dynamicMemberLookup
protocol MyRecordProtocol {
subscript<Value: CKRecordValueProtocol>(dynamicMember keyPath: WritableKeyPath<MyRecord, Value>) -> Value? { get set }
}
extension CKRecord: MyRecordProtocol {
}
func usage() {
var record = CKRecord(recordType: "Test") as MyRecordProtocol
record.aaa = true
// Xcode infers type as `Bool?`, but NSExpression occur fatal error.
let value = record.aaa
print(value)
}
@Koze
Copy link
Author

Koze commented Mar 15, 2020

This seems good type-safe if it's enable to extract string from keyPath.
See also other ways.
https://gist.github.com/Koze/7fb045148c4772c5c28acb3958192cd9
https://gist.github.com/Koze/f6afb934377717bf34fd285439e86281

@dtrofimov
Copy link

Any ideas on how to fix this crash?

I'm trying to implement a similar utility to access NSDictionary with NSManagedObject properties, and getting the same error. Looks like dynamicMemberLookup provides some different kind of key path, not working with NSExpression for some reason.

@Koze
Copy link
Author

Koze commented Sep 6, 2021

@dtrofimov
This was a bug in Xcode, and has been fixed in Xcode 12.5.
See Xcode 12.5 release notes.
https://developer.apple.com/documentation/xcode-release-notes/xcode-12_5-release-notes

Fixed a crash that occurred when setting a value using a ReferenceWritableKeyPath that was upcast to a WritableKeyPath. (74191390) (FB8999603)

Now you can use the technique of this gist!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment