xcode CoreData - 不能将空字符串设置为属性的默认值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5154708/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 20:21:08  来源:igfitidea点击:

CoreData - can't set empty string as default value for attribute

xcodecore-datamigrationstring

提问by glenc

I have an entity in my datamodel with a string attribute that is currently optional, and I'd like to convert this to a required attribute with a default value of the empty string.

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

As others have discovered, leaving the default value blank in the Xcode CoreData data modeller results in validation errors (since the designer interprets this as NULL), but trying '', "", or @"" as the default value results in those literal characters being interpreted as the default, rather than the empty zero-length string, as desired.

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

I did find this threadon Google, however, apart from the solution being really ugly (model definition split between the .xcdatamodel and objc source), it also doesn't work for lightweight migrations because those migrations are done solely based on the .xcdatamodel files and the objc logic from your entity implementations isn't loaded.

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

Is there any way to achieve this in the data model designer?

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

采纳答案by TechZen

This is a very interesting question. After some testing I don't think this is possible because of the way the text field in the data model is configured.

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

In principle, you could use the unicode empty-set character of \u2205to represent a default empty string but the text field does not seem to accept any escapes so it converts any attempt to escape a unicode character code to the literal string of the code characters themselves e.g. entering '\u2205' ends up as the literal text '\u2205'.

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

In theory you could write a utility app to read in the graphically generated managed object model file and then programmatically set the attribute default to equal an empty string and then save the file back to disk. I say "in theory" because there is no documented way to way to save a managed object model file from code. You can read one and modify it in memory but not persist the changes.

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

Bit of an oversight, I think.

有点疏忽,我想。

I don't think you have any choice but to set the default empty string pragmatically when the model first loads. That is simple to do but it's ugly and you'll have to remember you did (especially if you migrate versions) but I think right now that is the only choice.

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

回答by Scott Marks

Whip out your favorite XML editor (I just used Emacs) and dive down to the contentsfile inside the .xcdatamodelbundle inside the .xcdatamodeldbundle. Then just add a defaultValueString=""XML attribute to the <attribute>...</attribute>element inside the <entity>...</entity>brackets. Here's an example:

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

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

I can't speak to whether this survives migration since I haven't had to do that yet.

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

回答by Sasha

I resolved this by overriding the getter for my field - if it contains null, I return an empty string instead:

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

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

So far it seems to be doing the trick, and I would imagine it wouldn't impact migrations (although I don't know enough about them to say for sure). I don't really care whether there's a null or an empty string in the db, after all - so long as I get "" instead of null when I ask for the field.

到目前为止,它似乎正在奏效,我想它不会影响迁移(尽管我对它们的了解还不够肯定)。毕竟,我真的不在乎数据库中是否有空字符串或空字符串——只要我在请求该字段时得到 "" 而不是 null。

回答by David Ravetti

My approach to resolving this issue was to create an NSManagedObjectsubclass and handle the substitution of empty strings for NULL values in awakeFromInsert. I then set all entities as children of this subclass rather than children of NSManagedObject. The assumption here is that I want everystring attribute within a given entity to be set to an empty string by default (it wouldn't work, or would at least require extra logic, if you wanted some to remain NULL within the same entity).

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

There's probably a more efficient way of doing this, but since it's only called upon entity creation, I don't think it is too much of a performance hit.

可能有一种更有效的方法来做到这一点,但由于它只调用实体创建,我认为这不会对性能造成太大影响。

- (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]];
            }
        }
    }
}

回答by AMTourky

You can do it manually. In your model class, override awakeFromInsert and set your strings to empty string

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

Swift:

迅速:

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

Objective-C

目标-C

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

回答by speshiou

Here is the Swift solution based on David Ravetti's answer and edelaney05's comment. In addition, I added optionality check.

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

This solution works fine in my projects.

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

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)
                }
            }
        }
    }

    ...
}

回答by Nikaaner

A simpler solution based on Scott Marks answerto avoid syntax errors:

基于Scott Marks 回答的更简单的解决方案,以避免语法错误:

First, temporarily set the default value to be easy to find, something like here you are. Open with any text editor the contentsfile inside the .xcdatamodelbundle inside the .xcdatamodeldbundle. Then just do a search with replacing the string "here you are"with the ""in this file.

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

The migration took place without problems.

迁移没有问题。

回答by Khajak Kirikian

Maybe I'm late with this answer, but I was Googling and found this forum.

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

The solution is very simple:

解决方法很简单:

  1. When you click on the xcdatamodelId (On the left screen)
  2. Change the Entity View to Graph
  3. Double Click on any Attribute you want and the menu will appear on the right.
  1. 当您单击 xcdatamodelId 时(在左侧屏幕上)
  2. 将实体视图更改为图形
  3. 双击您想要的任何属性,菜单将出现在右侧。

All changes are easy.

所有的改变都很容易。

Part 2

第2部分

For Part 2

对于第 2 部分

Part 3

第 3 部分

For Part 3

第 3 部分