NSManagedObject 自定义访问器方法
我希望有人能给我一些有用的建议,告诉我该怎么做。
我一直在尝试多种方法来对一组具有 client<-->>job 关系的实体进行排序,这些实体基于 client 属性的自定义访问器作为第一个排序描述符,然后作业描述属性作为第二个排序描述符。
我首先尝试使用名为 Client.sortValue 的瞬态属性,并发现瞬态属性不能用作 NSFetchedResultsController 的排序描述符。所以我将属性 Client.sortValue 更改为非瞬态的。
我从不将 sortValue 的值保存到持久存储中。相反,我使用自定义访问器。显然,当运行 fetechedResultsController PerformFetch: 方法时,没有使用自定义访问器方法。当我进行日志记录时会调用它,如下面的代码所示。我可以看到,在自定义访问器中使用断点并查看堆栈跟踪就是这种情况。当运行 PerformFetch 时,我没有看到它在访问器方法上中断,但是当日志记录完成时,它确实在访问器方法上中断。
(奇怪的是,今天早些时候我在某些情况下让它工作,但在其他情况下却不行。它显然是按照我想要的方式排序的,但是在我重构代码以追踪它工作的条件之后,我还没有看到它再次工作。)
我尝试了各种自定义访问器方法,包括以下方法:
- (NSString *) primitiveSortValue {
NSString *retVal = nil;
[self willAccessValueForKey:@"lastName"];
[self willAccessValueForKey:@"firstName"];
[self willAccessValueForKey:@"company"];
if (![self.lastName isNullString] ) retVal = [self primitiveValueForKey:@"lastName"];
else if (![self.firstName isNullString] ) retVal = [self primitiveValueForKey:@"firstName"];
else if (![self.company isNullString] ) retVal = [self primitiveValueForKey:@"company"];
else retVal = @"";
[self didAccessValueForKey:@"lastName"];
[self didAccessValueForKey:@"firstName"];
[self didAccessValueForKey:@"company"];
NSLog(@"Sort Value: %@", retVal);
return retVal;
}
在决定覆盖原始访问器方法之前我也尝试过这个方法:
- (NSString *) sortValue {
NSString *retVal = nil;
if (![self.lastName isNullString] ) retVal = self.lastName;
else if (![self.firstName isNullString] ) retVal = self.firstName;
else if (![self.company isNullString] ) retVal = self.company;
else retVal = @"";
NSLog(@"Sort Value: %@", retVal);
return retVal;
}
这是我的 fetchedResultsController 方法:
#define CLIENT_SORT_KEY @"clientOfJob.sortValue"
- (NSFetchedResultsController *) fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription * entity = [NSEntityDescription entityForName:@"Job" inManagedObjectContext:dataInterface.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:10];
if (segmentedControl.selectedSegmentIndex == 0) { // sort by client, then job dscription
NSSortDescriptor *clientSortDescriptor = [[NSSortDescriptor alloc] initWithKey:CLIENT_SORT_KEY ascending:YES];
NSSortDescriptor *jobSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"jobDescription" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:clientSortDescriptor, jobSortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:dataInterface.managedObjectContext
sectionNameKeyPath:CLIENT_SORT_KEY
cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[jobSortDescriptor release];
[clientSortDescriptor release];
[sortDescriptors release];
}
else { // sort by job description
... }
NSError *error = nil;
if (![fetchedResultsController performFetch:&error]) {
NSLog(@"Unresolved Error %@, %@", error, [error userInfo]);
abort();
}
int i = 0;
for (id<NSFetchedResultsSectionInfo> sectionItem in [fetchedResultsController sections]){
NSLog(@"\n***********\nsection %d name %@\n-----------\n",i++, [sectionItem name]);
int j = 0;
for (Job *jobItem in [sectionItem objects]) {
NSLog(@"%d job: %@, client: %@\n",j, jobItem.jobDescription, jobItem.clientOfJob.sortValue);
}
}
return fetchedResultsController;
}
I hope someone can give me some helpful suggestions on what to do about this.
I have been trying several ways to sort a set of entities that have the relationship client<-->>job based on a custom accessor for a property of client as the first sort descriptor, and then the job description property as the second sort descriptor.
I first tried to use a transient property, called Client.sortValue, and discovered that transient properties can't be used as sort descriptors with the NSFetchedResultsController. So I changed the property Client.sortValue to be non-transient.
I never save a value for sortValue to the persistent store. Instead, I use a custom accessor. Apparently, the custom accessor method is not being used when the fetechedResultsController performFetch: method is run. It is called when I do logging, as shown in the code below. I can see that this is the case using a break point in the custom accessor and viewing the stack trace. I don't see it break on the accessor method when the performFetch is run, but it does break on the accessor method when the logging is done.
(Strangely, I had it working earlier today under some circumstances, but not others. It was obviously being sorted the way I wanted it to be, but after I refactored my code to track down the conditions where it worked, I have not seen it work again.)
I have tried various custom accessor methods, including the following:
- (NSString *) primitiveSortValue {
NSString *retVal = nil;
[self willAccessValueForKey:@"lastName"];
[self willAccessValueForKey:@"firstName"];
[self willAccessValueForKey:@"company"];
if (![self.lastName isNullString] ) retVal = [self primitiveValueForKey:@"lastName"];
else if (![self.firstName isNullString] ) retVal = [self primitiveValueForKey:@"firstName"];
else if (![self.company isNullString] ) retVal = [self primitiveValueForKey:@"company"];
else retVal = @"";
[self didAccessValueForKey:@"lastName"];
[self didAccessValueForKey:@"firstName"];
[self didAccessValueForKey:@"company"];
NSLog(@"Sort Value: %@", retVal);
return retVal;
}
I also tried this one before deciding to override the primitive accessor method:
- (NSString *) sortValue {
NSString *retVal = nil;
if (![self.lastName isNullString] ) retVal = self.lastName;
else if (![self.firstName isNullString] ) retVal = self.firstName;
else if (![self.company isNullString] ) retVal = self.company;
else retVal = @"";
NSLog(@"Sort Value: %@", retVal);
return retVal;
}
Here is my fetchedResultsController method:
#define CLIENT_SORT_KEY @"clientOfJob.sortValue"
- (NSFetchedResultsController *) fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription * entity = [NSEntityDescription entityForName:@"Job" inManagedObjectContext:dataInterface.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:10];
if (segmentedControl.selectedSegmentIndex == 0) { // sort by client, then job dscription
NSSortDescriptor *clientSortDescriptor = [[NSSortDescriptor alloc] initWithKey:CLIENT_SORT_KEY ascending:YES];
NSSortDescriptor *jobSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"jobDescription" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:clientSortDescriptor, jobSortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:dataInterface.managedObjectContext
sectionNameKeyPath:CLIENT_SORT_KEY
cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[jobSortDescriptor release];
[clientSortDescriptor release];
[sortDescriptors release];
}
else { // sort by job description
... }
NSError *error = nil;
if (![fetchedResultsController performFetch:&error]) {
NSLog(@"Unresolved Error %@, %@", error, [error userInfo]);
abort();
}
int i = 0;
for (id<NSFetchedResultsSectionInfo> sectionItem in [fetchedResultsController sections]){
NSLog(@"\n***********\nsection %d name %@\n-----------\n",i++, [sectionItem name]);
int j = 0;
for (Job *jobItem in [sectionItem objects]) {
NSLog(@"%d job: %@, client: %@\n",j, jobItem.jobDescription, jobItem.clientOfJob.sortValue);
}
}
return fetchedResultsController;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论