drewmccormack / ensembles

A synchronization framework for Core Data.
MIT License
1.63k stars 132 forks source link

Multiple NSEntityDescriptions claim the NSManagedObject subclass ... #275

Closed UberJason closed 5 years ago

UberJason commented 5 years ago

Hi Drew,

In Xcode 10 I'm getting this warning in the console when I save new objects to Core Data. (Context: I have an NSManagedObject subclass called CDEvent which I'm creating and saving in this case, and my Core Data stack lives in a shared framework called FeedingKit.)

2018-07-26 16:34:30.268969-0400 Feeding[2936:3350281] [error] warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'FeedingKit.CDEvent' so +entity is unable to disambiguate.
CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'FeedingKit.CDEvent' so +entity is unable to disambiguate.
2018-07-26 16:34:30.269522-0400 Feeding[2936:3350281] [error] warning:       'CDEvent' (0x7ffcb082c570) from NSManagedObjectModel (0x7ffcae58a4c0) claims 'FeedingKit.CDEvent'.
CoreData: warning:       'CDEvent' (0x7ffcb082c570) from NSManagedObjectModel (0x7ffcae58a4c0) claims 'FeedingKit.CDEvent'.
2018-07-26 16:34:30.269984-0400 Feeding[2936:3350281] [error] warning:       'CDEvent' (0x7ffcb0c09380) from NSManagedObjectModel (0x7ffcb0c06530) claims 'FeedingKit.CDEvent'.
CoreData: warning:       'CDEvent' (0x7ffcb0c09380) from NSManagedObjectModel (0x7ffcb0c06530) claims 'FeedingKit.CDEvent'.

I investigated a little bit using the memory graph debugger and noticed that there are three NSManagedObjectModels while my app is running. One of them comes from my own Core Data stack, and two of them come from Ensembles (CDEPersistentStoreEnsemble has a managedObjectModel, and CDEEventStore has a managedObjectContext that points to a persistentStoreEnsemble which points to a managedObjectModel). The two managed object models that the warnings reference correspond to the one from my own Core Data stack, and the CDEPersistentStoreEnsemble's directly-owned managedObjectModel.

So far, I haven't noticed this warning actually causing any problems - my app and Ensembles work as desired. The warning is disconcerting, though, and I'm not sure if you're already aware of it and/or have an easy solution to fix or suppress it. Any ideas?

drewmccormack commented 5 years ago

How are you creating the model object? You should not use the merged model method, but load it with the file initializer.

Could also have to do with Swift modules.

Kind regards, Drew

On 26 Jul 2018, at 22:43, Jason Ji notifications@github.com wrote:

Hi Drew,

In Xcode 10 I'm getting this warning in the console when I save new objects to Core Data. (Context: I have an NSManagedObject subclass called CDEvent which I'm creating and saving in this case, and my Core Data stack lives in a shared framework called FeedingKit.)

2018-07-26 16:34:30.268969-0400 Feeding[2936:3350281] [error] warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'FeedingKit.CDEvent' so +entity is unable to disambiguate. CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'FeedingKit.CDEvent' so +entity is unable to disambiguate. 2018-07-26 16:34:30.269522-0400 Feeding[2936:3350281] [error] warning: 'CDEvent' (0x7ffcb082c570) from NSManagedObjectModel (0x7ffcae58a4c0) claims 'FeedingKit.CDEvent'. CoreData: warning: 'CDEvent' (0x7ffcb082c570) from NSManagedObjectModel (0x7ffcae58a4c0) claims 'FeedingKit.CDEvent'. 2018-07-26 16:34:30.269984-0400 Feeding[2936:3350281] [error] warning: 'CDEvent' (0x7ffcb0c09380) from NSManagedObjectModel (0x7ffcb0c06530) claims 'FeedingKit.CDEvent'. CoreData: warning: 'CDEvent' (0x7ffcb0c09380) from NSManagedObjectModel (0x7ffcb0c06530) claims 'FeedingKit.CDEvent'. I investigated a little bit using the memory graph debugger and noticed that there are in fact three NSManagedObjectModels while my app is running. One of them comes from my own Core Data stack, and two of them come from Ensembles (CDEPersistentStoreEnsemble has a managedObjectModel, and CDEEventStore has a managedObjectContext that points to a persistentStoreEnsemble which points to a managedObjectModel).

