How should I remove all items from an NSTableView controlled by NSArrayController?
Asked Answered
Q

5

7

I'm using an NSArrayController, NSMutableArray and NSTableView to show a list of my own custom objects (although this question probably applies if you're just showing a list of vanilla NSString objects too).

At various points in time, I need to clear out my array and refresh the data from my data source. However, just calling removeAllObjects on my NSMutableArray object does not trigger the KVO updates, so the list on screen remains unchanged.

NSArrayController has no removeAllObjects method available, which seems really weird. (It does have addObject, which I use to add the objects, ensuring the KVO is triggered and the UI is updated.)

The cleanest way I've managed to cause this happen correctly is:

[self willChangeValueForKey:@"myArray"];
[myArray removeAllObjects];
[self didChangeValueForKey:@"myArray"];

...so I'm kind of having to do the KVO notification manually myself (this is in my test app class, that contains the myArray property, which is NSMutableArray, as mentioned.)

This seems wrong - is there a better way? From my googling it seems a few people are confused by the lack of removeAllObjects in NSArrayController, but haven't seen any better solutions.

I have seen this solution:

[self removeObjectsAtArrangedObjectIndexes:
  [NSIndexSet indexSetWithIndexesInRange:
    NSMakeRange(0, [[self arrangedObjects] count])]];

but this looks even more unpleasant to me. At least my solution is at least marginally self-documenting.

Did Apple not notice that sometimes people might want to empty a list control being managed via an NSArrayController object? This seems kind of obvious, so I think I must be missing something...

Aside: of course, if I add new items to the array (via NSArrayController), then this triggers a KVO update with the NSArrayController/NSTableView, but:

  1. Sometimes I don't put any items in the list, because there are none. So you just see the old items.
  2. This is a bit yucky anyway.
Quaternity answered 14/3, 2009 at 21:39 Comment(0)
S
16

You don't remove items from a table view. It doesn't have any items—it just displays another object's items.

If you bound the array controller's content array binding to an array property of some other object, then you should be working with that property of that object. Use [[object mutableArrayValueForKey:@"property"] removeAllObjects].

If, on the other hand, you haven't bound the array controller's content array binding, then you need to interact with its content directly. Use [[arrayController mutableArrayValueForKey:@"content"] removeAllObjects]. (You could also work with arrangedObjects instead of content. If one doesn't work, try the other—I've only ever done things the first way, binding the array controller to something else.)

Subarid answered 14/3, 2009 at 23:38 Comment(3)
Thanks - that works. I changed my original code in my question to: [[self mutableArrayValueForKey:@"myArray"] removeAllObjects]; and it works fine. Much cleaner. You spelt mutableArrayValueForKey wrong btw - fix that and I'll mark it as the accepted answer. :-)Quaternity
Your method works perfectly when the ArrayController is bounded to an array. But it doesn't work when the ArrayController is not bounded to an array. The content array you are getting from the ArrayController is an NSArray not NSMutableArray. Just use method from ArrayController to clear the content: NSRange range = NSMakeRange(0, [[anArrayController arrangedObjects] count]);[anArrayController removeObjectsAtArrangedObjectIndexes:[NSIndexSet indexSetWithIndexesInRange:range]];Exigent
@Exigent The NSRange solution is significantly faster than the original answer or [anArrayController removeObjects:[anArrayController arrangedObjects]]. Thanks!Radiosurgery
H
3

Had this problem as well and solved it this way:

NSArrayController* persons = /* your array controller */;
[[persons content] removeAllObjects];
Higinbotham answered 15/8, 2009 at 20:16 Comment(1)
Unfortunately, this does not work. If one were to call [persons arrangedObjects], the array contents might still be there. After removing all of the items from the content array with removeAllObjects, I have found that you need to also call [persons rearrangeObjects] as well.Mars
C
1

Swift

@IBOutlet var acLogs: NSArrayController!

acLogs.removeObjects(acLogs.content as! [AnyObject])

worked for me.

Crat answered 17/1, 2016 at 22:36 Comment(0)
G
0

Solution in Swift:

if let ac = arrayController
{
    let range:NSRange = NSMakeRange(0, ac.arrangedObjects.count);
    let indexSet:NSIndexSet = NSIndexSet(indexesInRange: range);
    ac.removeObjectsAtArrangedObjectIndexes(indexSet);
}
Gawky answered 2/5, 2015 at 9:39 Comment(0)
S
0

Just an update that works in Swift 4:

let range = 0 ..< (self.arrayController.arrangedObjects as AnyObject).count
self.arrayController.remove(atArrangedObjectIndexes: IndexSet(integersIn: range))
Stralsund answered 24/11, 2018 at 1:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.