可可结合:结合到“许多”结束一对多关系 [英] Cocoa Bindings: Binding to the "many" end of a to-many relationship

查看:266
本文介绍了可可结合:结合到“许多”结束一对多关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Employees-Departments示例,我要做的是将列绑定到Departments.arrangedObjects.employees。@ sum.hoursWorked,如下所示:

Using the Employees-Departments example what I want to do is bind a column to "Departments.arrangedObjects.employees.@sum.hoursWorked" as outlined below:

实体员工


  • 属性:firstName,lastName,hoursWorked

  • departments

实体部


  • 属性:name

  • 关系:employees

显示有关部门的一些摘要信息。

I want a table which will display some summary info about departments.

我将第一列绑定到我的Departments数组控制器arrangedObjects.name。
我可以通过绑定到arrangedObjects.employees。@ count来显示一个部门中的员工人数。

I bind the first column to my "Departments" array controller, "arrangedObjects.name". I can have a column displaying the number of employees in a department by binding to "arrangedObjects.employees.@count"

但是我无法获得工作人员的工作时间我假设我可能通过绑定到arrangeObjects.employees。@ sum.hours工作

However I can't get a sum of the hoursWorked by employees as I assume I might by binding to "arrangedObjects.employees.@sum.hoursWorked"

我得到的错误是沿着 < _NSFaultingMutableSet 0x1acea0> addObserver:forKeyPath:options:context:]不支持键路径:@ sum.hoursWorked

The error I get is along the lines of "[<_NSFaultingMutableSet 0x1acea0> addObserver:forKeyPath:options:context:] is not supported. Key path: @sum.hoursWorked"

我相信这是因为它不可能绑定到许多端的一对多关系。如果是这样,我该怎么做我想做的?

I believe this is because it is not possible to bind to the many end of a to-many relationship. If so how can I do what I want to do?

对于额外的信用,说每个员工也有另一个属性,种族,我也想我的摘要表以显示每个部门的独特种族数。

For extra credit, say each employee also has another attribute, "race", I would also like my summaries table to show the number of unique races in each department.

提前感谢。

推荐答案

我遇到了同样的错误。看起来虽然你可以得到的员工集合,并执行一些集合的操作,通过做以下事情:

I encountered the same errors you did. It seems that while you can get the set of employees and perform some set of aggregate operations on it by doing something like:

Department * dept =;
NSSet * employees = dept.employees;
NSNumber * sumOfHoursWorked = [employees valueForKeyPath:@@ sum.hoursWorked];

Department* dept = ; NSSet* employees = dept.employees; NSNumber* sumOfHoursWorked = [employees valueForKeyPath: @"@sum.hoursWorked"];

绑定时有区别。绑定要求观察键路径,而不是评估一次。鉴于,它有点,排序有道理为什么你不能绑定到这些关键路径。 Kinda。 Sorta。

There's a difference when you bind. Bindings are asking to observe the key path, not evaluate it once. Given that, it kinda, sorta makes sense why you can't bind to these key paths. Kinda. Sorta.

现在。至于解决方案,我通常在这样的情况下写一个小的NSValueTransformer子类来做我所需要的,然后把它插入到IB。这样,我写了我需要的十行代码,但不要最终做整个NSTableView数据源spiel为一个简单的聚合。在这种情况下,你可以这样做:

Now. As for a solution, what I usually do in cases like this is write a tiny little NSValueTransformer subclass to do just what I need, and then plug that into IB. This way, I write the ten lines of code I need, but don't end up doing the whole NSTableView data source spiel for want of a simple aggregate. In this case, you might do something like this:

// Declaration

@interface MySumOfHoursWorkedTransformer : NSValueTransformer
@end

@interface MyNumberOfRacesTransformer : NSValueTransformer
@end

// Implementation


@implementation MySumOfHoursWorkedTransformer

+ (Class)transformedValueClass { return [NSNumber class]; }   // class of the "output" objects, as returned by transformedValue:
+ (BOOL)allowsReverseTransformation { return NO; }    // flag indicating whether transformation is read-only or not

- (id)transformedValue:(id)value           // by default returns value
{
    NSNumber* retVal = nil;
    if ([value isMemberOfClass: [Department class]])
    {
        double hoursWorked = 0.0;
        for (Employee* employee in [value valueForKey: @"employees"])
        {
            NSNumber* hoursWorkedNumber = employee.hoursWorked;
            hoursWorked += hoursWorkedNumber ? [hoursWorkedNumber doubleValue] : 0.0;
        }
        retVal = [NSNumber numberWithDouble: hoursWorked];
    }
    return retVal;
}

@end

@implementation MyNumberOfRacesTransformer

+ (Class)transformedValueClass { return [NSNumber class]; }   // class of the "output" objects, as returned by transformedValue:
+ (BOOL)allowsReverseTransformation { return NO; }    // flag indicating whether transformation is read-only or not

- (id)transformedValue:(id)value           // by default returns value
{
    NSNumber* retVal = nil;
    if ([value isMemberOfClass: [Department class]])
    {
        NSMutableSet* raceSet = [NSMutableSet set];
        for (Employee* employee in [value valueForKey: @"employees"])
        {
            id raceVal = employee.race;
            if (raceVal)
                [raceSet addObject: raceVal];
        }
        retVal = [NSNumber numberWithUnsignedInteger: raceSet.count];
    }
    return retVal;
}

@end

然后,只要绑定这些TableColumns到ArrayController.arrangedObjects并插入适当的值变换器子类。现在,您将无法编辑这些值,但是仍然可以修改汇总值意味着什么?

Then, just bind those TableColumns to ArrayController.arrangedObjects and plug in the appropriate value transformer subclass. Now, you won't be able to edit those values, but what would it mean to edit an aggregate value anyway?

希望有帮助。我使用这种方法一堆,它肯定会放弃绑定。

Hope that helps. I've used this approach a bunch, and it sure beats giving up on bindings.

这篇关于可可结合:结合到“许多”结束一对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