So far, I haven't noticed this warning actually causing any problems - my app and Ensembles work as desired. The warning is disconcerting, though, and I'm not sure if you're already aware of it and/or have an easy solution to fix or suppress it. Any ideas?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

UberJason commented 5 years ago

@drewmccormack I'm creating the model object the same way Ensembles is, I believe - by using init(contentsOfURL:).

I'm curious about your comment about Swift modules. How do you think that could affect things? In my xcdatamodeld file, I have the module for my Core Data object defined as Current Product Module. Really, this is a tricky one for me to debug because I have very little insight into how Core Data works under the hood, including the relationship between NSEntityDescription and NSManagedObjectModel.

UberJason commented 5 years ago

Actually, your comment about asking about the model object helped me to realize I need to be researching NSManagedObjectModel and NSEntityDescription, and I realized after reading up on the documentation about those two classes what the problem was. I was creating my managed objects using the convenience initializer init(context:), which probably calls into the designated initializer init(entity:insertInto:).

If I create an entity description myself and use it to call the designated initializer, the warning is no longer generated. I guess whatever entity description they try to use in that convenience method was getting confused by the multiple managed object models. Just leaving this explanation here in case anyone else stumbles into this warning and searches the Ensembles issues for something like it.

Anyway, resolved - thank you for your comment, which was helpful!

drewmccormack commented 5 years ago

Ah, good catch. Glad you found it.

On 29 Jul 2018, at 04:06, Jason Ji notifications@github.com wrote:

Actually, your comment about asking about the model object helped me to realize I need to be researching NSManagedObjectModel and NSEntityDescription, and I realized after reading up on the documentation about those two classes what the problem was. I was creating my managed objects using the convenience initializer init(context:) https://developer.apple.com/documentation/coredata/nsmanagedobject/1640602-init?changes=_2, which probably calls into the designated initializer init(entity:insertInto:) https://developer.apple.com/documentation/coredata/nsmanagedobject/1506357-init?changes=_2.

If I create an entity description myself and use it to call the designated initializer, the warning is no longer generated. I guess whatever entity description they try to use in that convenience method was getting confused by the multiple managed object models.

Anyway, resolved - thank you for your comment, which was helpful!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-408646755, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEuABSBG4k0awDaQBoQoWIWn1VhsBQtks5uLRiLgaJpZM4VihCJ.

shaps80 commented 5 years ago

I had the same issue recently so I made a simple extension on NSManagedObject to 'override' the default behaviour.

import CoreData

public extension NSManagedObject {

    convenience init(context: NSManagedObjectContext) {
        let name = String(describing: type(of: self))
        let entity = NSEntityDescription.entity(forEntityName: name, in: context)!
        self.init(entity: entity, insertInto: context)
    }

}

Posting here in case anyone else comes across this. This way you don't need to update any of the call-sites. 👍

FYI this approach assumes your class names match the entity name exactly.

ksoftllc commented 5 years ago

Just a comment to @shaps80 that it is probably best not to override the preferred initializer and instead provide a new convenience initializer, i.e. convenience init(using context: NSManagedObjectContext) that does the same as what you describe.

shaps80 commented 5 years ago

@ksoftllc fair call 😬

ksoftllc commented 5 years ago

@shaps80 Your suggestion has saved me twice! Great call.

pascalfribi commented 3 years ago

Hi Drew,

I stumbled across this issue as well, and the problem really is, that the managedObjectModel should not be loaded more than one time. I have these strange crashes as well when using NSManagedObject.init(entity:insertIntoContext:). In some classes it works, in others it does not.

And it does only crash, when I have ensembles enabled. When it is disabled then it never crashes.

So I experimentally just changed the API to provide the NSManagedObjectModel instead of the URL to the model, so that Ensembles does not need to load it (again). After that my code just worked.

I have found multiple entries in Stack Overflow that talk about this problem.

So the real fix is, that the API of Ensembles should be changed to using the already loaded managed object model. This would permanently fix this issue.

What do you think?

drewmccormack commented 3 years ago

