2

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

歌曲按艺术家排序,因此我可以将艺术家姓名显示为行视图。

在此处输入图像描述


代码

到目前为止,我必须遍历表数据并手动将艺术家添加到数组中。

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 中的所有歌曲。我想使用组行来显示歌曲的艺术家,就像我在上面添加的打印屏幕一样。

为此,我必须提供一个包含艺术家的数组,然后是歌曲,然后是下一位艺术家,依此类推。

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

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


暗示

就像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;
}
4

3 回答 3

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's”是 6-7。宾果游戏,我们需要展示艺术家“Ed & Billy's Time Machine”!

这个想法是,我们在实际显示数据之前做了大量的准备工作。循环播放艺术家将比循环播放所有歌曲快得多。另外,现在你只做简单的数学运算——不需要移动东西。

有时,您如何存储数据意味着成功与失败之间的区别。每当您看到自己必须“重新定义数据结构”时,这通常意味着您的数据结构有问题——这可能很简单,但会带来更多的努力。

希望这会有所帮助,并且最终不会成为“TLTR”(阅读时间过长)。

于 2013-01-04T21:26:09.797 回答
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 ;
}
于 2013-01-04T21:20:39.737 回答
3

好吧,我试图重现你的问题。我不知道你从哪里得到数据,所以我伪造它们只是为了进行性能测试。我还在 iPod 4gen 上测试了代码,它运行起来没有任何延迟。(尝试了 50000 行,它只在启动时挂起,然后完美运行)

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

尽管如此,我的方法似乎更适合搜索工作(对不起,我太费心去尝试实现它)。确实,现在要进行搜索,可能会在不检查歌曲的情况下排除整个部分,除非您当然需要搜索歌曲,无论如何这提供了更大的灵活性。

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

很高兴在这里提供一些反馈,谢谢

问候,伊戈尔

于 2013-01-12T00:11:10.313 回答