优化Cocoa / Objective-C搜索

时间:2009-07-01 16:36:37

标签: iphone objective-c cocoa-touch algorithm optimization

我正在搜索一个包含字典的大型plist文件,其中包含数以万计的字典,每个都有2个键/字符串对。我的搜索算法遍历字典,当它在字典中的任何一个字符串中找到文本匹配时,将插入字典的内容。以下是它的工作原理:

NSDictionary *eachEntry;
NSArray *rawGlossaryArray = [[NSArray alloc] initWithContentsOfFile:thePath]; // this contains the contents of the plist

for (eachEntry in rawGlossaryArray)
    {
        GlossaryEntry *anEntry = [[GlossaryEntry alloc] initWithDictionary:eachEntry];


        NSRange titleResultsRange = [anEntry.title rangeOfString:filterString options:NSCaseInsensitiveSearch];
        NSRange defResultsRange = [anEntry.definition rangeOfString:filterString options:NSCaseInsensitiveSearch];

        if (titleResultsRange.length > 0 || defResultsRange.length > 0) {
            // store that item in the glossary dictionary with the name as the key
            [glossaryDictionary setObject:anEntry forKey:anEntry.title];

        }
        [anEntry release];
    }

每次执行搜索时,我的iPhone应用程序都会延迟大约3-4秒(至少在设备上;所有内容在模拟器中运行得非常快)。任何人都可以建议我如何优化此搜索?

7 个答案:

答案 0 :(得分:2)

如果不查看数据集,我无法确定,但如果您对其进行分析,那么您将花费大量时间在-rangeOfString:options:。如果是这种情况,如果不从根本上改变用于存储数据的数据结构,您将无法提高性能。

您可能希望使用指向对象的字符串和子字符串构造一些排序trie。设置要复杂得多,插入它会更加昂贵,但查找速度会非常快。鉴于您正在序列化结构,无论如何昂贵的插入应该不是一个问题。

答案 1 :(得分:2)

这只是急于使用数据库,你预先填充并放入应用程序。

答案 2 :(得分:1)

一些建议:

  1. 你在那个循环中做了很多分配和释放。你能在循环之前创建一个GlossaryEntry,然后只是在循环中重新加载它的内容吗?这样可以避免一堆分配/释放。

  2. 不是每次都加载文件,你是否可以延迟加载一次并将其缓存在内存中(可能是单例类型的对象)?一般来说,这在iPhone上并不是一个好主意,但你可以在你的“didReceiveMemoryWarning”处理程序中使用一些代码,如果它成为一个问题就会释放缓存。

答案 3 :(得分:1)

你应该运行你的应用程序是Instruments,看看瓶颈究竟是什么。盲人中的性能优化确实很困难,而且我们有工具使它们清晰,工具也很好!

还有可能这是不可优化的。我不确定它是否真的在你的应用程序中挂起UI或者只是花了很长时间。如果它阻止了UI,你需要离开主线程来完成这项工作。与保持应用响应的任何重要工作相同。

答案 4 :(得分:1)

尝试以下操作,看看是否有任何改进:

1)使用

- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask

并作为掩码,传递值NSLiteralSearch。这可能会大大加快搜索速度,如Apple文档(Cocoa的字符串编程指南)中所述:

NSLiteralSearch执行逐字节比较。不同的文字序列(例如组合的字符序列)被认为是等同的被认为是不匹配的。使用此选项可以显着加快某些操作。

2)从文档(Cocoa的字符串编程指南):

如果您只想确定字符串是否包含给定模式,则可以使用谓词:

BOOL match = [myPredicate evaluateWithObject:myString];

有关谓词的更多信息,请参阅谓词编程指南。

答案 5 :(得分:1)

根据您当前的数据结构,您可能获得了可能获得的最佳性能。您需要更改访问数据的方式,以获得更好的性能。

建议,没有特别的顺序:

  1. 在过滤时,不要在循环中创建GlossaryEntry对象。而不是将数据存储在属性列表中,只需归档您的GlossaryEntry对象数组。请参阅NSCoding文档。

  2. 不是在每次击键时搜索成千上万的字符串,而是生成公共子串的索引(可能是2或3个字母),并创建一个从该公共子串映射到要使用的结果集的NSDictionary作为一个指标。您可以在构建时创建索引,而不是在运行时创建索引。如果您可以将数据集切割成几个较小的部分,则匹配字符串的线性搜索将会快得多。

  3. 将您的数据存储在SQLite数据库中,并使用SQL进行查询 - 可能只是针对此问题,但如果您需要,可以在将来进行更复杂的搜索。

    < / LI>
  4. 如果创建简单索引的效果不佳,则需要创建搜索树样式数据结构。

答案 6 :(得分:0)

您应该在仪器中对其进行分析,以找出瓶颈实际存在的位置。如果我不得不猜测,我会说瓶颈是[[NSArray alloc] initWithContentsOfFile:thePath]。

话虽如此,您可能会通过将数据存储在sqlite数据库(您将使用SQL搜索)而不是使用plist来获得最佳性能。