I don’t think that allows Ensembles to do a version check, which is the reason we get the URL. Ensembles needs to be able to access all the model versions, not just the most recent.

There should be no user loading a model more than once, but maybe there is a thread issue. Perhaps we can ensure the model is loaded on the main thread.

Drew

On 11 Apr 2021, at 14:35, pascalfribi @.***> wrote:

 Hi Drew,

I stumbled across this issue as well, and the problem really is, that the managedObjectModel should not be loaded more than one time. I have these strange crashes as well when using NSManagedObject.init(entity:insertIntoContext:). In some classes it works, in others it does not.

And it does only crash, when I have ensembles enabled. When it is disabled then it never crashes.

So I experimentally just changed the API to provide the NSManagedObjectModel instead of the URL to the model, so that Ensembles does not need to load it (again). After that my code just worked.

I have found multiple entries in Stack Overflow that talk about this problem.

So the real fix is, that the API of Ensembles should be changed to using the already loaded managed object model. This would permanently fix this issue.

What do you think?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

pascalfribi commented 3 years ago

In my case the model is loaded on the main thread. Also Ensembles loads the model on the main thread. So this is not the issue.

But I understand your issue. What about changing the API to provide both? We could still leave the old API for backwards compatibility and provide a Deprecated indication so that we do not break all the apps. And then introduce the new API which provides both model and modelURL.

What do you think?

On 11 Apr 2021, at 14:58, Drew McCormack @.***> wrote:

I don’t think that allows Ensembles to do a version check, which is the reason we get the URL. Ensembles needs to be able to access all the model versions, not just the most recent.

There should be no user loading a model more than once, but maybe there is a thread issue. Perhaps we can ensure the model is loaded on the main thread.

Drew

On 11 Apr 2021, at 14:35, pascalfribi @.***> wrote:

 Hi Drew,

I stumbled across this issue as well, and the problem really is, that the managedObjectModel should not be loaded more than one time. I have these strange crashes as well when using NSManagedObject.init(entity:insertIntoContext:). In some classes it works, in others it does not.

And it does only crash, when I have ensembles enabled. When it is disabled then it never crashes.

So I experimentally just changed the API to provide the NSManagedObjectModel instead of the URL to the model, so that Ensembles does not need to load it (again). After that my code just worked.

I have found multiple entries in Stack Overflow that talk about this problem.

So the real fix is, that the API of Ensembles should be changed to using the already loaded managed object model. This would permanently fix this issue.

What do you think?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe. — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817303896, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPAO5BGCUC4DH57QHDVKH3TIGMHFANCNFSM4FMKCCEQ.

drewmccormack commented 3 years ago

I don’t think that will work. The URL is needed to load each version in the model, so Ensembles will still load the model again. It can’t use the model you pass to check for compatibility, because it is only the most recent model.

If you can find a way to do it, put in a PR and I am happy to look at it.

To me, this is a very poor API from Apple. They provide the means to load a model as much as you like, in different situations. There should be no assumption that an app only loads a model once. There is a similar problem with the mergedModel, which will just take any core data model it finds and put it all together, including the internal Ensembles model!

Drew

On 11 Apr 2021, at 15:12, pascalfribi @.***> wrote:

In my case the model is loaded on the main thread. Also Ensembles loads the model on the main thread. So this is not the issue.

But I understand your issue. What about changing the API to provide both? We could still leave the old API for backwards compatibility and provide a Deprecated indication so that we do not break all the apps. And then introduce the new API which provides both model and modelURL.

What do you think?

On 11 Apr 2021, at 14:58, Drew McCormack @.***> wrote:

I don’t think that allows Ensembles to do a version check, which is the reason we get the URL. Ensembles needs to be able to access all the model versions, not just the most recent.

There should be no user loading a model more than once, but maybe there is a thread issue. Perhaps we can ensure the model is loaded on the main thread.

Drew

On 11 Apr 2021, at 14:35, pascalfribi @.***> wrote:

 Hi Drew,

I stumbled across this issue as well, and the problem really is, that the managedObjectModel should not be loaded more than one time. I have these strange crashes as well when using NSManagedObject.init(entity:insertIntoContext:). In some classes it works, in others it does not.

And it does only crash, when I have ensembles enabled. When it is disabled then it never crashes.

