将对象添加到已排序的NSMutable数组并回答索引路径

时间:2012-03-26 05:00:07

标签: iphone objective-c nsmutablearray nsindexpath

我有一个名为Topic的类的已排序可变数组。主题代表一系列出版物。我在表中提供主题,并定期从Web服务中获取新的出版物。当新出版物到来时,我想用动画添加到表格中。

困扰我的是我需要做的计算工作才能添加到此数组中,并回答正确的索引路径。有人可以提出比这更直接的方式:

// add a publication to the topic model.  if the publication has a new topic, answer
// the index path of the new topic
- (NSIndexPath *)addPublication:(Publication *)pub {

    // first a search to fit into an existing topic
    NSNumber *topicId = [pub valueForKey:@"topic_id"];
    for (Topic *topic in self.topics) {
        if ([topicId isEqualToNumber:[topic valueForKey:"id"]]) {
            // this publication is part of an existing topic, no new index path
            [topic addPublication:pub];
            return nil;
         }
    }

    // the publication must have a new topic, add a new topic (and therefore a new row)
    Topic *topic = [[Topic alloc] initWithPublication:publication];
    [self.topics addObject:topic];

    // sort it into position
    [self.topics sortUsingSelector:@selector(compareToTopic:)];

    // oh no, we want to return an index path, but where did it sort to?
    // yikes, another search!
    NSInteger row = [self.topics indexOfObject:topic];
    return [NSIndexPath indexPathForRow:row inSection:0];
}

// call this in a loop for all the publications I fetch from the server,
// collect the index paths for table animations
// so much computation, poor user's phone is going to melt!

我想,第一次搜索无法解决。但是有没有更有效的方法来为数组添加新东西,维护排序并记住它放在哪里?

3 个答案:

答案 0 :(得分:3)

将值插入排序列表非常简单。想想如何将数字“3”插入到“1,2,7,9”列表中。你想做同样的事情。

使用for循环按索引遍历数组。

对于每个对象,使用compareToTopic:将其与要插入的对象进行比较。

当您找到要插入的相应索引时,请使用-[NSArray insertObject:atIndex:]插入它。

然后返回带有该索引的NSIndexPath

编辑:并且,正如其他答案所指出的那样,二元搜索会更快 - 但要想做对,肯定更难。

答案 1 :(得分:2)

这几乎肯定不是问题; NSArrays are actually hashes,搜索速度比真正的数组快得多。你可能有多少主题?

尽管如此,如果你衡量表现并发现它很差,你可以考虑使用B-tree; Kurt Revis在下面评论了Core Foundation中类似结构(binary heap)的链接:CFBinaryHeap

另一个选项(也需要测量)可能是在第一次走数组时进行比较;你可以标记该位置并直接插入:

NSUInteger insertIndex = 0;
NSComparisonResult prevOrder = NSOrderedDescending;
for (Topic *topic in self.topics) {
    NSComparisonResult order = [topicId compareToTopic:topic];
    if (NSOrderedSame == order) {
        // this publication is part of an existing topic, no new index path
        [topic addPublication:pub];
        return nil;
    }
    else if( prevOrder == NSOrderedDescending && 
             order == NSOrderedAscending )
    {
        break;
    }
    insertIndex++;
    prevOrder = order;
}

请注意,我没有对此进行测试,抱歉。

我不确定这实际上比你写它的方式更好或更快。

不要担心计算机正在做的工作,除非它明显地做得太慢。

答案 2 :(得分:1)

我猜你所做的是正确的。还有另一种方式。您可以编写自己的二进制搜索实现方法。 (其中只有几行代码)。并且您可以检索新对象应该适合的索引。并使用insertObject:atIndex:方法将新对象添加到所需的索引。