propertiesToFetch对Core Data性能的影响:未指定属性为何仍可访问?
问题背景
存在一个Person实体,包含name、age、gender、photo(Transformable类型,用于存储UIImage内容)属性。在大量保存Person对象后,查询列表耗时约5秒,推测是photo属性导致的性能问题。设置propertiesToFetch为@[@"name", @"age", @"gender"]、resultType为NSManagedObjectResultType后,查询速度大幅提升,但产生两个疑问。
相关代码
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Person"]; fetchRequest.propertiesToFetch = @[@"name", @"age", @"gender"]; fetchRequest.resultType = NSManagedObjectResultType; NSError *error = nil; NSArray *results = [context executeFetchRequest:fetchRequest error:&error]; if (results) { for (NSManagedObject *object in results) { NSString *name = [object valueForKey:@"name"]; NSNumber *age = [object valueForKey:@"age"]; NSString *gender = [object valueForKey:@"gender"]; UIImage *photo = [object valueForKey:@"photo"]; // Why is photo not nil? } } else { NSLog(@"Error fetching data: %@", error); }
疑问解答
1. 未将photo加入propertiesToFetch,为何该属性仍可访问,而非nil?
当resultType设为NSManagedObjectResultType时,propertiesToFetch的作用是指定查询时预先加载到内存的属性,而非限制托管对象可访问的属性范围。Core Data的托管对象(NSManagedObject)采用懒加载机制:当你访问photo属性时,它会自动从持久化存储(或同步后的CloudKit本地缓存)中实时获取该属性的值,只要该属性在存储中本身不为nil,就能拿到对应的值,不会返回nil。
2. 既然photo仍能被查询到,为何查询速度会提升?
默认情况下,Core Data查询托管对象时,会把该对象的所有属性一次性加载到内存。你的photo是存储UIImage的Transformable属性,数据体积远大于其他三个基础属性,大量Person对象同时加载这些大体积数据,会导致IO耗时剧增、内存占用飙升,最终拖慢查询速度。
设置propertiesToFetch后,Core Data只会预先加载你指定的name、age、gender三个小体积属性,这一步的数据量极小,所以查询速度大幅提升。而photo属性只有在你主动访问它的时候才会触发加载操作,在遍历列表的代码中,如果没有访问photo,就不会产生额外的IO开销,整体查询流程自然变快。
内容的提问来源于stack exchange,提问作者Lix