So I experimentally just changed the API to provide the NSManagedObjectModel instead of the URL to the model, so that Ensembles does not need to load it (again). After that my code just worked.

I have found multiple entries in Stack Overflow that talk about this problem.

So the real fix is, that the API of Ensembles should be changed to using the already loaded managed object model. This would permanently fix this issue.

What do you think?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe. — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817303896, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPAO5BGCUC4DH57QHDVKH3TIGMHFANCNFSM4FMKCCEQ.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817305910, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAS4ABPEN4AB3GUSXUQCRTTIGN43ANCNFSM4FMKCCEQ.

pascalfribi commented 3 years ago

I agree on the poor design from Apple’s side. Core Data has some strange issues that are really hard to debug.

The even stranger thing is, that the other loads in ensembles of the managed object model do not seem to bother at all. Do not ask me why!

I will make some more tests to see, if with this API change I can permanently solve the issue. If it works I will provide the Pull request.

Pascal

On 11 Apr 2021, at 15:46, Drew McCormack @.***> wrote:

I don’t think that will work. The URL is needed to load each version in the model, so Ensembles will still load the model again. It can’t use the model you pass to check for compatibility, because it is only the most recent model.

If you can find a way to do it, put in a PR and I am happy to look at it.

To me, this is a very poor API from Apple. They provide the means to load a model as much as you like, in different situations. There should be no assumption that an app only loads a model once. There is a similar problem with the mergedModel, which will just take any core data model it finds and put it all together, including the internal Ensembles model!

Drew

On 11 Apr 2021, at 15:12, pascalfribi @.***> wrote:

In my case the model is loaded on the main thread. Also Ensembles loads the model on the main thread. So this is not the issue.

But I understand your issue. What about changing the API to provide both? We could still leave the old API for backwards compatibility and provide a Deprecated indication so that we do not break all the apps. And then introduce the new API which provides both model and modelURL.

What do you think?

On 11 Apr 2021, at 14:58, Drew McCormack @.***> wrote:

I don’t think that allows Ensembles to do a version check, which is the reason we get the URL. Ensembles needs to be able to access all the model versions, not just the most recent.

There should be no user loading a model more than once, but maybe there is a thread issue. Perhaps we can ensure the model is loaded on the main thread.

Drew

On 11 Apr 2021, at 14:35, pascalfribi @.***> wrote:

 Hi Drew,

I stumbled across this issue as well, and the problem really is, that the managedObjectModel should not be loaded more than one time. I have these strange crashes as well when using NSManagedObject.init(entity:insertIntoContext:). In some classes it works, in others it does not.

And it does only crash, when I have ensembles enabled. When it is disabled then it never crashes.

So I experimentally just changed the API to provide the NSManagedObjectModel instead of the URL to the model, so that Ensembles does not need to load it (again). After that my code just worked.

I have found multiple entries in Stack Overflow that talk about this problem.

So the real fix is, that the API of Ensembles should be changed to using the already loaded managed object model. This would permanently fix this issue.

What do you think?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe. — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817303896, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPAO5BGCUC4DH57QHDVKH3TIGMHFANCNFSM4FMKCCEQ.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817305910, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAS4ABPEN4AB3GUSXUQCRTTIGN43ANCNFSM4FMKCCEQ.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817310552, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPAO5BHZJN6IBY7CGFXIWTTIGR4LANCNFSM4FMKCCEQ.

drewmccormack commented 3 years ago

The issue isn’t really Core Data per se. It always worked before. The problem appeared when they added Swift support. In my view, they tried to be too cute, and their API is incomplete. I guess they were trying to make it super easy, and it is, but as soon as you want to do something a bit more advanced, it all breaks down.

Drew

On 11 Apr 2021, at 16:09, pascalfribi @.***> wrote:

I agree on the poor design from Apple’s side. Core Data has some strange issues that are really hard to debug.

The even stranger thing is, that the other loads in ensembles of the managed object model do not seem to bother at all. Do not ask me why!

I will make some more tests to see, if with this API change I can permanently solve the issue. If it works I will provide the Pull request.

Pascal

On 11 Apr 2021, at 15:46, Drew McCormack @.***> wrote:

