NSMutableArray将对象从一个索引移动到另一个索引

78

我有一个带有可重排行的UItableview,数据存储在NSarray中。那么当合适的tableview代理被调用时,如何移动NSMutablearray中的对象?

换句话说,如何重新排序NSMutableArray?


1
本页上的《表格视图编程指南》中的“清单8-2”展示了如何执行此操作。 - user467105
http://www.icab.de/blog/2009/11/15/moving-objects-within-an-nsmutablearray/ - Hemang
7个回答

123
id object = [[[self.array objectAtIndex:index] retain] autorelease];
[self.array removeObjectAtIndex:index];
[self.array insertObject:object atIndex:newIndex];

就这样。要注意保留计数非常重要,因为数组可能是唯一引用对象的东西。


由于您已经保留了指针,那么自动释放的理由并不多,对吧?与其在移除之前进行保留,然后在插入之后进行释放。 - Sixten Otto
是的,没错。只是这样可以少一行代码,但我理解你的意思,直接发布会更便宜。对于一个对象,我并不介意,但在(紧)循环中最好避免这样做。 - Joost
3
当需要交换两个数组元素时,可以使用该方法:- (void)exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2; - Saren Inden
6
因为该方法交换指定的对象,而不是将单个对象移动到其他位置。 - Joost

51

符合ARC标准的类别:

NSMutableArray+Convenience.h

@interface NSMutableArray (Convenience)

- (void)moveObjectAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex;

@end

NSMutableArray+Convenience.m

@implementation NSMutableArray (Convenience)

- (void)moveObjectAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex
{
    // Optional toIndex adjustment if you think toIndex refers to the position in the array before the move (as per Richard's comment)
    if (fromIndex < toIndex) {
        toIndex--; // Optional 
    }

    id object = [self objectAtIndex:fromIndex];
    [self removeObjectAtIndex:fromIndex];
    [self insertObject:object atIndex:toIndex];
}

@end

用法:

[mutableArray moveObjectAtIndex:2 toIndex:5];

6
如果你的fromIndex小于toIndex,最好将toIndex减小。 - Richard
2
如果您正在指定一个在移动之前的数组位置作为toIndex,则Richard的观点是有效的。如果这是您的期望,那么您可能应该按建议减少toIndex。但是,如果您正在指定一个在数组中最终位置的toIndex,则不应该递减。 - Oliver Pearmain
2
@OliverPearmain 抱歉,我很难理解那个想法。使用您的方法(带有建议的递减),在调用moveObjectAtIndex:0 toIndex:1后,数组 [A,B,C] 将保持不变。这合乎逻辑吗? - Stuart
1
remove 有效地减少了 fromIndex 后所有对象的索引。 - Richard

14

使用 Swift 的 Array 就像这样简单:

Swift 3

extension Array {
    mutating func move(at oldIndex: Int, to newIndex: Int) {
        self.insert(self.remove(at: oldIndex), at: newIndex)
    }
}

Swift 2

extension Array {
    mutating func moveItem(fromIndex oldIndex: Index, toIndex newIndex: Index) {
        insert(removeAtIndex(oldIndex), atIndex: newIndex)
    }
}

2
如果您有一个NSArray,由于它是不可变的,因此无法移动或重新排序任何内容。
您需要一个NSMutableArray。使用它,您可以添加和替换对象,这当然也意味着您可以重新排序数组。

0

类似于Tomasz,但具有超出范围错误处理

enum ArrayError: ErrorType {
    case OutOfRange
}

extension Array {
    mutating func move(fromIndex fromIndex: Int, toIndex: Int) throws {
        if toIndex >= count || toIndex < 0 {
            throw ArrayError.OutOfRange
        }
        insert(removeAtIndex(fromIndex), atIndex: toIndex)
    }
}

0

不行。 NSArray 是不可变的。你可以将该数组复制到一个NSMutableArray中(或者一开始就使用它)。可变版本有方法来移动和交换其项目。


抱歉,我的意思是可变的,但NSMutableArray没有移动方法。 - Jonathan.
5
有的。尝试使用-exchangeObjectAtIndex:withObjectAtIndex:,还有各种排序方法。 - Sixten Otto
2
不是交换两个对象,我想移动一个。 - Jonathan.
正如其他帖子中所指出的,您需要删除并重新添加。 - Sixten Otto

0

我猜如果我理解正确,你可以这样做:

- (void) tableView: (UITableView*) tableView moveRowAtIndexPath: (NSIndexPath*)fromIndexPath toIndexPath: (NSIndexPath*) toIndexPath

{
    [self.yourMutableArray moveRowAtIndex: fromIndexPath.row toIndex: toIndexPath.row]; 
    //category method on NSMutableArray to handle the move
}

那么你可以做的是,使用 - insertObject:atIndex: 方法为 NSMutableArray 添加一个分类方法来处理移动。


是的,我正在尝试找到类别方法的代码以实现它,应该是插入然后删除吗? - Jonathan.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接