NSArray - move Items at indexes

  • Is there any code out there to do something like a [NSArray
    moveObjectsAtIndexes:(NSindexSet*)indexes toIndex:(unsigned)index]; Im
    really having a hard time wrapping my head around how to do that.

    thanks

    AC
  • On 9/20/07, Alexander Cohen <alexcohen...> wrote:
    > Is there any code out there to do something like a [NSArray
    > moveObjectsAtIndexes:(NSindexSet*)indexes toIndex:(unsigned)index]; Im
    > really having a hard time wrapping my head around how to do that.

    First, you need an NSMutableArray (as NSArray instances are immutable).

    Second, you can remove objects at the old indexes, and re-insert them
    at the new index. Something along the lines of this (warning composed
    in mail, not tested, but should give you the basic idea):

    @implementation NSMutableArray(CSCAdditions)

    -(void) moveObjectsAtIndexes:(NSindexSet*)indexes toIndex:(unsigned)index
    {
        NSArray *objectsToMove = [self objectsAtIndexes: indexes];

        //If any of the removed objects come before the index, we want to
    decrement the index appropriately
        index -= [indexes countOfIndexesInRange: (NSRange){0, index}];

        [self removeObjectsAtIndexes: indexes];

        NSEnumerator    *enumerator = [objectsToMove objectEnumerator];
        id              object      = nil;

        while(object = [enumerator nextObject]) {
            [self insertObject: object atIndex: index++];
        }
    }

    @end

    --
    Clark S. Cox III
    <clarkcox3...>
  • Am 20.09.2007 um 17:27 Uhr schrieb Clark Cox:

    > NSEnumerator    *enumerator = [objectsToMove objectEnumerator];
    > id              object      = nil;
    >
    > while(object = [enumerator nextObject]) {
    > [self insertObject: object atIndex: index++];
    > }

    Instead of this loop you could use -
    replaceObjectsInRange:withObjectsFromArray:.

    Andreas
  • On 9/20/07, Andreas Mayer <andreas...> wrote:
    >
    > Am 20.09.2007 um 17:27 Uhr schrieb Clark Cox:
    >
    >> NSEnumerator    *enumerator = [objectsToMove objectEnumerator];
    >> id              object      = nil;
    >>
    >> while(object = [enumerator nextObject]) {
    >> [self insertObject: object atIndex: index++];
    >> }
    >
    > Instead of this loop you could use -
    > replaceObjectsInRange:withObjectsFromArray:.

    Indeed, good catch:

    -(void) moveObjectsAtIndexes:(NSindexSet*)indexes toIndex:(unsigned)index
    {
      NSArray *objectsToMove = [self objectsAtIndexes: indexes];

      //If any of the removed objects come before the index, we want to
    decrement the index appropriately
      index -= [indexes countOfIndexesInRange: (NSRange){0, index}];

      [self removeObjectsAtIndexes: indexes];
      [self replaceObjectsInRange: (NSRange){index,0}
    withObjectsFromArray: objectsToMove];
    }

    ... much cleaner.

    --
    Clark S. Cox III
    <clarkcox3...>
  • One thing that might be considered, I don't think he mentioned if he was
    using an NSArrayController or a subclass of it.  I recently snatched a
    similar routine for my controller subclass from the Bookmarks sample code:

    -(void) moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet*)indexSet
                                            toIndex:(unsigned int)insertIndex

        One thing I've learned is that if you are using array controllers and
    bindings with table views: DONT MESS WITH THE ARRAY DIRECTLY!  Do it through
    the controller methods instead if you want the changes to track in other
    views.  I have several views that differently display the same info.  I
    guess if you know what you are doing with notifications (I don't) you can
    make it work directly. It may or may not apply in his case.

    > -(void) moveObjectsAtIndexes:(NSindexSet*)indexes toIndex:(unsigned)index
    > {
    > NSArray *objectsToMove = [self objectsAtIndexes: indexes];
    >
    > //If any of the removed objects come before the index, we want to
    > decrement the index appropriately
    > index -= [indexes countOfIndexesInRange: (NSRange){0, index}];
    >
    > [self removeObjectsAtIndexes: indexes];
    > [self replaceObjectsInRange: (NSRange){index,0}
    > withObjectsFromArray: objectsToMove];
    > }
    >
    > ... much cleaner.
    >
  • > One thing I've learned is that if you are using array controllers and
    > bindings with table views: DONT MESS WITH THE ARRAY DIRECTLY!

    This shouldn't be a problem if you use -mutableArrayValueForKey: to
    access the array.
  • On Sep 21, 2007, at 12:54 PM, Gordon Apple wrote:

    > One thing I've learned is that if you are using array controllers
    > and
    > bindings with table views: DONT MESS WITH THE ARRAY DIRECTLY!  Do it
    > through
    > the controller methods instead if you want the changes to track in
    > other
    > views.

    The first part is correct but the second part is not.  Model-level
    changes DO NOT go through the NSArrayController.  Model-level changes
    should be done by manipulating the relationship the collection
    represents; that is, the result of -mutableArrayValueForKey: or -
    mutableSetValueForKey: for the relationship's key.  *This* is what
    actually causes the Key-Value Observing notifications to be posted.
    It's also what the controllers actually do behind the scenes anyway.

    A lot of people seem to be hacking together code that interacts with
    controllers to perform model-layer manipulations because they've
    "learned" by trial and error that it "works."  This is why there is
    such a huge emphasis on having a deep understanding of Key-Value
    Coding and Key-Value Observing before using Cocoa Bindings and the
    controller layer:  If you try to approach the controller layer without
    such an understanding, you will wind up with code that isn't
    architected as well as it could be and that is hard to test and extend.

    There is a process to learning Cocoa.  Learn Cocoa according to that
    process.  Do not try to take shortcuts and backfill your knowledge;
    you will wind up with gaps that lead you down incorrect paths.  Cocoa
    bindings are not difficult to understand or get right once you
    understand KVC and KVO thoroughly, but if you don't understand them
    they will be a mystery and whatever intuitive notion you develop of
    them may be very incorrect.

      -- Chris
previous month september 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Go to today