I don’t think that will work. The URL is needed to load each version in the model, so Ensembles will still load the model again. It can’t use the model you pass to check for compatibility, because it is only the most recent model.

If you can find a way to do it, put in a PR and I am happy to look at it.

To me, this is a very poor API from Apple. They provide the means to load a model as much as you like, in different situations. There should be no assumption that an app only loads a model once. There is a similar problem with the mergedModel, which will just take any core data model it finds and put it all together, including the internal Ensembles model!

Drew

On 11 Apr 2021, at 15:12, pascalfribi @.***> wrote:

In my case the model is loaded on the main thread. Also Ensembles loads the model on the main thread. So this is not the issue.

But I understand your issue. What about changing the API to provide both? We could still leave the old API for backwards compatibility and provide a Deprecated indication so that we do not break all the apps. And then introduce the new API which provides both model and modelURL.

What do you think?

On 11 Apr 2021, at 14:58, Drew McCormack @.***> wrote:

I don’t think that allows Ensembles to do a version check, which is the reason we get the URL. Ensembles needs to be able to access all the model versions, not just the most recent.

There should be no user loading a model more than once, but maybe there is a thread issue. Perhaps we can ensure the model is loaded on the main thread.

Drew

On 11 Apr 2021, at 14:35, pascalfribi @.***> wrote:

 Hi Drew,

I stumbled across this issue as well, and the problem really is, that the managedObjectModel should not be loaded more than one time. I have these strange crashes as well when using NSManagedObject.init(entity:insertIntoContext:). In some classes it works, in others it does not.

And it does only crash, when I have ensembles enabled. When it is disabled then it never crashes.

So I experimentally just changed the API to provide the NSManagedObjectModel instead of the URL to the model, so that Ensembles does not need to load it (again). After that my code just worked.

I have found multiple entries in Stack Overflow that talk about this problem.

So the real fix is, that the API of Ensembles should be changed to using the already loaded managed object model. This would permanently fix this issue.

What do you think?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe. — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817303896, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPAO5BGCUC4DH57QHDVKH3TIGMHFANCNFSM4FMKCCEQ.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817305910, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAS4ABPEN4AB3GUSXUQCRTTIGN43ANCNFSM4FMKCCEQ.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817310552, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPAO5BHZJN6IBY7CGFXIWTTIGR4LANCNFSM4FMKCCEQ.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817314060, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAS4ACY6FJQJ5IL6OIGBLLTIGUR7ANCNFSM4FMKCCEQ.

pascalfribi commented 3 years ago

I agree and they just do not fix it. This is a longstanding problem.

I even tried to move to the new way to create the stores with NSPersistentContainer, but also this does not solve this issue.

Pascal

On 11 Apr 2021, at 16:27, Drew McCormack @.***> wrote:

The issue isn’t really Core Data per se. It always worked before. The problem appeared when they added Swift support. In my view, they tried to be too cute, and their API is incomplete. I guess they were trying to make it super easy, and it is, but as soon as you want to do something a bit more advanced, it all breaks down.

Drew

On 11 Apr 2021, at 16:09, pascalfribi @.***> wrote:

I agree on the poor design from Apple’s side. Core Data has some strange issues that are really hard to debug.

The even stranger thing is, that the other loads in ensembles of the managed object model do not seem to bother at all. Do not ask me why!

I will make some more tests to see, if with this API change I can permanently solve the issue. If it works I will provide the Pull request.

Pascal

On 11 Apr 2021, at 15:46, Drew McCormack @.***> wrote:

I don’t think that will work. The URL is needed to load each version in the model, so Ensembles will still load the model again. It can’t use the model you pass to check for compatibility, because it is only the most recent model.

If you can find a way to do it, put in a PR and I am happy to look at it.

To me, this is a very poor API from Apple. They provide the means to load a model as much as you like, in different situations. There should be no assumption that an app only loads a model once. There is a similar problem with the mergedModel, which will just take any core data model it finds and put it all together, including the internal Ensembles model!

Drew

On 11 Apr 2021, at 15:12, pascalfribi @.***> wrote:

In my case the model is loaded on the main thread. Also Ensembles loads the model on the main thread. So this is not the issue.

