【问题标题】:CoreData - can't set empty string as default value for attributeCoreData - 不能将空字符串设置为属性的默认值
【发布时间】:2011-07-06 11:56:59
【问题描述】:

我的数据模型中有一个实体,其字符串属性当前是可选的,我想将其转换为默认值为空字符串的必需属性。

正如其他人所发现的,将 Xcode CoreData 数据建模器中的默认值留空会导致验证错误(因为设计人员将其解释为 NULL),但尝试将 ''、"" 或 @"" 作为默认值会导致在那些被解释为默认值的文字字符中,而不是根据需要的空零长度字符串。

我确实在 Google 上找到了 this thread,但是,除了解决方案非常丑陋(模型定义在 .xcdatamodel 和 objc 源之间拆分)之外,它也不适用于轻量级迁移,因为这些迁移完全基于在 .xcdatamodel 文件上,并且未加载实体实现中的 objc 逻辑。

有没有办法在数据模型设计器中实现这一点?

【问题讨论】:

    标签: xcode core-data migration string


    【解决方案1】:

    这是一个非常有趣的问题。经过一些测试,我认为这是不可能的,因为数据模型中的文本字段的配置方式。

    原则上,您可以使用 \u2205 的 unicode 空集字符来表示默认的空字符串,但文本字段似乎不接受任何转义,因此它将任何试图转义 unicode 字符代码的尝试转换为文字代码字符本身的字符串,例如输入 '\u2205' 以文字文本 '\u2205' 结束。

    理论上,您可以编写一个实用程序来读取以图形方式生成的托管对象模型文件,然后以编程方式将属性默认值设置为空字符串,然后将文件保存回磁盘。我说“理论上”是因为没有记录的方法可以从代码中保存托管对象模型文件。您可以读取一个并在内存中对其进行修改,但不能保留更改。

    我认为有点疏忽。

    我认为您别无选择,只能在模型首次加载时实用地设置默认空字符串。这很简单,但很丑陋,你必须记住你做过(特别是如果你迁移版本),但我认为现在这是唯一的选择。

    【讨论】:

    • 感谢您的回复和额外的测试......我怀疑这个问题不会有答案,是的,这真是太糟糕了!
    • 嗯,这是一个很好的问题。我经常使用 Core Data,但这是我从未遇到过的问题。我在研究它时学到了很多东西。我从未尝试以编程方式修改托管对象模型并保存它,但我一直认为你可以。我很惊讶地发现没有记录在案的方法。
    • 有人提交过雷达吗?当我这样做时,我很想与现有的票号联系起来。
    【解决方案2】:

    我通过覆盖我的字段的 getter 解决了这个问题 - 如果它包含 null,我将返回一个空字符串:

    -(NSString *)unit {
        if ([self primitiveValueForKey:@"unit"] == NULL) {
            return @"";
        } else {
            return [self primitiveValueForKey:@"unit"];
        }
    }
    

    到目前为止,它似乎在起作用,我想它不会影响迁移(尽管我对它们的了解还不够,无法肯定地说)。毕竟,我真的不在乎数据库中是否有空字符串或空字符串 - 只要我在请求字段时得到“”而不是空字符串。

    【讨论】:

      【解决方案3】:

      我解决此问题的方法是创建一个NSManagedObject 子类并处理用空字符串替换awakeFromInsert 中的NULL 值。然后我将所有实体设置为这个子类的子类,而不是NSManagedObject 的子类。这里的假设是我希望给定实体中的 every 字符串属性默认设置为空字符串(如果你想要一些,它不会工作,或者至少需要额外的逻辑在同一实体中保持 NULL)。

      可能有一种更有效的方法来执行此操作,但由于它仅在创建实体时调用,我认为它不会对性能造成太大影响。

      - (void)awakeFromInsert {
          [super awakeFromInsert];
      
          NSDictionary *allAttributes = [[self entity] attributesByName];
          NSAttributeDescription *oneAttribute;
      
          for (NSString *oneAttributeKey in allAttributes) { 
              oneAttribute = [allAttributes objectForKey:oneAttributeKey];
              if ([oneAttribute attributeType] == NSStringAttributeType) {
                  if (![self valueForKey:[oneAttribute name]]) {
                      [self setValue:@"" forKey:[oneAttribute name]];
                  }
              }
          }
      }
      

      【讨论】:

      • 一个建议基于awakeFromInsert 的文档 - 而不是使用setValue:forKey: 使用setPrimitiveValue:forKey: 以便不会触发KVO。
      【解决方案4】:

      拿出你最喜欢的 XML 编辑器(我刚刚使用 Emacs)并深入到 .xcdatamodel 包中的 contents 文件中 .xcdatamodeld 包中。然后只需在<entity>...</entity> 括号内的<attribute>...</attribute> 元素中添加一个defaultValueString="" XML 属性。 这是一个例子:

      <attribute name="email" attributeType="String" defaultValueString="" syncable="YES"/>
      

      我不能说这是否能在迁移中幸存下来,因为我还没有这样做。

      【讨论】:

      • 这对我有用。我也不能对迁移发表评论,但它确实可以在打开/关闭模型文件以及在检查器中编辑属性的其他属性时保留下来。
      • 多么毫无价值的评论:“这是一个糟糕的主意。”。也许提出更好的建议会更有帮助?我的概念虽然肯定使用了contents 文件可能变化的结构的知识,但至少模拟了没有此错误功能的CoreData 数据建模器。所有其他解决方案都是针对应该在设计时解决的问题的相对重量级的代码改进,即使用非错误建模器。
      • @ScottMarks,完全同意你的看法。得到一个不接受默认值“”的 XCode 让我非常紧张,这与 nil 字符串完全不同。迅速,这甚至是噩梦。正如您所说,它必须在设计时解决,我们不应该因为 XCode 有时一文不值而用愚蠢的指令破坏我们所有的代码。据我说,这是控制字段上的一个错误,因为我不知道为什么空格字符或空字符不能成为默认值。看到 2015 年这个问题还没有解决,我感到很难过
      【解决方案5】:

      您可以手动完成。 在您的模型类中,覆盖 awakeFromInsert 并将您的字符串设置为空字符串

      斯威夫特:

      override func awakeFromInsert()
      {
          super.awakeFromInsert()
          self.stringProperty = ""
      }
      

      目标-C

      - (void) awakeFromInsert
      {
          [super awakeFromInsert];
          self.stringProperty = @"";
      }
      

      【讨论】:

        【解决方案6】:

        这是基于 David Ravetti 的回答和 edelaney05 的评论的 Swift 解决方案。此外,我还添加了可选性检查。

        此解决方案在我的项目中运行良好。

        class ExampleEntity: NSManagedObject {
        
            ...
        
            override func awakeFromInsert() {
                super.awakeFromInsert()
                for (key, attr) in self.entity.attributesByName {
                    if attr.attributeType == .stringAttributeType && !attr.isOptional {
                        if self.value(forKey: key) == nil {
                            self.setPrimitiveValue("", forKey: key)
                        }
                    }
                }
            }
        
            ...
        }
        

        【讨论】:

          【解决方案7】:

          也许我迟到了这个答案,但我在谷歌上搜索并找到了这个论坛。

          解决方法很简单:

          1. 当您单击 xcdatamodelId 时(在左侧屏幕上)
          2. 将实体视图更改为图形
          3. 双击您想要的任何属性,菜单将出现在右侧。

          所有更改都很容易。

          第 2 部分

          第三部分

          【讨论】:

            【解决方案8】:

            一个基于Scott Marks answer的更简单的解决方案以避免语法错误:

            首先,将默认值临时设置为易于查找,例如here you are。使用任何文本编辑器打开.xcdatamodel 包内的contents 文件.xcdatamodeld 包内。然后只需在此文件中用"" 替换字符串"here you are" 进行搜索。

            迁移没有问题。

            【讨论】:

              【解决方案9】:

              这似乎已在某个时候得到修复。使用 Xcode 13:


              空字符串,未选中默认值:

              <attribute name="myAttributeName" optional="YES" attributeType="String"/>
              

              空字符串,现在在 Xcode 界面中显示:

              <attribute name="myAttributeName" defaultValueString="" optional="YES" attributeType="String"/>
              

              在字段中输入 "" 似乎是错误的,并在 XML 中生成 "&amp;quot;&amp;quot;"

              <attribute name="myAttributeName" defaultValueString="&quot;&quot;" optional="YES" attributeType="String"/>
              

              【讨论】:

                猜你喜欢
                • 2011-04-09
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-17
                • 1970-01-01
                • 2011-08-25
                • 1970-01-01
                • 2010-10-16
                相关资源
                最近更新 更多