面试题答案
一键面试可能导致性能问题的原因
- 缺乏索引:Core Data默认不会自动为实体属性创建索引。在复杂多条件查询时,如果查询涉及的属性没有索引,数据库需要全表扫描,导致性能下降。例如,如果经常按某个
NSString
类型的属性name
进行查询,而name
属性没有索引,查询速度会很慢。 - 大数据集加载:一次性加载大量数据到内存,会占用过多内存资源,导致应用响应变慢。特别是在使用
fetchRequest
获取数据时,如果没有对结果集进行适当的限制。比如,没有设置fetchLimit
。 - 复杂的对象图:如果Core Data实体之间存在复杂的关系(如多层级的
to - many
关系),在获取数据时,MagicalRecord可能会加载过多不必要的关联对象,增加了数据加载的复杂度和时间。 - 缓存未合理使用:没有合理利用缓存机制,每次查询都从数据库获取数据,而不是优先从缓存中读取,增加了数据库的负载。
利用MagicalRecord特性及相关技术手段优化性能
- 设置数据库索引
- 在Core Data模型编辑器中,为经常用于查询的属性设置索引。例如,假设我们有一个
Person
实体,经常按age
和email
属性进行查询:
// 在Core Data模型文件中,选中Person实体的age属性,在Attributes Inspector中勾选Indexed // 同样为email属性勾选Indexed
- 代码中进行查询时,索引会提升性能:
NSFetchRequest *fetchRequest = [Person MR_fetchRequest]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age > %d AND email CONTAINS[cd] %@", 18, @"example.com"]; [fetchRequest setPredicate:predicate]; NSArray *people = [Person MR_executeFetchRequest:fetchRequest];
- 在Core Data模型编辑器中,为经常用于查询的属性设置索引。例如,假设我们有一个
- 限制结果集
- 使用
fetchLimit
限制每次从数据库获取的数据数量。比如,我们只想获取最新的10条记录:
NSFetchRequest *fetchRequest = [SomeEntity MR_fetchRequest]; [fetchRequest setFetchLimit:10]; NSArray *limitedResults = [SomeEntity MR_executeFetchRequest:fetchRequest];
- 使用
- 优化对象图加载
- 对于
to - many
关系,如果不需要立即加载所有关联对象,可以使用faulting
机制。MagicalRecord默认支持faulting
。例如,有一个Department
实体和Employee
实体,Department
有一个to - many
关系employees
。
Department *department = [Department MR_findFirst]; // 此时,department.employees不会立即加载所有员工数据,而是一个fault对象 // 只有当真正访问department.employees时,数据才会从数据库加载
- 如果确定只需要部分关联对象,可以使用
NSFetchRequest
的relationshipKeyPathsForPrefetching
来预取特定的关联对象。假设Employee
有一个to - one
关系manager
,我们在获取Employee
时预取manager
:
NSFetchRequest *fetchRequest = [Employee MR_fetchRequest]; [fetchRequest setRelationshipKeyPathsForPrefetching:@[@"manager"]]; NSArray *employees = [Employee MR_executeFetchRequest:fetchRequest];
- 对于
- 缓存策略
- 可以使用
NSCache
来实现简单的缓存机制。例如,我们经常按某个特定条件查询数据,并且结果相对稳定:
static NSCache *queryCache; + (void)initialize { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ queryCache = [[NSCache alloc] init]; }); } - (NSArray *)cachedResultsForQuery:(NSString *)queryString { return [queryCache objectForKey:queryString]; } - (void)cacheResults:(NSArray *)results forQuery:(NSString *)queryString { [queryCache setObject:results forKey:queryString]; } // 在查询方法中使用缓存 - (NSArray *)fetchDataWithQuery:(NSString *)query { NSArray *cachedResults = [self cachedResultsForQuery:query]; if (cachedResults) { return cachedResults; } NSFetchRequest *fetchRequest = [SomeEntity MR_fetchRequest]; NSPredicate *predicate = [NSPredicate predicateWithFormat:query]; [fetchRequest setPredicate:predicate]; NSArray *results = [SomeEntity MR_executeFetchRequest:fetchRequest]; [self cacheResults:results forQuery:query]; return results; }
- 可以使用