But I understand your issue. What about changing the API to provide both? We could still leave the old API for backwards compatibility and provide a Deprecated indication so that we do not break all the apps. And then introduce the new API which provides both model and modelURL.

What do you think?

On 11 Apr 2021, at 14:58, Drew McCormack @.***> wrote:

I don’t think that allows Ensembles to do a version check, which is the reason we get the URL. Ensembles needs to be able to access all the model versions, not just the most recent.

There should be no user loading a model more than once, but maybe there is a thread issue. Perhaps we can ensure the model is loaded on the main thread.

Drew

On 11 Apr 2021, at 14:35, pascalfribi @.***> wrote:

 Hi Drew,

I stumbled across this issue as well, and the problem really is, that the managedObjectModel should not be loaded more than one time. I have these strange crashes as well when using NSManagedObject.init(entity:insertIntoContext:). In some classes it works, in others it does not.

And it does only crash, when I have ensembles enabled. When it is disabled then it never crashes.

So I experimentally just changed the API to provide the NSManagedObjectModel instead of the URL to the model, so that Ensembles does not need to load it (again). After that my code just worked.

I have found multiple entries in Stack Overflow that talk about this problem.

So the real fix is, that the API of Ensembles should be changed to using the already loaded managed object model. This would permanently fix this issue.

What do you think?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe. — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817303896, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPAO5BGCUC4DH57QHDVKH3TIGMHFANCNFSM4FMKCCEQ.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817305910, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAS4ABPEN4AB3GUSXUQCRTTIGN43ANCNFSM4FMKCCEQ.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817310552, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPAO5BHZJN6IBY7CGFXIWTTIGR4LANCNFSM4FMKCCEQ.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817314060, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAS4ACY6FJQJ5IL6OIGBLLTIGUR7ANCNFSM4FMKCCEQ.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/drewmccormack/ensembles/issues/275#issuecomment-817316837, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPAO5ADK2UHLO3G5HM6W6LTIGWWZANCNFSM4FMKCCEQ.

yunsanch commented 1 year ago

