Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Predicate to NSPredicate conversion fails (not tagged as ObjC) #36

Open
helje5 opened this issue Oct 29, 2024 · 4 comments
Open

Predicate to NSPredicate conversion fails (not tagged as ObjC) #36

helje5 opened this issue Oct 29, 2024 · 4 comments
Labels
bug Something isn't working

Comments

@helje5
Copy link
Contributor

helje5 commented Oct 29, 2024

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.

@helje5
Copy link
Contributor Author

helje5 commented Oct 29, 2024

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)

@helje5 helje5 added the bug Something isn't working label Oct 29, 2024
@helje5
Copy link
Contributor Author

helje5 commented Nov 1, 2024

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 🤔

helje5 added a commit that referenced this issue Nov 1, 2024
Partially addresses issue #36.

This works for hardcoded base types, some Foundation types and
if the property is explicitly tagged as a Relationship.
@helje5
Copy link
Contributor Author

helje5 commented Nov 1, 2024

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.

@HealsCodes
Copy link

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 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants