【问题标题】:NSManagedObject ignoring changed transformableNSManagedObject 忽略更改的可转换对象
【发布时间】:2014-07-16 17:56:17
【问题描述】:

对于一些符合 NSCoding 的对象,我有一个非常基本的缓存系统。方法获取对象,提取键和搜索参数的一些信息,创建或更新 NSManagedObject,并将其保存到持久存储:

+ (void)updateQuestion:(StacManQuestion *)question site:(StacManSite *)site
{
    // 1. Look up with a basic predicate.
    SECachedQuestion *cachedQuestion = [SECachedQuestion 
        findFirstWithQuestionId:question.questionId site:site];

    // 2. Create if missing.
    if (!cachedQuestion) {
        cachedQuestion = [SECachedQuestion MR_createEntity];
        cachedQuestion.questionId = question.questionId;
        cachedQuestion.site = site.apiSiteParameter;
    }

    // 3. Update properties.
    cachedQuestion.isFavorite = question.favorited;
    cachedQuestion.lastAccessTime = [NSDate date];
    cachedQuestion.question = question;

    // 4. Save
    [[NSManagedObjectContext MR_contextForCurrentThread] 
        MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
        /* ... */
    }];
}

此代码第一次运行时,运行良好。该对象被保存到缓存中,并可立即用于下一次运行。然而,在此之后,为 cachedQuestion.question 分配一个新值将无济于事。

我添加了一些断点,发现如下:

  1. 问题的分配没有更新changedValues

    (lldb) po [cachedQuestion changedValues]  {
        lastAccessTime = "2014-07-16 17:16:45 +0000";
    }
    
  2. questioncachedQuestion.question 以不同的地址开始,然后以相同的地址结束,因此肯定会发生分配。

  3. 如果我在设置cachedQuestion.question = nil 的作业之前放置一个步骤,我会得到以下信息,但问题的记录会在重新分配时再次消失。

    (lldb) po [cachedQuestion changedValues]  {
        lastAccessTime = "2014-07-16 17:16:45 +0000";
        question = "<null>";
    }
    
  4. 这是另一个超级好的东西。我继续做了一个测试,我只是为应用程序的几个版本设置了cachedQuestion.question = nil。这对于单次运行中的后续查找工作正常,但每次应用程序启动第一次读取 cachedQuestion.question 时都会返回原始值!我可以确认已开始创建新的缓存问题并且 lastAccessTime 更新没有问题。只是这一字段被及时冻结。 这是因为数据验证。 nil 让它显示在更改的值中,但保存失败,因为它不是可选的。

更新

现在我正在做一个悲伤的黑客攻击,只要有更改,我就会删除旧记录并插入新记录。它工作得很好,但我更想知道出了什么问题。

【问题讨论】:

    标签: ios core-data nsmanagedobject magicalrecord


    【解决方案1】:

    您没有将更改写入正确的上下文。首先,停止使用 contextForCurrentThread。它已被弃用,并且会在 100 次中导致您崩溃 1 次,这实在是太多了。你也有崩溃的风险,因为这个方法可以并且将会返回一个不是默认上下文的上下文。跨上下文进行托管对象分配也会崩溃,这是有充分理由的。

    相反,您应该显式创建上下文,将更改写入其中,然后在方法结束时保存。这可能会解决您遇到的大部分问题。

    【讨论】:

    • 我在这里没有看到任何变化。此流程中的所有调用最初都发生在主线程上,因此在保存期间不存在线程消失的风险。失败点似乎仍然是我为 question 设置了一个新值,但 changedValues 没有更新。
    • contextForCurrentThread 是(或最终将是)您的问题,底线。停止使用它。如果你现在在主线程上做这一切(糟糕),那么就明确一点,用默认上下文尝试你的东西。
    【解决方案2】:

    我不得不读了好几遍... 我认为这里的问题是您没有正确使用关系。 NSManagedObjects 应该设置为一个实体。

    它不应该是可转换的,而是与实体的关系。

    从上下文中,您可以在 MutableArray 中获取第一个实体中的第一个所有对象,然后通过在选择一个对象时调用此方法,通过其关系在新的对象 MutableArray 中获取其所有相关对象:

    self.newArray = [[self.oldObject.relationshipName allObjects]mutableCopy];

    然后,您将只获得与所选对象相关的内容,而不是相关实体中的所有对象。

    这意味着不应该有问题属性,而是与实体问题的关系。

    【讨论】:

      猜你喜欢
      • 2017-08-08
      • 2020-12-07
      • 2017-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-24
      • 1970-01-01
      相关资源
      最近更新 更多