绑定到 Core Data 中的关系属性

发布于 2024-09-04 22:18:22 字数 411 浏览 6 评论 0原文

我是核心数据的新手,我遇到了一个问题,我无法理解如何以“正确的方式”进行操作,

我将尝试举例说明我的问题。

我有一辆实体车。以及我的程序中所有汽车的列表。汽车有一些属性,但它们不是预定义的。因此,对于每辆车,我希望能够定义一些属性。 因此,我定义了一个新的实体 CarProperty,与汽车具有一对多的关系。

在 nscollectionview 中,我想显示汽车的一些属性,更具体的是它已经行驶的公里数(numKm)(如果该属性存在)。所以我想将它绑定到标签上。但怎么办呢?

我不能说 representedObject.properties.numKmrepresentedObject.numKm

我应该如何解决这个问题?

希望这是有道理的。

I'm new in Core Data, and i got a problem i can't get my head around how to do "the right way"

I'll try and examplify my problem.

I got a entity Car. And a list of all the cars in my program. The cars have some attributes, but they are not predefined. So for each car i want to be able to define some properties.
Therefore i have defined a new entity CarProperty, with a one to many relation with the car.

In the nscollectionview i would like to show some of the properties from the car, more specefic the number of kilometer (numKm) it has driven (if that property exist). So i want to bind it to a label. But how to do?

I can't say representedObject.properties.numKm, or representedObject.numKm.

How should I get around this?

Hope it makes sense.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

半世蒼涼 2024-09-11 22:18:22

这不是一个容易的问题。问题是,Core Data 对 numKm 作为属性一无所知。它如何知道 numKm 对应于特定的 CarProperty 对象?

您描述的根本问题是键值编码合规性。 Cocoa 将在 properties 对象上查找名为 numKm 的方法。如果找不到,它将尝试发送 [properties valueForKey:@"numKm"]; 因为 valueForKey: 不知道如何处理 numKm 时,您会收到错误,但在调用 [properties valueForUndefinedKey:@"numKm"] 之前不会出现错误,

但问题是:properties 是一个 NSSet 由 Core Data 生成,因此您无法对其进行子类化以覆盖 valueForUndefinedKey:。您可以做的是为您的任意属性创建符合 KVC 的您自己的对象并使用它。

一种解决方案是子类化 NSDictionary 并使其充当代理。原始方法是 countobjectForKey:keyEnumerator。如果您重写这三个方法,则可以创建一个链接到您的 Car 对象的 NSDictionary 并返回相应的 CarProperty 对象。例如:

@interface PropertyProxy : NSDictionary {
}
@property (nonatomic, readonly, assign) Car *car;

- (id)initWithCar:(Car *)car

@end

@implementation PropertyProxy

@synthesize car = _car;

- (id)initWithCar:(Car *)car {
    if (!(self = [super init]))
        return nil;

    _car = car;

    return self;
}

- (NSInteger)count {
    return [car.properties count];
}

- (id)objectForKey:(NSString *)key {
    return [[car.properties filteredSetUsingPredicate:[NSPredicate predicateWithFormt:@"key == %@", key]] anyObject];
}

- (NSEnumerator *)keyEnumerator {
    return [[car valueForKeyPath:@"properties.key"] objectEnumerator];
}

@end

然后,在您的 Car 类中,执行以下操作:(

@interface Car : NSManagedObject {
    // other stuff
}

@property (nonatomic, readonly) NSDictionary *carProperties;

// other stuff

@end

@implementation Car

// other stuff

- (NSDictionary *)carProperties {
    return [[[PropertyProxy alloc] initWithCar:self] autorelease];
}

@end

免责声明:我只是将其输入到我的网络浏览器中,因此不能保证它实际上可以编译:-))

如您所见,这不是世界上最容易做的事情。您将能够像这样设置关键路径:

representedObject.carProperties.numKm;

请记住,虽然这是符合键值编码的,但它不符合键值观察的。因此,如果 numKm 发生变化,您将无法观察到这一点。您需要做一些额外的工作才能实现这一点。

This isn't an easy problem. The thing is, Core Data doesn't know anything about numKm as a property. How is it supposed to know that numKm corresponds to a particular CarProperty object?

The fundamental problem you're describing is key-value coding compliance. Cocoa's going to look for a method called numKm on the properties object. Not finding one, it'll try sending [properties valueForKey:@"numKm"]; Since valueForKey: doesn't know what to do with numKm, you get an error, but not before it calls [properties valueForUndefinedKey:@"numKm"]

But here's the catch: properties is an NSSet generated by Core Data, so you can't subclass it to override valueForUndefinedKey:. What you can do is create your own object that's KVC-compliant for your arbitrary properties and use that instead.

One solution is to subclass NSDictionary and make it act as a proxy. The primitive methods are count, objectForKey: and keyEnumerator. If you override these three methods, you can create an NSDictionary that's linked to your Car object and returns the appropriate CarProperty objects. For example:

@interface PropertyProxy : NSDictionary {
}
@property (nonatomic, readonly, assign) Car *car;

- (id)initWithCar:(Car *)car

@end

@implementation PropertyProxy

@synthesize car = _car;

- (id)initWithCar:(Car *)car {
    if (!(self = [super init]))
        return nil;

    _car = car;

    return self;
}

- (NSInteger)count {
    return [car.properties count];
}

- (id)objectForKey:(NSString *)key {
    return [[car.properties filteredSetUsingPredicate:[NSPredicate predicateWithFormt:@"key == %@", key]] anyObject];
}

- (NSEnumerator *)keyEnumerator {
    return [[car valueForKeyPath:@"properties.key"] objectEnumerator];
}

@end

Then, in your Car class, do this:

@interface Car : NSManagedObject {
    // other stuff
}

@property (nonatomic, readonly) NSDictionary *carProperties;

// other stuff

@end

@implementation Car

// other stuff

- (NSDictionary *)carProperties {
    return [[[PropertyProxy alloc] initWithCar:self] autorelease];
}

@end

(Disclaimer: I just typed this into my web browser, so no guarantees this actually compiles :-))

As you can see, it's not the easiest thing in the world to do. You'll be able to set up key paths like this:

representedObject.carProperties.numKm;

Keep in mind that, while this is key-value coding compliant, it is not key-value observing compliant. So if numKm changes, you won't be able to observe that. You would need to do some extra work to make that happen.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文