关闭应用后,某些CoreData关系会丢失

时间:2022-01-02 16:30:46

This is the overview of my problem:

这是我的问题的概述:

I am adding (and confirm they are added) about 1400 relationships loaded from a soap service into CoreDat. After I close the app and open it again some of the relationships are lost; I only see around 800 of them (although it varies). Also, I am not getting any errors.

我正在添加(并确认它们已添加)大约1400个从soap服务加载到CoreDat的关系。关闭应用程序并再次打开它之后,一些关系就会丢失;我只看到他们中的大约800个(虽然它有所不同)。另外,我没有收到任何错误。

And now, more details:

现在,更多细节:

I have an object called User that has information about services a user have saved; it looks something like this:

我有一个名为User的对象,它包含有关用户保存的服务的信息;它看起来像这样:

@interface OosUser : NSManagedObject

    + (OosUser *) userFromSlug: (NSString *) slug;
    @property (nonatomic, retain) NSString *name;
    @property (nonatomic, retain) NSString *slug;
    @property (nonatomic, retain) NSMutableSet /* Service */ *services;
    - (void) addServicesObject: (Service * )service;
    - (void) removeServicesObject: (Service *) service;

@end

@implementation User

   @dynamic name;
   @dynamic slug;
   @dynamic services;

   static NSString *fetchPredicate = @"slug = %@";

   + (User *) userFromSlug:(NSString *)slug
   {
       User *result = [super objectWithPredicate: fetchPredicate, slug];
       if (!result) {
           result = [super create];
           result.slug = slug;
       }
   return result;
   }

@end

In the part of the code where the data is used, the relationships are saved like this:

在使用数据的代码部分中,关系保存如下:

NSMutableSet *userServices = self.user.services;

for (Service *service in servicesToAdd) {
        [self.services addObject: service];
        bool contained = false;
        for (Service *userService in userServices) {
            if ((contained = [userService.slug isEqualToString:service.slug])) {
                break;
            }
        }
        if (!contained) {
            // [userServices addObject:service];
            [self.user addServicesObject: service];
            NSError *error = nil;
            if (![[service managedObjectContext] save:&error]) {
                NSLog(@"Saving failed");
                NSLog(@"Error: %@", [error localizedDescription]);
            }else {
                NSLog(@"Registered service %d: %@", self.services.count, service.slug);
            }
        }
    }

The case is that I have checked with the debugger and I can see that all the over 1400 relationships are added, but when the app is reset and they are restored though self.user.services I only get around 800 objects.

情况是我已经检查过调试器,我可以看到所有1400多个关系都被添加了,但是当应用程序被重置并通过self.user.services恢复时我只能获得大约800个对象。

Why could this be happening? Anybody had this before?

为什么会发生这种情况?以前有人这个吗?

Thanks in advance.

提前致谢。


UPDATE:

People keep suggesting that I am not using Core Data correctly but the problem is that the data is lost AFTER restarting the app. There is absolutely no problem with it while using it. I am using Core Data as correct as it could be given the limited documentation and examples you get from Apple.

人们一直建议我没有正确使用Core Data,但问题是重启应用程序后数据丢失了。使用它时绝对没有问题。我使用Core Data是正确的,因为它可以提供有限的文档和从Apple获得的示例。

6 个解决方案

#1


11  

NSMutableSet *userServices = self.user.services;

...

            [userServices addObject:service];

Can't do that. self.user.services does not return a mutable set. That's what that addServicesObject method is for. Change the second line to:

做不到。 self.user.services不返回可变集。这就是addServicesObject方法的用途。将第二行更改为:

            [self.user addServicesObject:service];

From Apple documentation:

来自Apple文档:

It is important to understand the difference between the values returned by the dot accessor and by mutableSetValueForKey:. mutableSetValueForKey: returns a mutable proxy object. If you mutate its contents, it will emit the appropriate key-value observing (KVO) change notifications for the relationship. The dot accessor simply returns a set. If you manipulate the set as shown in this code fragment:

了解dot访问器返回的值与mutableSetValueForKey:之间的区别非常重要。 mutableSetValueForKey:返回一个可变的代理对象。如果改变其内容,它将为关系发出适当的键值观察(KVO)更改通知。点访问器只返回一个集合。如果您操作此代码片段中显示的集合:

[aDepartment.employees addObject:newEmployee]; // do not do this! then KVO change notifications are not emitted and the inverse relationship is not updated correctly.

[aDepartment.employees addObject:newEmployee]; // 不要这样做!然后不发出KVO更改通知,并且反向关系未正确更新。

Recall that the dot simply invokes the accessor method, so for the same reasons:

回想一下,dot只是调用了访问器方法,所以出于同样的原因:

[[aDepartment employees] addObject:newEmployee]; // do not do this, either!

[[aDepartment employees] addObject:newEmployee]; //也不要这样做!

#2


3  

I've the same problem, but after set up the inverse relationship, everything is OK again. I hope this helps investigating this issue.

我有同样的问题,但在建立反向关系后,一切都还可以。我希望这有助于调查此问题。

#3


1  

Okay, let's look at the symptoms here. You are making changes to objects within a context, but when you restart the app, some but not all of these changes are there.

好的,让我们来看看这里的症状。您正在对上下文中的对象进行更改,但是当您重新启动应用程序时,会有一些但并非所有这些更改都存在。

This can only mean that these changes are not being written to the persistent store. Since you are seeing some of the changes, you are calling the save: method, but Core Data is not recognising all the objects as needing to be saved.

这只能意味着这些更改不会写入持久性存储。由于您看到了一些更改,因此您调用了save:方法,但Core Data无法将所有对象识别为需要保存。

This leads us to how you are performing the changes to said objects. Are you making the changes in a KVO-compliant manner? Core Data relies on KVO to know what changes have occurred, and therefore what changes need persisting. If you change the objects in a non-KVO fashion, they will appear to be changed when you examine them, but Core Data will not know that these changes exist, and will therefore not know that it must persist them.

这导致我们如何对所述对象执行更改。您是否以符合KVO标准的方式进行更改?核心数据依赖于KVO来了解发生了哪些变化,因此需要持续进行哪些变更。如果以非KVO方式更改对象,则在检查它们时它们似乎会更改,但Core Data将不知道这些更改存在,因此不会知道它必须保留它们。

I would amend your code as follows, providing the Service object has the inverse relationship back to the User (and that relationship is called user, and part of a 1-M):

我会修改你的代码如下,假设Service对象与用户有反向关系(这个关系叫做user,是1-M的一部分):

[servicesToAdd setValue:self.user forKey:@"user"];

NSError *error = nil;
if (![[service managedObjectContext] save:&error]) {
    NSLog(@"Saving failed");
    NSLog(@"Error: %@", [error localizedDescription]);
}

This relies on the fact that Core Data will take care of both ends of the relationship for you, where an inverse relationship is set up. Of course, if it's a many-to-many relationship, then the code is slightly different, but we still use the KVO-compliant methods to make the changes.

这取决于核心数据将为您处理关系的两端,其中建立了反向关系。当然,如果它是多对多关系,那么代码略有不同,但我们仍然使用符合KVO的方法进行更改。

[servicesToAdd setValue:self.user forKey:@"user"];

for (Service *service in servicesToAdd) {
    [user addServicesObject:service];
} 

NSError *error = nil;
if (![[service managedObjectContext] save:&error]) {
    NSLog(@"Saving failed");
    NSLog(@"Error: %@", [error localizedDescription]);
}

#4


0  

In the end I have solved it by using a custom NSPredicate that fetches the services using one special parameter that I set on services when they are added by an user.

最后,我通过使用自定义NSPredicate解决了这个问题,该自定义NSPredicate使用我在用户添加服务时在服务上设置的一个特殊参数来获取服务。

It works although it's not ideal.

虽然它不理想但它仍然有效。

#5


0  

I had the same issue the relationship to another entity lost every time I restart the app. I searched for hours. In the end I found the issue. I declared my relationship as Transient, this caused the issue.

我有同样的问题,每次重新启动应用程序时,与另一个实体的关系都会丢失。我搜索了几个小时。最后我发现了这个问题。我宣称我的关系是瞬态的,这引起了这个问题。

关闭应用后,某些CoreData关系会丢失

#6


0  

For me, the issue was the Inverse relationship

对我来说,问题是逆向关系

There is my model

有我的模特

关闭应用后,某些CoreData关系会丢失

All have is to enable inverse relationship like this:

所有人都有这样的反向关系:

关闭应用后,某些CoreData关系会丢失

关闭应用后,某些CoreData关系会丢失

#1


11  

NSMutableSet *userServices = self.user.services;

...

            [userServices addObject:service];

Can't do that. self.user.services does not return a mutable set. That's what that addServicesObject method is for. Change the second line to:

做不到。 self.user.services不返回可变集。这就是addServicesObject方法的用途。将第二行更改为:

            [self.user addServicesObject:service];

From Apple documentation:

来自Apple文档:

It is important to understand the difference between the values returned by the dot accessor and by mutableSetValueForKey:. mutableSetValueForKey: returns a mutable proxy object. If you mutate its contents, it will emit the appropriate key-value observing (KVO) change notifications for the relationship. The dot accessor simply returns a set. If you manipulate the set as shown in this code fragment:

了解dot访问器返回的值与mutableSetValueForKey:之间的区别非常重要。 mutableSetValueForKey:返回一个可变的代理对象。如果改变其内容,它将为关系发出适当的键值观察(KVO)更改通知。点访问器只返回一个集合。如果您操作此代码片段中显示的集合:

[aDepartment.employees addObject:newEmployee]; // do not do this! then KVO change notifications are not emitted and the inverse relationship is not updated correctly.

[aDepartment.employees addObject:newEmployee]; // 不要这样做!然后不发出KVO更改通知,并且反向关系未正确更新。

Recall that the dot simply invokes the accessor method, so for the same reasons:

回想一下,dot只是调用了访问器方法,所以出于同样的原因:

[[aDepartment employees] addObject:newEmployee]; // do not do this, either!

[[aDepartment employees] addObject:newEmployee]; //也不要这样做!

#2


3  

I've the same problem, but after set up the inverse relationship, everything is OK again. I hope this helps investigating this issue.

我有同样的问题,但在建立反向关系后,一切都还可以。我希望这有助于调查此问题。

#3


1  

Okay, let's look at the symptoms here. You are making changes to objects within a context, but when you restart the app, some but not all of these changes are there.

好的,让我们来看看这里的症状。您正在对上下文中的对象进行更改,但是当您重新启动应用程序时,会有一些但并非所有这些更改都存在。

This can only mean that these changes are not being written to the persistent store. Since you are seeing some of the changes, you are calling the save: method, but Core Data is not recognising all the objects as needing to be saved.

这只能意味着这些更改不会写入持久性存储。由于您看到了一些更改,因此您调用了save:方法,但Core Data无法将所有对象识别为需要保存。

This leads us to how you are performing the changes to said objects. Are you making the changes in a KVO-compliant manner? Core Data relies on KVO to know what changes have occurred, and therefore what changes need persisting. If you change the objects in a non-KVO fashion, they will appear to be changed when you examine them, but Core Data will not know that these changes exist, and will therefore not know that it must persist them.

这导致我们如何对所述对象执行更改。您是否以符合KVO标准的方式进行更改?核心数据依赖于KVO来了解发生了哪些变化,因此需要持续进行哪些变更。如果以非KVO方式更改对象,则在检查它们时它们似乎会更改,但Core Data将不知道这些更改存在,因此不会知道它必须保留它们。

I would amend your code as follows, providing the Service object has the inverse relationship back to the User (and that relationship is called user, and part of a 1-M):

我会修改你的代码如下,假设Service对象与用户有反向关系(这个关系叫做user,是1-M的一部分):

[servicesToAdd setValue:self.user forKey:@"user"];

NSError *error = nil;
if (![[service managedObjectContext] save:&error]) {
    NSLog(@"Saving failed");
    NSLog(@"Error: %@", [error localizedDescription]);
}

This relies on the fact that Core Data will take care of both ends of the relationship for you, where an inverse relationship is set up. Of course, if it's a many-to-many relationship, then the code is slightly different, but we still use the KVO-compliant methods to make the changes.

这取决于核心数据将为您处理关系的两端,其中建立了反向关系。当然,如果它是多对多关系,那么代码略有不同,但我们仍然使用符合KVO的方法进行更改。

[servicesToAdd setValue:self.user forKey:@"user"];

for (Service *service in servicesToAdd) {
    [user addServicesObject:service];
} 

NSError *error = nil;
if (![[service managedObjectContext] save:&error]) {
    NSLog(@"Saving failed");
    NSLog(@"Error: %@", [error localizedDescription]);
}

#4


0  

In the end I have solved it by using a custom NSPredicate that fetches the services using one special parameter that I set on services when they are added by an user.

最后,我通过使用自定义NSPredicate解决了这个问题,该自定义NSPredicate使用我在用户添加服务时在服务上设置的一个特殊参数来获取服务。

It works although it's not ideal.

虽然它不理想但它仍然有效。

#5


0  

I had the same issue the relationship to another entity lost every time I restart the app. I searched for hours. In the end I found the issue. I declared my relationship as Transient, this caused the issue.

我有同样的问题,每次重新启动应用程序时,与另一个实体的关系都会丢失。我搜索了几个小时。最后我发现了这个问题。我宣称我的关系是瞬态的,这引起了这个问题。

关闭应用后,某些CoreData关系会丢失

#6


0  

For me, the issue was the Inverse relationship

对我来说,问题是逆向关系

There is my model

有我的模特

关闭应用后,某些CoreData关系会丢失

All have is to enable inverse relationship like this:

所有人都有这样的反向关系:

关闭应用后,某些CoreData关系会丢失

关闭应用后,某些CoreData关系会丢失