hello im getting this same error, would you anyone be able to sugggest what to change in my code so that error goes again properly? ` class TailorPersistentController: ObservableObject {

var persistentContainer = NSPersistentContainer(name: "Model")
private var clientFetchRequest = CustomerCD.fetchRequest()
private var measurestFetchRequest = MeasurementsCD.fetchRequest()
private var jobsEventFetchRequest = JobsDueCD.fetchRequest()

@Published var editTask: JobsDueCD?
@Published var jobsEventDue: JobsEvents?

init() {
    persistentContainer.loadPersistentStores { storeDescription, error in
        if let error = error {
            print("error = \(error)")
        }
    }

}

func saveCustomerToCoreData(customer: CustomersMeasurementsAndDetails) -> UUID {
    let managedObjectContext = persistentContainer.viewContext

    let id = UUID()
    let customerCD = CustomerCD(context: managedObjectContext)
    customerCD.fullName = customer.clientInfo.fullName
    customerCD.gender =  customer.clientInfo.gender?.rawValue
    customerCD.id = id
    customerCD.phone = customer.clientInfo.phone
    customerCD.comments = customer.clientInfo.comments

    // 5. save changes
    try? managedObjectContext.save()

    return id  
}
//save pants measurements
func savePantsMeasurementsToCoreData(customerMeasurements: CustomersMeasurementsAndDetails.PantsMeasuresDetails,
                                customerId: UUID) {

    let managedObjectContext = persistentContainer.viewContext

    //MARK: done to be able to save the pants to the existing customer
    let findClientFetchRequest = CustomerCD.fetchRequest()
    let searchPredicate = NSPredicate(
        format: "id == %@", customerId as CVarArg
    )

    findClientFetchRequest.predicate = searchPredicate

    let clientsCDList = try? managedObjectContext.fetch(findClientFetchRequest)

    guard let clientsCDList = clientsCDList else {
        return
    }

    let customerCD = clientsCDList.first

    let measurementsCD = MeasurementsCD(context: managedObjectContext)
    measurementsCD.clothType = ClothType.pants.rawValue
    measurementsCD.customerID = customerId
    measurementsCD.forCustomer = customerCD
    measurementsCD.id = UUID()
    measurementsCD.trouserRoll = customerMeasurements.trouserRoll
    measurementsCD.knee = customerMeasurements.knee
    measurementsCD.flyFrontKnuckle = customerMeasurements.flyFrontKnuckle
    measurementsCD.hips = customerMeasurements.hips
    measurementsCD.waist = customerMeasurements.waist
    measurementsCD.length = customerMeasurements.length
    measurementsCD.rearKnuckleLength = customerMeasurements.rearKnuckleLength
    measurementsCD.otherPants = customerMeasurements.other
    // 5. save changes
    try? managedObjectContext.save()
}

//save job due events
func saveJobEFormToCoreData(jobsEventDue: JobsEvents
                                )-> UUID {

    let managedObjectContext = persistentContainer.viewContext

    let jodsDueCD = JobsDueCD(context: managedObjectContext)
    let id = UUID()

    jodsDueCD.clothingType = jobsEventDue.jobsEventType.rawValue
    jodsDueCD.isCompleted = jobsEventDue.isComplete
    jodsDueCD.date = jobsEventDue.datetime
    jodsDueCD.customerName = jobsEventDue.customerName
    jodsDueCD.clothingType = jobsEventDue.taskType
    jodsDueCD.pieacesClothingtoMake = jobsEventDue.numPieacesOfClothingDue
    jodsDueCD.numPants = jobsEventDue.numPants
    jodsDueCD.numJackets = jobsEventDue.numJacket
    jodsDueCD.numDress = jobsEventDue.numDress
    jodsDueCD.numShorts = jobsEventDue.numShorts
    jodsDueCD.numSkirts = jobsEventDue.numSkirts
    jodsDueCD.amountDue = jobsEventDue.totalDue
    jodsDueCD.amountPaid = jobsEventDue.amountPaid
    jodsDueCD.notes = jobsEventDue.note

    // 5. save changes
    try? managedObjectContext.save()

    return id
}

func fetchClientsFromCoreData() -> [CustomersMeasurementsAndDetails] {

    let clientNameSortDescriptor = NSSortDescriptor(key: "fullName",
                                                       ascending: true)

    clientFetchRequest.sortDescriptors = [clientNameSortDescriptor]
    let clientsCDList = try? persistentContainer.viewContext.fetch(clientFetchRequest)
    var convertedClients: [CustomersMeasurementsAndDetails] = []

    guard let clientsCDList = clientsCDList else {
        return []
    }

    for clientCD in clientsCDList {

        let client = CustomersMeasurementsAndDetails(id: clientCD.id?.uuidString ?? "", clientInfo: CustomersMeasurementsAndDetails.ClientInfo(fullName: clientCD.fullName ?? "", phone: clientCD.phone ?? "", comments: clientCD.comments ?? "")
                                                         , pantsMeasurment: CustomersMeasurementsAndDetails.PantsMeasuresDetails(id:  "", clothType: "", waist: "", hips: "", flyFrontKnuckle:  "", knee: "" , trouserRoll: "", length: "" , rearKnuckleLength:  "", other: "" )
        )
        convertedClients.append(client)

    }
    print("checking whats inside of this \(convertedClients)")

    return convertedClients

    }

//fetch events
func fetchEventsFromCoreData(currentTab: String) -> [JobsEvents] {
    // MARK: Predicate to Filter current date Tasks
    let calendar = Calendar.current
    var predicate: NSPredicate!
    if currentTab == "Today"{
        let today = calendar.startOfDay(for: Date())
        let tommorow = calendar.date(byAdding: .day, value: 1, to: today)!

        // Filter Key
        let filterKey = "date"

        // This will fetch task between today and tommorow which is 24 HRS
        // 0-false, 1-true
        predicate = NSPredicate(format: "\(filterKey) >= %@ AND \(filterKey) < %@ AND isCompleted == %i", argumentArray: [today,tommorow,0])
    }else if currentTab == "Upcoming"{
        let today = calendar.startOfDay(for: calendar.date(byAdding: .day, value: 1, to: Date())!)
        let tommorow = Date.distantFuture

        // Filter Key
        let filterKey = "date"

        // This will fetch task between today and tommorow which is 24 HRS
        // 0-false, 1-true

        predicate = NSPredicate(format: "\(filterKey) >= %@ AND \(filterKey) < %@ AND isCompleted == %i", argumentArray: [today,tommorow,0])
    }else if currentTab == "Delayed"{
        let today = calendar.startOfDay(for: Date())
        let past = Date.distantPast

        // Filter Key
        let filterKey = "date"

        // This will fetch task between today and tommorow which is 24 HRS
        // 0-false, 1-true
        predicate = NSPredicate(format: "\(filterKey) >= %@ AND \(filterKey) < %@ AND isCompleted == %i", argumentArray: [past,today,0])
    }
    else{
        // 0-false, 1-true
        predicate = NSPredicate(format: "isCompleted == %i", argumentArray: [1])
    }

    jobsEventFetchRequest.sortDescriptors = [.init(keyPath: \JobsDueCD.date, ascending: false)]

    let jobseventsCDList = try? persistentContainer.viewContext.fetch(jobsEventFetchRequest)
    var convertedjobevents: [JobsEvents] = []

    guard let jobseventsCDList = jobseventsCDList else {
        return []
    }

    for eventsCD in jobseventsCDList {

        let events =

        JobsEvents(amountPaid: eventsCD.amountPaid ?? "",
                   totalDue: eventsCD.amountDue ?? "",
                   datetime: eventsCD.date ?? Date(),
                   note: eventsCD.notes ?? "",
                   numPieacesOfClothingDue: eventsCD.pieacesClothingtoMake ?? "",
                   numPants: eventsCD.numPants ?? "",
                   numjacket: eventsCD.numJackets ?? "",
                   numShorts: eventsCD.numShorts ?? "",
                   numskirts: eventsCD.numSkirts ?? "",
                   numDress: eventsCD.numDress ?? "",
                   isComplete: eventsCD.isCompleted,
                   taskType: eventsCD.clothingType ?? "",
                   customerName: eventsCD.customerName ?? "",
                   clothToMake: eventsCD.clothingToMake ?? ""
        )

        convertedjobevents.append(events)
    }

    return convertedjobevents

    }

} `

