是否有更高效的内存搜索核心数据数据库?

时间:2022-10-17 23:21:03

I need to see if an object that I have obtained from a CSV file with a unique identifier exists in my Core Data Database, and this is the code I deemed suitable for this task:

我需要查看我从核心数据库中是否存在从具有唯一标识符的CSV文件中获取的对象,这是我认为适合此任务的代码:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity;
entity = 
[NSEntityDescription entityForName:@"ICD9"
            inManagedObjectContext:passedContext];
[fetchRequest setEntity:entity];
NSPredicate *pred = [NSPredicate predicateWithFormat:@"uniqueID like %@", uniqueIdentifier];
[fetchRequest setPredicate:pred];
NSError *err;
NSArray* icd9s = [passedContext executeFetchRequest:fetchRequest error:&err];
[fetchRequest release];
if ([icd9s count] > 0) {
    for (int i = 0; i < [icd9s count]; i++) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
        NSString *name = [[icd9s objectAtIndex:i] valueForKey:@"uniqueID"];
        if ([name caseInsensitiveCompare:uniqueIdentifier] == NSOrderedSame && name != nil)
        {
            [pool release];
            return [icd9s objectAtIndex:i];
        }
        [pool release];
    }
}
return nil;

After more thorough testing it appears that this code is responsible for a huge amount of leaking in the app I'm writing (it crashes on a 3GS before making it 20 percent through the 1459 items). I feel like this isn't the most efficient way to do this, any suggestions for a more memory efficient way? Thanks in advance!

经过更彻底的测试后,似乎这个代码导致我正在编写的应用程序中出现大量泄漏(它在3GS上崩溃,然后通过1459项目将其降低20%)。我觉得这不是最有效的方法,对于更有效的内存方式有什么建议吗?提前致谢!

2 个解决方案

#1


2  

  • Don't use the like operator in your request predicate. Use =. That should be much faster.
  • 不要在请求谓词中使用like运算符。使用=。那应该快得多。
  • You can specify the case insensitivity of the search via the predicate, using the [c] modifier.
  • 您可以使用[c]修饰符通过谓词指定搜索的大小写不敏感性。
  • It's not necessary to create and destroy an NSAutoreleasePool on each iteration of your loop. In fact, it's probably not needed at all.
  • 没有必要在循环的每次迭代中创建和销毁NSAutoreleasePool。事实上,根本不需要它。
  • You don't need to do any of the checking inside the for() loop. You're duplicating the work of your predicate.
  • 您不需要在for()循环中进行任何检查。您正在复制谓词的工作。

So I would change your code to be:

所以我会将你的代码改为:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:...];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"uniqueID =[c] %@", uniqueIdentifier]];
NSError *err = nil;
NSArray *icd9s = [passedContext executeFetchRequest:fetchRequest error:&err];
[fetchRequest release];
if (error == nil && [icd9s count] > 0) {
  return [icd9s objectAtIndex:0]; //we know the uniqueID matches, because of the predicate
}
return nil;

#2


1  

Use the Leaks template in Instruments to hunt down the leak(s). Your current code may be just fine once you fix them. The leak(s) may even be somewhere other than code.

使用仪器中的泄漏模板来搜索泄漏。修复后,您当前的代码可能会很好。泄漏甚至可能是代码之外的其他地方。

Other problems:

其他问题:

  • Using fast enumeration will make the loop over the array (1) faster and (2) much easier to read.
  • 使用快速枚举将使得数组(1)上的循环更快并且(2)更容易阅读。
  • Don't send release to an autorelease pool. If you ever port the code to garbage-collected Cocoa, the pool will not do anything. Instead, send it drain; in retain-release Cocoa and in Cocoa Touch, this works the same as release, and in garbage-collected Cocoa, it pokes the garbage collector, which is the closest equivalent in GC-land to draining the pool.
  • 不要将版本发送到自动释放池。如果您将代码移植到垃圾收集的Cocoa,则池将不会执行任何操作。相反,发送它流失;在retain-release Cocoa和Cocoa Touch中,这与release相同,并且在垃圾收集的Cocoa中,它会占用垃圾收集器,垃圾收集器是GC-land中最接近排放池的等效物。
  • Don't repeat yourself. You currently have two [pool release]; lines for one pool, which gets every experienced Cocoa and Cocoa Touch programmer really worried. Store the result of your tests upon the name in a Boolean variable, then drain the pool before the condition, then conditionally return the object.
  • 不要重复自己。你目前有两个[池发布];一个池的线条,让每个有经验的Cocoa和Cocoa Touch程序员都非常担心。将测试结果存储在布尔变量中的名称上,然后在条件之前排空池,然后有条件地返回对象。
  • Be careful with variable types. -[NSArray count] returns and -[NSArray objectAtIndex:] takes an NSUInteger, not an int. Try to keep all your types matching at all times. (Switching to fast enumeration will, of course, solve this instance of this problem in a different way.)
  • 注意变量类型。 - [NSArray count]返回 - [NSArray objectAtIndex:]采用NSUInteger,而不是int。尽量保持所有类型的匹配。 (切换到快速枚举当然会以不同的方式解决此问题的这个实例。)
  • Don't hide releases. I almost accused you of leaking the fetch request, then noticed that you'd buried it in the middle of the code. Make your releases prominent so that you're less likely to accidentally add redundant (i.e., crash-inducing) ones.
  • 不要隐藏版本。我几乎指责你泄漏了获取请求,然后注意到你把它埋在了代码的中间。使您的版本突出显示,以便您不太可能意外添加冗余(即崩溃诱导)。

