nsfetchedresultscontroller中节名称键路径的Nil关系值

时间:2013-08-23 08:09:29

标签: iphone ios objective-c cocoa core-data

对于EntityA与EntityB具有多对一关系的核心数据模型,我想创建一个EntityA对象列表,按照与它们相关的EntityB的名称进行排序。通常要这样做,我会设置这样的获取请求:

if (_fetchedResultsController != nil) {
    return _fetchedResultsController;
}

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

然后我会设置我的请求值:(在这种情况下,它是按物种名称排序的植物列表。某些植物没有物种设置。)

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Plant" inManagedObjectContext:self.managedObjectContext];
NSSortDescriptor *sortDescriptorOne = [[NSSortDescriptor alloc] initWithKey:@"species.name" ascending:YES];
NSString *sectionKeyPath = @"species.name";

然后我用通常的东西完成它:

[fetchRequest setEntity:entity];

// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];

NSArray *sortDescriptors = @[sortDescriptorOne];
[fetchRequest setSortDescriptors:sortDescriptors];

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:sectionKeyPath
cacheName:@"plantsCache"];

aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;

[NSFetchedResultsController deleteCacheWithName:@"plantsCache"];
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

return _fetchedResultsController;

但我得到的结果对我不起作用,因为这种关系是可选的。因此,某些EntityA与EntityB有关系,有些则没有。当EntityA的关系值为零时,结果控制器似乎不知道该怎么做。

我可以做些什么建议继续使用关系的值创建部分,但允许某些对象为nil?

2 个答案:

答案 0 :(得分:3)

Plant中设置瞬态属性,如下所示:

-(NSString*)speciesName {
    return self.species ? self.species.name : @"";
}

您现在可以使用speciesName作为sectionNameKeyPath

答案 1 :(得分:0)

使用Swift 3.0进入此阶段。有两个实体EntityA和EntityB,其中EntityA通常属于(有一个指针)某个EntityB,但也可能是无主的。

Swift修复是为EntityA添加一个扩展,如果检测到nil条件,则返回一个空字符串。

extension Note {
    var bookTitleOrNil : String {
        if let bookTitle = self.book?.title {
            return bookTitle
        }
        return ""
    }
}

然后在构建fetchRequestController(FRC)时替换以下内容:

let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.coreDataManager.managedObjectContext, sectionNameKeyPath: "book.title", cacheName: nil)

使用sectionNameKeyPath的新扩展名:

let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.coreDataManager.managedObjectContext, sectionNameKeyPath: "bookTitleOrNil", cacheName: nil)

然后,在为不同部分生成标题时,我使用了以下内容:

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    let useIndexPath = IndexPath(row: 0, section: section) // Get first item in section (all notes in a section point to same book)
    let note = frc.object(at: useIndexPath)
    if let bookTitle = note.book?.title {
        return bookTitle
    } else {
        return "Unlinked"
    }
}

所以这些笔记首先按照它们所属的书排序,如章节标题所示(尽管不属于任何书籍的笔记首先在“未链接”标题下排序)。

此外,在FRC的fetchRequest中设置排序时,需要设置主排序描述符以使用book.title,然后使用任何其他排序,例如注释的标题。

let sortDescriptor1 = NSSortDescriptor(key: "book.title", ascending: true)
let sortDescriptor2 = NSSortDescriptor(key: "title", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor1, sortDescriptor2]

当然,人们还可以设计应用程序,以便在创建笔记时通过额外检查将笔记始终属于书籍,并以此方式避免使用零件。