开发者

Subclassing NSArrayController in order to limit size of arrangedObjects

I'm trying to limit the number of objects in an array controller, but I still want to be able to access the full array, if necessary. A simple solution I came up with was to subclass NSArrayController, and define a new method named "limitedArrangedObjects", that returns a limited number of objects from the real set of a开发者_如何学Gorranged objects. (I've seen Limiting the number of objects in NSArrayController , but that doesn't address my problem.)

I want this property to be observable via bindings, so I set a dependency to arrangedObjects on it.

Problem is, when arrangedObjects is updated, limitedArrangedObjects seems not to be observing the value change in arrangedObjects. I've hooked up an NSCollectionView to limitedArrangedObjects, and zero objects are being displayed. (If I bind it to arrangedObjects instead, all the objects show up as expected.)

What's the problem?

Here's the relevant code:

@property (readonly) NSArray *limitedArrangedObjects;

- (NSArray *)limitedArrangedObjects;
{
    NSArray *arrangedObjects = [super arrangedObjects];

    NSUInteger upperLimit = 10000;

    NSUInteger count = [arrangedObjects count];
    if (count > upperLimit) count = upperLimit;
    arrayToReturn = [arrangedObjects subarrayWithRange:NSMakeRange(0, count)];


    return arrayToReturn;
}


+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key;
{
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];

    if ([key isEqualToString:@"limitedArrangedObjects"]) {
        NSSet *affectingKeys = [NSSet setWithObjects:@"arrangedObjects",nil];
        keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKeys];
    }

    return keyPaths;
}


I would probably take a different approach, which would be to override -arrangeObjects:, which can filter out objects and then set an auxiliary property like completeArrangedObjects to let you access the whole array. It'd look something like this:

- (NSArray*)arrangeObjects:(NSArray*)originalObjects
{
    NSArray* arrayToReturn;
    NSUInteger upperLimit = 10000;

    NSUInteger count = [originalObjects count];
    if (count > upperLimit) count = upperLimit;
    arrayToReturn = [arrangedObjects subarrayWithRange:NSMakeRange(0, count)];
    [self setCompleteArrangedObjects:originalObjects];
    return arrayToReturn;
}

Then you'd just bind your NSCollectionView to arrangedObjects, and since you're using a setter for completeArrangedObjects, that should also trigger KVO notifications when appropriate if you want to bind to it as well.


I can't remember where/who told me this, but I was informed that observing the "arrangedObjects" key using keyPathsForValuesAffectingValueForKey: currently doesn't work for NSArrayControllers. You can observe sub-keys (arrangedObjects.name, etc.), but you can't observe arrangedObjects directly.

So, the solution in my case was to create two instantiated objects in my nib file, a normal NSArrayController and an AFArrayController. AFArrayController has arrangedObjects: defined as such:

- (NSArray *)arrangedObjects;
{
    return [self limitedArrayFromArray:[super arrangedObjects]];
}

- (NSArray *)limitedArrayFromArray:(NSArray *)theArray;
{
    NSUInteger upperLimit = 0;
    if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_5) {
        upperLimit = 500;
    } else {
        upperLimit = 10000;
    }

    NSUInteger count = [theArray count];
    if (count > upperLimit) count = upperLimit;
    NSArray *arrayToReturn = [theArray objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, count)]];


    return arrayToReturn;
}

Now, I can observe arrangedObjects on NSArrayController if I want to get all the objects, or arrangedObjects on the AFArrayController if I want to get the limited set, and I can observe sub-properties on both the NSArrayController and the AFArrayController.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