#1


2  

  • Don't use the like operator in your request predicate. Use =. That should be much faster.
  • 不要在请求谓词中使用like运算符。使用=。那应该快得多。
  • You can specify the case insensitivity of the search via the predicate, using the [c] modifier.
  • 您可以使用[c]修饰符通过谓词指定搜索的大小写不敏感性。
  • It's not necessary to create and destroy an NSAutoreleasePool on each iteration of your loop. In fact, it's probably not needed at all.
  • 没有必要在循环的每次迭代中创建和销毁NSAutoreleasePool。事实上,根本不需要它。
  • You don't need to do any of the checking inside the for() loop. You're duplicating the work of your predicate.
  • 您不需要在for()循环中进行任何检查。您正在复制谓词的工作。

So I would change your code to be:

所以我会将你的代码改为:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:...];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"uniqueID =[c] %@", uniqueIdentifier]];
NSError *err = nil;
NSArray *icd9s = [passedContext executeFetchRequest:fetchRequest error:&err];
[fetchRequest release];
if (error == nil && [icd9s count] > 0) {
  return [icd9s objectAtIndex:0]; //we know the uniqueID matches, because of the predicate
}
return nil;

#2


1  

Use the Leaks template in Instruments to hunt down the leak(s). Your current code may be just fine once you fix them. The leak(s) may even be somewhere other than code.

使用仪器中的泄漏模板来搜索泄漏。修复后,您当前的代码可能会很好。泄漏甚至可能是代码之外的其他地方。

Other problems:

其他问题:

  • Using fast enumeration will make the loop over the array (1) faster and (2) much easier to read.
  • 使用快速枚举将使得数组(1)上的循环更快并且(2)更容易阅读。
  • Don't send release to an autorelease pool. If you ever port the code to garbage-collected Cocoa, the pool will not do anything. Instead, send it drain; in retain-release Cocoa and in Cocoa Touch, this works the same as release, and in garbage-collected Cocoa, it pokes the garbage collector, which is the closest equivalent in GC-land to draining the pool.
  • 不要将版本发送到自动释放池。如果您将代码移植到垃圾收集的Cocoa,则池将不会执行任何操作。相反,发送它流失;在retain-release Cocoa和Cocoa Touch中,这与release相同,并且在垃圾收集的Cocoa中,它会占用垃圾收集器,垃圾收集器是GC-land中最接近排放池的等效物。
  • Don't repeat yourself. You currently have two [pool release]; lines for one pool, which gets every experienced Cocoa and Cocoa Touch programmer really worried. Store the result of your tests upon the name in a Boolean variable, then drain the pool before the condition, then conditionally return the object.
  • 不要重复自己。你目前有两个[池发布];一个池的线条,让每个有经验的Cocoa和Cocoa Touch程序员都非常担心。将测试结果存储在布尔变量中的名称上,然后在条件之前排空池,然后有条件地返回对象。
  • Be careful with variable types. -[NSArray count] returns and -[NSArray objectAtIndex:] takes an NSUInteger, not an int. Try to keep all your types matching at all times. (Switching to fast enumeration will, of course, solve this instance of this problem in a different way.)
  • 注意变量类型。 - [NSArray count]返回 - [NSArray objectAtIndex:]采用NSUInteger,而不是int。尽量保持所有类型的匹配。 (切换到快速枚举当然会以不同的方式解决此问题的这个实例。)
  • Don't hide releases. I almost accused you of leaking the fetch request, then noticed that you'd buried it in the middle of the code. Make your releases prominent so that you're less likely to accidentally add redundant (i.e., crash-inducing) ones.
  • 不要隐藏版本。我几乎指责你泄漏了获取请求,然后注意到你把它埋在了代码的中间。使您的版本突出显示,以便您不太可能意外添加冗余(即崩溃诱导)。