Predicate to NSPredicate conversion fails (not tagged as ObjC)
Follow up to #22 by @HealsCodes:
I've been playing around with Predicates + ManagedModels but always run into a dead-end seemingly because Model properties aren't exposed to the underlying Objective-C runtime so code like this doesn't work:
@Model
final class MyModel: NSManagedObject {
var enabled: Bool
convenience init() {
self.enabled = false
}
}
// the following works if MyModel is created using the traditional NSManagedObject / @NSManaged means
let p = #Predicate<MyModel> { $0.enabled == true }
let predicate = NSPredicate(p) // returns nil, because apparently MyModel.enabled isn't bridged
Likewise a simple NSExpression(forKeyPath: \MyModel.enabled) fails with "Foundation/NSObject.swift:132: Fatal error: Could not extract a String from KeyPath \MyModel.enabled"
The same issue breaks interoperability with packages like PredicateKit which relies on being able to convert AnyKeyPath to String using ObjC bridging internals.
So this is currently generated for the property:
@Model
final class MyModel: NSManagedObject {
@_PersistedProperty
var enabled: Bool
{
set {
setValue(forKey: "enabled", to: newValue)
}
get {
getValue(forKey: "enabled")
}
}
}
And indeed, this is a Swift only property. Looks like just adding @objc will make this work:
@Model
final class MyModel: NSManagedObject {
@objc var enabled2: Bool {
set {
setValue(forKey: "enabled", to: newValue)
}
get {
getValue(forKey: "enabled")
}
}
}
let p = #Predicate<MyModel> { $0.enabled2 == true }
let predicate = NSPredicate(p) // works
print("Predicate:", predicate)
// Predicate: Optional(enabled2 == 1)
This turns out to be more difficult than expected :-) I.e. this is problematic:
enum AddressType: Int {
case home, work
}
@Model
final class Address /*test*/ : NSManagedObject {
var street : String
var type : AddressType
var person : Person
We cannot add @objc to type, because:
Property cannot be marked @objc because its type cannot be represented in Objective-C
Not quite sure how we can figure out whether a node can be represented in ObjC 🤔
I added something to 0.8.14, but I don't think we can fully determine the ObjC convertibility in a macro, as that can't resolve types.
Thank you for putting in all the effort! I'll gladly give 0.8.14 a go once I have time to sit down and work on my own project next.
For me it is already a huge bonus to be able to use key paths this way with types that can be mapped cleanly to Foundation and thus ObjC types.
I had good success manually adding the extra @obj to base types and using that in queries even with PredikateKit 😄
Version 0.8.14 introduced a bug where such a model does no longer compile due to presence of Int? and Double?, as well as a Set of Codable structs.
Compilation Error:
Property cannot be marked @objcbecause its type cannot be represented in Objective-C
@Model
final class AdvancedStoredAccess: NSManagedObject {
var token : String
var expires : Date
var distance: Int?
var avgSpeed: Double?
var sip : AccessSIP
var optionalSip : AccessSIP?
var codableSet : Set<AccessSIP>
}
Added a PR #37 which aims to improve the @objc tagging and fix bugs introduced in 0.8.14