我的项目实现了与iCloud的核心数据同步。当我尝试删除重复项时,出现以下异常:
-[NSFunctionExpression _propertyType]:无法识别的选择器已发送到实例
我已经读到这种问题的主要原因是在不同线程上使用相同的托管对象上下文。但是,就我而言,所有进程都是在主线程上完成的。我不知道如何解决此问题。
在初始化方法中,我添加以下观察者:
[[NSNotificationCenter defaultCenter] addObserverForName:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:self.managedObjectContext.persistentStoreCoordinator
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
NSLog(@"NSPersistentStoreDidImportUbiquitousContentChangesNotification received");
[self.managedObjectContext performBlock:^{
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:note];
[self filterDuplicates]; <-- Here I call method to call filtering duplicates
}];
}];
重复方法:
- (void) filterDuplicates {
NSString *uniquePropertyKey = @"name";
NSString *entityName = @"SFGallery";
NSExpression *countExpression = [NSExpression expressionWithFormat:@"count:(%@)", uniquePropertyKey];
NSExpressionDescription *countExpressionDescription = [[NSExpressionDescription alloc] init];
[countExpressionDescription setName:@"count"];
[countExpressionDescription setExpression:countExpression];
[countExpressionDescription setExpressionResultType:NSInteger64AttributeType];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:self.managedObjectContext];
NSAttributeDescription *uniqueAttribute = [[entity attributesByName] objectForKey:uniquePropertyKey];
// Fetch the number of times each unique value appears in the store.
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:entityName];
fetchRequest.propertiesToFetch = @[uniqueAttribute, countExpression];
fetchRequest.propertiesToGroupBy = @[uniqueAttribute];
fetchRequest.resultType = NSDictionaryResultType;
fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES]];
NSArray *fetchedDictionaries = [self fetchAlbumsWithFetchRequest:fetchRequest];
// Filter out unique values that have no duplicates.
NSMutableArray *valuesWithDupes = [NSMutableArray array];
for (NSDictionary *dict in fetchedDictionaries) {
NSNumber *count = dict[@"count"];
if ([count integerValue] > 1) {
[valuesWithDupes addObject:dict[uniquePropertyKey]];
}
}
NSFetchRequest *dupeFetchRequest = [NSFetchRequest fetchRequestWithEntityName:entityName];
dupeFetchRequest.includesPendingChanges = NO;
dupeFetchRequest.fetchBatchSize = 20;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name IN (%@)", valuesWithDupes];
dupeFetchRequest.predicate = predicate;
NSArray *dupes = [self fetchAlbumsWithFetchRequest:dupeFetchRequest];
SFGallery *prevObject;
for (SFGallery *duplicate in dupes) {
if (prevObject) {
if ([duplicate.name isEqualToString:prevObject.name]) {
if ([duplicate.timestamp compare:prevObject.timestamp] == NSOrderedAscending) {
[self.managedObjectContext deleteObject:duplicate];
} else {
[self.managedObjectContext deleteObject:prevObject];
prevObject = duplicate;
}
} else {
prevObject = duplicate;
}
} else {
prevObject = duplicate;
}
}
}
以及发生异常时的方法:
- (NSArray *)fetchAlbumsWithFetchRequest:(NSFetchRequest *)fetchRequest {
Exception Here ---> NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
NSError *error = nil;
if (![fetchedResultsController performFetch:&error]) {
NSLog(@"Error when fetching Albums: %@", [error userInfo]);
return nil;
}
return fetchedResultsController.fetchedObjects;
}
有什么帮助吗?
编辑1:
我很确定它与NSFetchRequest有关。
NSFetchRequest实例具有设置的属性属性:
fetchRequest.propertiesToFetch = @[uniqueAttribute, countExpression];
这就是带来问题的
countExpression
。在异常断点上,我记录了提取请求对象,并得到以下信息:
<NSFetchRequest: 0x10c58b4a0> (entity: SFGallery; predicate: ((null)); sortDescriptors: ((
"(timestamp, descending, compare:)"
)); type: NSDictionaryResultType; includesPendingChanges: NO; propertiesToFetch: ((
"(<NSAttributeDescription: 0x10c56e5c0>), name title, isOptional 1, isTransient 0, entity SFGallery, renamingIdentifier title, validation predicates (\n), warnings (\n), versionHashModifier (null)\n userInfo {\n}, attributeType 700 , attributeValueClassName NSString, defaultValue (null)",
"count:(\"title\")"
)); propertiesToGroupBy: ((
"(<NSAttributeDescription: 0x10c56e5c0>), name title, isOptional 1, isTransient 0, entity SFGallery, renamingIdentifier title, validation predicates (\n), warnings (\n), versionHashModifier (null)\n userInfo {\n}, attributeType 700 , attributeValueClassName NSString, defaultValue (null)"
)); )
这将引发调用堆栈:
0 CoreFoundation 0x0000000103692495 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001033ca99e objc_exception_throw + 43
2 CoreFoundation 0x000000010372365d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x0000000103683d8d ___forwarding___ + 973
4 CoreFoundation 0x0000000103683938 _CF_forwarding_prep_0 + 120
5 CoreData 0x0000000100d7812d -[NSFetchRequest _newValidatedProperties:groupBy:error:] + 541
6 CoreData 0x0000000100d0da63 -[NSFetchRequest(_NSInternalMethods) _resolveEntityWithContext:] + 179
7 CoreData 0x0000000100e03c2b -[NSFetchedResultsController initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:] + 555
8 myAppli 0x000000010003d2d3 -[SFCoreDataManager fetchAlbumsWithFetchRequest:] + 163
9 myAppli 0x000000010003c901 -[SFCoreDataManager filterDuplicates] + 1073
10 myAppli 0x00000001000271cb -[SFDebugViewController removeDuplicates:] + 91
11 UIKit 0x0000000101d0af06 -[UIApplication sendAction:to:from:forEvent:] + 80
12 UIKit 0x0000000101d0aeb4 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 17
13 UIKit 0x0000000101de7880 -[UIControl _sendActionsForEvents:withEvent:] + 203
14 UIKit 0x0000000101de6dc0 -[UIControl touchesEnded:withEvent:] + 530
15 UIKit 0x0000000101d41d05 -[UIWindow _sendTouchesForEvent:] + 701
16 UIKit 0x0000000101d426e4 -[UIWindow sendEvent:] + 925
17 UIKit 0x0000000101d1a29a -[UIApplication sendEvent:] + 211
18 UIKit 0x0000000101d07aed _UIApplicationHandleEventQueue + 9579
19 CoreFoundation 0x0000000103621d21 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
20 CoreFoundation 0x00000001036215f2 __CFRunLoopDoSources0 + 242
21 CoreFoundation 0x000000010363d46f __CFRunLoopRun + 767
22 CoreFoundation 0x000000010363cd83 CFRunLoopRunSpecific + 467
23 GraphicsServices 0x000000010482cf04 GSEventRunModal + 161
24 UIKit 0x0000000101d09e33 UIApplicationMain + 1010
25 myAppli 0x0000000100010473 main + 115
26 libdyld.dylib 0x0000000103ea55fd start + 1
27 ??? 0x0000000000000001 0x0 + 1
编辑2:
当我得到证明时:
[NSFunctionExpression _propertyType]: unrecognized selector sent to instance 0x10c433d90
用
po [0x10c433d90 class]
打印实例后我得到
NSFunctionExpression
最佳答案
上面包含的代码部分来自Apple示例代码。
来源是:https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/UsingSQLiteStoragewithiCloud/UsingSQLiteStoragewithiCloud.html
我不敢相信苹果工程师在提供样本之前不会测试代码。
首先,应该以这种方式定义表达式:
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:uniquePropertyKey];
NSExpression *countExpression = [NSExpression expressionForFunction: @"count:" arguments:@[keyPathExpression]];
在这种情况下,实际上令我感到惊讶的是,为什么此实现不起作用:
NSExpression *countExpression = [NSExpression expressionWithFormat:@"count:(%@)", uniquePropertyKey];
可能是一个知道为什么可以分享一些知识的人
还有苹果的 Shiny 花朵:
fetchRequest.propertiesToFetch = @[uniqueAttribute, countExpression];
应该
fetchRequest.propertiesToFetch = @[uniqueAttribute, countExpressionDescription];
我希望这个答案可以节省很多时间