xcode 核心数据可转换属性不适用于 NSPredicate
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6104566/
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
Core Data Transformable attributes NOT working with NSPredicate
提问by petershine
I often use Transformable
for Core Data attributes
, so I can change them later.
我经常使用Transformable
for Core Data attributes
,所以我可以稍后更改它们。
However, it seems like, if I want to use NSPredicate
to find a NSManagedObject
, using "uniqueKey == %@"
, or "uniqueKey MATCHES[cd] %@"
, it's not working as it should.
但是,看起来,如果我想使用NSPredicate
来查找NSManagedObject
、使用"uniqueKey == %@"
或"uniqueKey MATCHES[cd] %@"
,则它无法正常工作。
It always misses matching objects, until I change the attributes of the uniqueKey of the matching object to have specific class like NSString
, or NSNumber
.
它总是错过匹配的对象,直到我将匹配对象的 uniqueKey 的属性更改为具有特定类,例如NSString
, 或NSNumber
。
Can someone explain the limitation of using NSPredicate
with Transformable
attributes?
有人可以解释使用NSPredicate
withTransformable
属性的限制吗?
采纳答案by greymouser
Note: I'm not sure when/if this has changed since 5/2011 (from Scott Ahten's accepted answer), but you can absolutely search with NSPredicate on transformable attributes. Scott correctly explained why your assumptions were broken, but if Can someone explain the limitation of using NSPredicate with Transformable attributes?was your question, he implied that it is not possible, and that is incorrect.
注意:我不确定自 2011 年 5 月(来自 Scott Ahten 接受的答案)以来何时/是否发生了变化,但您绝对可以使用 NSPredicate 搜索可转换属性。Scott 正确地解释了为什么你的假设被打破了,但是如果有人可以解释使用 NSPredicate 和 Transformable 属性的限制吗?是你的问题,他暗示这是不可能的,这是不正确的。
Since the is the first google hit for "Core Data transformable value search nspredicate" (what I searched for trying to find inspiration), I wanted to add my working answer.
由于这是“核心数据可转换值搜索 nspredicate”的第一个谷歌搜索(我试图寻找灵感的搜索),我想添加我的工作答案。
How to use NSPredicate with transformable properties
如何使用具有可转换属性的 NSPredicate
Short, heady answer: you need to be smart about your data transformers. You need to transfrom the value to NSData that contains what I'll call "primitive identifying information", i.e. the smallest, most identifying set of bytes that can be used to reconstruct your object. Long answer, ...
简短而令人兴奋的答案:您需要对数据转换器保持智能。您需要将值转换为包含我称之为“原始识别信息”的 NSData,即可用于重建对象的最小、最具识别性的字节集。长答案,...
Foremost, consider:
首先,考虑:
- Did you actual mean to use a transformable attribute? If any supported data type -- even binary data -- will suffice, use it.
- Do you understand what transformable attributes actually are? How they pack and unpack data to and from the store? Review Non-Standard Persistent Attributesin Apple's documentation.
- After reading the above, ask: does custom code that hides a supported type "backing attribute" work for you? Possibly use that technique.
- 你真的想使用一个可转换的属性吗?如果任何支持的数据类型——甚至是二进制数据——就足够了,就使用它。
- 你明白什么是可转换属性吗?他们如何打包和解包进出商店的数据?查看Apple 文档中的非标准持久属性。
- 阅读以上内容后,问:隐藏支持类型“支持属性”的自定义代码对您有用吗?可能会使用该技术。
Now, past those considerations, transformable attributes are rather slick. Frankly, writing an NSValueTransformer "FooToData" for Foo instances to NSData seemed cleaner than writing a lot of adhoc custom code. I haven't found a case where Core Data doesn't know it needs to transform the data using the registered NSValueTransformer.
现在,抛开这些考虑,可转换的属性是相当光滑的。坦率地说,为 Foo 实例编写一个 NSValueTransformer "FooToData" 到 NSData 似乎比编写大量临时自定义代码更简洁。我还没有发现 Core Data 不知道它需要使用注册的 NSValueTransformer 来转换数据的情况。
To proceed simply address these concerns:
继续简单地解决这些问题:
- Did you tell Core Data what transformer to use? Open the Core Data model in table view, click the entity, click the attribute, load the Data Model Inspector pane. Under "Attribute Type: Transformable", set "Name" to your transformer.
- Use a default transformer (again, see the previous Apple docs) or write your own transformer -- transformedValue: mustreturn NSData.
- NSKeyedUnarchiveFromDataTransformerNameis the default transformer and may not suffice, or may draw in somewhat-transient instance data that can make two similar objects be different when they are equal.
- The transformed value should contain only -- what I'll call -- "primitive identifying information". The store is going to be comparing bytes, so every byte counts.
- You may also register your transformer globally. I have to do this since I actually reuse them elsewhere in the app -- e.g.
NSString *name = @"FooTrans"; [NSValueTransformer setValueTransformer:[NSClassFromString(name) new] forName:name];
- 你告诉 Core Data 使用什么转换器了吗?在表视图中打开核心数据模型,单击实体,单击属性,加载数据模型检查器窗格。在“属性类型:可转换”下,将“名称”设置为您的转换器。
- 使用默认转换器(再次参见之前的 Apple 文档)或编写您自己的转换器——transformedValue : mustreturn NSData。
- NSKeyedUnarchiveFromDataTransformerName是默认的转换器,可能不够用,或者可能会引入一些暂时性的实例数据,这可以使两个相似的对象在相等时不同。
- 转换后的值应该只包含——我称之为——“原始识别信息”。商店将比较字节,所以每个字节都很重要。
- 您也可以在全球范围内注册您的变压器。我必须这样做,因为我实际上在应用程序的其他地方重用它们 - 例如
NSString *name = @"FooTrans"; [NSValueTransformer setValueTransformer:[NSClassFromString(name) new] forName:name];
You probably don't want to use transforms heavily queried data operations - e.g. a large import where the primary key information uses transformers - yikes!
您可能不想使用转换大量查询的数据操作 - 例如主键信息使用转换器的大型导入 - 哎呀!
And then in the end, I simply use this to test for equality for high-level object attributes on models with NSPredicates -- e.g. "%K == %@" -- and it works fine. I haven't tried some of the various matching terms, but I wouldn't be surprised if they worked sometimes, and others not.
最后,我只是使用它来测试具有 NSPredicates 的模型上高级对象属性的相等性——例如“%K == %@”——并且它工作正常。我还没有尝试过一些不同的匹配术语,但如果它们有时有效,而另一些则无效,我不会感到惊讶。
Here's an example of an NSURL to NSData transformer. Why not just store the string? Yeah, that's fine -- that's a good example of custom code masking the stored attribute. This example illustrates that an extra byte is added to the stringified URL to record if it was a file URL or not -- allowing us to know what constructors to use when the object is unpacked.
这是 NSURL 到 NSData 转换器的示例。为什么不只存储字符串?是的,这很好——这是自定义代码屏蔽存储属性的一个很好的例子。这个例子说明了一个额外的字节被添加到字符串化的 URL 来记录它是否是一个文件 URL——允许我们知道在对象解包时使用什么构造函数。
// URLToDataTransformer.h - interface
extern NSString *const kURLToDataTransformerName;
@interface URLToDataTransformer : NSValueTransformer
@end
...
...
// URLToDataTransformer.m - implementation
#import "URLToDataTransformer.h"
NSString *const kURLToDataTransformerName = @"URLToDataTransformer";
@implementation URLToDataTransformer
+ (Class)transformedValueClass { return [NSData class]; }
+ (BOOL)allowsReverseTransformation { return YES; }
- (id)transformedValue:(id)value
{
if (![value isKindOfClass:[NSURL class]])
{
// Log error ...
return nil;
}
NSMutableData *data;
char fileType = 0;
if ([value isFileURL])
{
fileType = 1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value path] dataUsingEncoding:NSUTF8StringEncoding]];
}
else
{
fileType = -1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value absoluteString] dataUsingEncoding:NSUTF8StringEncoding]];
}
return data;
}
- (id)reverseTransformedValue:(id)value
{
if (![value isKindOfClass:[NSData class]])
{
// Log error ...
return nil;
}
NSURL *url = nil;
NSData *data = (NSData *)value;
char fileType = 0;
NSRange range = NSMakeRange(1, [data length]-1);
[data getBytes:&fileType length:1];
if (1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL fileURLWithPath:str];
}
else if (-1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL URLWithString:str];
}
else
{
// Log error ...
return nil;
}
return url;
}
@end
回答by Scott Ahten
Transformable attributes are usually persisted as archived binary data. As such, you are attempting to compare an instance of NSData with an instance of NSString or NSNumber.
可转换属性通常作为存档的二进制数据保存。因此,您正在尝试将 NSData 的实例与 NSString 或 NSNumber 的实例进行比较。
Since these classes interpret the same data in different ways, they are not considered a match.
由于这些类以不同的方式解释相同的数据,因此它们不被视为匹配。
回答by Jimi
you can try this way
你可以试试这种方式
NSExpression *exprPath = [NSExpression expressionForKeyPath:@"transformable_field"];
NSExpression *exprKeyword = [NSExpression expressionForConstantValue:nsdataValue];
NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression:exprPath rightExpression:exprKeyword modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType options:0];