在NSTableView的运行时计算组行

时间:2013-01-02 18:42:37

标签: objective-c macos cocoa nstableview

我有NSTableView,充满了歌曲标题。

歌曲由艺术家订购,因此我可以将艺术家名称显示为行视图。

enter image description here


代码

到现在为止,我不得不遍历表数据并手动将艺术家添加到数组中。

NSMutableArray *songsAndArtists = [NSMutableArray array];

Artist *artist;
for (Song *song in self.songs) {
    if (artist != song.artist) {
        artist = song.artist;
        [songsAndArtists addObject:artist];
    }

    [songsAndArtists addObject:song];
}

如果你有1'000 - 5'000首歌,这可能会非常慢 我还没弄清楚如何加快这个过程。

有人知道如何在运行时计算这个吗?


修改

我会试着澄清我的意思:

NSTableView支持组行。我的表格视图显示CoreData中的所有歌曲。 我想使用组行来显示歌曲的艺术家,就像我在上面添加的打印屏幕一样。

要做到这一点,我必须提供一个包含艺术家的数组,然后是它的歌曲,然后是下一个艺术家,依此类推。

上面的代码展示了如何插入艺术家,但这是一个非常耗时的过程。

所以我的问题是,我怎样才能加快速度呢?


HINT

nielsbotFeloneous Cat建议一样,遍历所有艺术家将不适合我。

用户还可以选择搜索库。 因此,并非所有歌曲都应该出现在列表中。


解决方案

我只是想让你告诉你问题是什么:

问题是,我实际上是通过前一版本中的NSString进行比较的 非常愚蠢的错误...

0.1秒或更短非常棒:

tableData = [self addGroupRowsToArray:[self allSongs] withKeyPath:@"artist"];

- (NSArray *)addGroupRowsToArray:(NSArray *)array withKeyPath:(NSString *)keyPath {
    NSMutableArray *mixedArray = [NSMutableArray array];

    id groupRowItem;
    for (id arrayItem in array) {
        if (groupRowItem != [arrayItem valueForKeyPath:keyPath]) {
            groupRowItem = [arrayItem valueForKeyPath:keyPath];
            [mixedArray addObject:groupRowItem];
        }

        [mixedArray addObject:arrayItem];
    }

    return mixedArray;
}

3 个答案:

答案 0 :(得分:3)

这更快吗?

-(NSArray*)songsAndArtists:(NSArray*)allArtists
{
    NSMutableArray * result = [ NSMutableArray array ] ;
    for( Artist * artist in allArtists )
    {
        [ result addObject:artist ] ;
        [ result addObjectsFromArray:artist.songs ] ;
    }
    return result ;
}

如果您从Core Data获得“所有艺术家”,您可以告诉它预取歌曲关系中的对象,这将加快进度。

-(NSArray*)allArtists
{
    NSFetchRequest * request = [ NSFetchRequest fetchRequestWithEntityName:@"Artist" ] ;
    [ request setRelationshipKeyPathsForPrefetching:@[ @"songs" ] ] ;
    ...
    return results ;
}

答案 1 :(得分:3)

所以,让我们回头看看你真正拥有的东西。您已经拥有了歌曲中所需的所有信息。为什么你只是为了突破艺术家而复制它?

如果您有以下歌曲(歌曲/艺术​​家)

,请按照这种方式考虑
(0)    "Death Eater", "Raging Machine Code"
(1)    "Interrupt",   "Raging Machine Code"
(2)    "Panic",       "Times Square Revolution"
(3)    "New Years",   "Times Square Revolution"
(4)    "Toast",       "Ed & Billy's Time Machine"
(5)    "Surge",       "Quiet Cat"
(6)    "Surveil",     "Quiet Cat"

这张照片出了什么问题?我们有相同的信息重复。理想情况下,我们想要这样的东西:

"Raging Machine Code"     -> has an  array that contains
                             "Death Eater"
                             "Interrupt"
"Times Square Revolution" -> has an array that contains
                             "Panic"
                             "New Years"
"Ed & Billy's Time Machine" -> array that contains
                             "Toast"
"Quiet Cat"               -> array that contains
                             "Surge"
                             "Surveil"

对于UITableView,这让事情变得微不足道 - 我们告诉它有多少部分(四个)和每个部分有多少首歌曲。为了生成单元格,我们得到一个NSIndexPath,它告诉我们节和行(节将是艺术家,行将是该艺术家的歌曲)。

NSTableView不这样做。它给了我们一排。但是,如果我们在前端做一些工作(即歌曲列表),那么我们可以确保生活将是美丽和快速的(或至少更快)。关键是预先计算每位艺术家的歌曲数量并存储它。

因此假设我们被要求显示第5行。“Raging Machine Code”是0-2(艺术家,歌曲,歌曲)。 “时代广场革命”是3-5。啊! 5是最后一首歌,所以我们显示“新年”!

尝试另一个,假设我们要显示第6行。“Raging ...”为0-2,“Times ......”为3-5,“Ed& Billy”为6-7。 Bingo,我们需要展示艺术家,“Ed& Billy的Time Machine”!

我们的想法是,我们在实际显示数据的前提下做了很多工作。通过艺术家循环将比循环播放所有歌曲要快得多。此外,现在你只做简单的数学运算 - 不需要搬东西。

有时,您存储数据的方式意味着成功与失败之间的差异。每当你发现自己必须“重新定义数据结构”时,通常意味着你的数据结构有问题 - 它可能很简单,但它会带来更多的努力。

希望这很有帮助,并没有最终成为“TLTR”(太长时间无法阅读)。

答案 2 :(得分:3)

好吧,我试图重现你的问题。我不知道你从哪里获取数据,因此我只是为了性能测试而伪造它们。我还测试了iPod 4gen上的代码,它没有任何延迟。 (尝试了50000行,它只在开始时挂起,然后完美地工作)

一般来说,我的方法与您的数据结构不同。所以你使用数组,我使用字典。我仍然认为,如果我使用数组,反正应该没有问题。也许我错了你所问的是什么?

尽管如此,我的方法似乎更适合搜索工作(sry我已经太费力去尝试实现它了)。实际上,现在进行搜索,可以排除整个部分而不检查歌曲,除非你需要搜索歌曲当然,无论如何这会提供更大的灵活性。

好的,这是一个链接:https://github.com/igorpakushin/BigList

很高兴在这里得到一些反馈, 谢谢

的问候, 伊戈尔