【问题标题】:Magical Record, cannot save an object: contextDidSave == NO, error = nil魔法记录,无法保存对象:contextDidSave == NO, error = nil
【发布时间】:2015-06-17 17:25:39
【问题描述】:

我正在尝试持久化新实体:

- (void)updateStorageWithQuizzess:(NSArray *)quizzess completion:(void(^)(NSArray *quizzess, BOOL succes, NSError *error))completion {
    NSMutableArray *mutableArray = [NSMutableArray array];

    [Quiz MR_truncateAll];
    [[NSManagedObjectContext MR_context] MR_saveWithBlock:^(NSManagedObjectContext *localContext) {

        for (NSDictionary *dictionary in quizzess) {
            Quiz *quiz = [Quiz MR_createEntity];
            [quiz fromDictionary:dictionary];
            [mutableArray addObject:quiz];
        }
    } completion:^(BOOL contextDidSave, NSError *error) {
        BlockSafeRun(completion, mutableArray, contextDidSave, error);
    }];
}

或者像这样:

- (void)updateStorageWithQuizzess:(NSArray *)quizzess completion:(void(^)(NSArray *quizzess, BOOL succes, NSError *error))completion {
    NSMutableArray *mutableArray = [NSMutableArray array];

    [Quiz MR_truncateAll];

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
        for (NSDictionary *dictionary in quizzess) {
            Quiz *quiz = [Quiz MR_createEntity];
            [quiz fromDictionary:dictionary];
            [mutableArray addObject:quiz];
        }
    } completion:^(BOOL contextDidSave, NSError *error) {
        BlockSafeRun(completion, mutableArray, contextDidSave, error);
    }];
}

但在完成块中,我收到 contextDidSave == NO,error == nil。 所以我无法弄清楚出了什么问题。 我犯了一些明显的错误吗?我该如何调试该问题?

//////

2015-06-17 20:39:27.061 HITO[6733:618953] Set root saving context: <NSManagedObjectContext: 0x16dbe070>
2015-06-17 20:39:27.062 HITO[6733:618953] Created new main queue context: <NSManagedObjectContext: 0x16e855b0>
2015-06-17 20:39:27.063 HITO[6733:618953] Set default context: <NSManagedObjectContext: 0x16e855b0>
2015-06-17 20:39:27.316 HITO[6733:618953] [HockeySDK] WARNING: Detecting crashes is NOT enabled due to running the app with a debugger attached.
2015-06-17 20:39:28.829 HITO[6733:618953] Created new private queue context: <NSManagedObjectContext: 0x16d57870>
2015-06-17 20:39:28.831 HITO[6733:619027] Created new private queue context: <NSManagedObjectContext: 0x16ea4ec0>
2015-06-17 20:39:28.841 HITO[6733:619027] NO CHANGES IN ** saveWithBlock:completion: ** CONTEXT - NOT SAVING

更新

以下来自 MR 的代码:

- (void) MR_saveWithOptions:(MRSaveOptions)saveOptions completion:(MRSaveCompletionHandler)completion;
{
    __block BOOL hasChanges = NO;

    if ([self concurrencyType] == NSConfinementConcurrencyType)
    {
        hasChanges = [self hasChanges];
    }
    else
    {
        [self performBlockAndWait:^{
            hasChanges = [self hasChanges];
        }];
    }

    if (!hasChanges)
    {
        MRLogVerbose(@"NO CHANGES IN ** %@ ** CONTEXT - NOT SAVING", [self MR_workingName]);

        if (completion)
        {
            dispatch_async(dispatch_get_main_queue(), ^{
                completion(NO, nil);
            });
        }

        return;
    }

所以,hasChanges 返回 NO。

【问题讨论】:

    标签: ios objective-c iphone core-data magicalrecord


    【解决方案1】:

    您的对象在保存块中没有发生任何更改。我在这里看到了两个问题。

    1. 当您需要在 localContext(即保存块的保存上下文)中创建新对象时,您正在 MR_defaultContext 中创建新对象。

    试试这个:

    - (void)updateStorageWithQuizzess:(NSArray *)quizzess completion:(void(^)(NSArray *quizzess, BOOL succes, NSError *error))completion {
        NSMutableArray *mutableArray = [NSMutableArray array];
    
    
        [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
            for (NSDictionary *dictionary in quizzess) {
                Quiz *quiz = [Quiz MR_createInContext:localContext];
                [quiz fromDictionary:dictionary];
                [mutableArray addObject:quiz];
            }
        } completion:^(BOOL contextDidSave, NSError *error) {
            BlockSafeRun(completion, mutableArray, contextDidSave, error);
        }];
    }
    
    1. 在您开始导入新对象之前,您的对象实际上并未被删除。这可能不会导致您的上下文没有变化,但我也会讨论这个问题。

    [Quiz MR_truncateAll] 只是将所有Quiz 对象deletedproperty 设置为true。这意味着下次保存或处理上下文时,将保存更改。

    因此,当您创建新的保存上下文时,该上下文仍然具有这些对象。我不确定您的 fromDictionary 方法在做什么,但如果它依赖于数据库,那么它就不会拥有它。

    你需要这样做:

    - (void)updateStorageWithQuizzess:(NSArray *)quizzess completion:(void(^)(NSArray *quizzess, BOOL succes, NSError *error))completion {
        NSMutableArray *mutableArray = [NSMutableArray array];
    
    
        [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
            [Quiz MR_truncateAllInContext:localContext];
            [localContext processPendingChanges];
    
            for (NSDictionary *dictionary in quizzess) {
                Quiz *quiz = [Quiz MR_createInContext:localContext];
                [quiz fromDictionary:dictionary];
                [mutableArray addObject:quiz];
            }
        } completion:^(BOOL contextDidSave, NSError *error) {
            BlockSafeRun(completion, mutableArray, contextDidSave, error);
        }];
    }
    

    这样,您将删除保存上下文中的对象。您还必须记住在保存上下文中调用 processPendingChanges 以从上下文中删除对象,而不仅仅是将它们标记为要删除。

    【讨论】:

    • 感谢您的回答。但是这些更改对我不起作用, contextDidSave 仍然 == 0 。 fromDictionary 只是从 NSDictionary 中填充一些参数。
    • 即使我完全删除了这些行,上下文也不会保存更改:[Quiz MR_truncateAllInContext:localContext]; [localContext processPendingChanges];
    • 哎呀!我第一次错过了一个关键问题!我已经更新了我的答案。确保在保存上下文中创建新实体! ;)
    • 是的,这似乎有道理,但实际上并非如此。据我了解,contextForCurrentThread 获取当前线程,如果有为该线程注册的上下文,它会返回它,否则,它会创建一个新的上下文,将其注册到该线程并返回它。但是saveWithBlock 实际上并没有在任何线程中注册它的上下文,因为它应该被使用一次然后它们就消失了,所以当你调用contextForCurrentThread 时,会为线程创建一个新的上下文。
    • 但很高兴我能帮上忙!
    猜你喜欢
    • 2023-04-07
    • 1970-01-01
    • 2016-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多