drewmccormack commented 1 year ago

I'm not that familiar with NSPersistentContainer, but my guess is that it is just using the default models, merging them all into one. With Ensembles, it is necessary that you keep the models apart, because Ensembles has its own Core Data models.

There should be a way with the persistent container to setup your own model, using the URL of your momd file, rather than letting the container look for all models. Take a look and google around for how you can setup the model for the container. (ChatGPT may even be able to write you code for this.)

drewmccormack commented 1 year ago

Here is code from ChatGPT. Don't know if it is correct, but probably is reasonable...

Yes, I can certainly help you with that! Here's an example Swift code that sets up an NSPersistentContainer for Core Data using a specific model file:

import CoreData

// Specify the name of your Core Data model file (without the file extension)
let modelName = "MyCoreDataModel"

// Get the URL of the specified model file in your app bundle
guard let modelURL = Bundle.main.url(forResource: modelName, withExtension: "momd") else {
    fatalError("Failed to find model file with name: \(modelName).")
}

// Initialize an NSManagedObjectModel instance with the specified model file
guard let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL) else {
    fatalError("Failed to initialize managed object model with URL: \(modelURL).")
}

// Initialize an NSPersistentContainer with the specified managed object model
let persistentContainer = NSPersistentContainer(name: modelName, managedObjectModel: managedObjectModel)

// Load the persistent store for the container
persistentContainer.loadPersistentStores { storeDescription, error in
    if let error = error as NSError? {
        fatalError("Failed to load persistent store: \(error), \(error.userInfo)")
    }
}

In this example, you first specify the name of your Core Data model file (without the file extension) in a variable called modelName. Then, you get the URL of the specified model file in your app bundle using the Bundle.main.url(forResource:withExtension:) method.

Next, you initialize an NSManagedObjectModel instance with the specified model file URL using the NSManagedObjectModel(contentsOf:) method.

Then, you initialize an NSPersistentContainer instance with the specified managed object model using the NSPersistentContainer(name:managedObjectModel:) method.

Finally, you load the persistent store for the container using the loadPersistentStores(completionHandler:) method, and handle any errors that may occur during the loading process.