2012-01-06 4 views
28

У меня возникли проблемы (понимание вопрос, если честно) с NSFetchedResultsController и новыми отношениями NSOrderedSet доступны в прошивке 5.NSFetchedResultsController и NSOrderedSet отношение

У меня есть следующие данные-модель (хорошо, мои настоящие один не является выдвижной ящик и носок), но это служит в качестве простого примера:

enter image description here

ящик и носок оба NSManagedObjects в Core Data/модель магазине. На Drawer отношение socks - это , заказанное для-многих отношение к Sock. Идея состоит в том, что носки находятся в ящике в определенном порядке. На Sock отношение drawer является обратным отношению socks.

В UIViewController я рисую UITableView на основе этих объектов. Я питаюсь столом, используя NSFetchedResultsController.

- (NSFetchedResultsController *)fetchedResultsController1 { 
    if (_fetchedResultsController1 != nil) { 
     return _fetchedResultsController1; 
    } 

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Sock" inManagedObjectContext:[NSManagedObjectContext MR_defaultContext]]; 
    [fetchRequest setEntity:entity]; 

    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"drawer.socks" ascending:YES]; 
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]]; 

    self.fetchedResultsController1 = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[NSManagedObjectContext MR_defaultContext] sectionNameKeyPath:nil cacheName:@"SocksCache"]; 
    self.fetchedResultsController1.delegate = self; 

    return _fetchedResultsController1;  
} 

Когда я запускаю это, я получаю следующее errror: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here'

Это имеет смысл для меня, как и отношения является NSOrderedSet и ни один объект для сравнения для сортировки целей.

Я хочу достичь Socks, чтобы появиться в UITableView в порядке, указанном в разделе socks. Я действительно не хочу иметь порядок сортировки, но NSFetchedResultsController, который является отличным компонентом, настаивает на том, что он должен быть одним. Как я могу сказать, что он использует порядок носков на объекте Ящика. Я не хочу, чтобы в таблице отображались объекты Drawer.

Примечание: Я использую это только в приложении iOS5, поэтому доступны упорядоченные отношения.

Любой, кто может предложить мне в любом направлении, был бы очень благодарен. Спасибо за ваше время.

Редактировать: Так табличное представление, что носки этого дисплея делают это только для одного ящика. Я просто хочу, чтобы представление таблицы соблюдало порядок, в котором содержатся отношения с носками. Я не уверен, что установить критерии сортировки, чтобы убедиться, что это происходит.

+0

Дамьен, вы, кажется, решили это. Когда вы говорите «в порядке, указанном в отношениях« носки »- как вы собираетесь определять порядок отношений? В редакторе я могу просто увидеть флажок (упорядоченный или не заказанный), но ничего не контролировать критерии сортировки. – jhabbott

+0

@jhabbott. Когда вы указываете упорядоченное соотношение (используя флажок), тогда связь представляется NSOrderedSet. Затем вы можете использовать обычные упорядоченные методы для управления порядком. – Damien

+0

Итак, теперь я начинаю использовать сгенерированный метод 'insertObject: inSocksAtIndex:', но я получаю исключение исключенного исключения. Я думал, что контекст управляемого объекта добавит это во время выполнения? – jhabbott

ответ

2

Насколько я понимаю эту функциональность, она позволяет заказать Sock s в каждом Drawer. Как Apple, пишет в documentation:

Вы должны использовать их только, если отношение имеет внутреннюю упорядоченность, что имеет решающее значение для его собственного представления, такие как шаги в рецепте.

Это означает, что вы не можете получить все Sock с использованием отсортированного отношения. Сортировка Sock s будет доступна только в каждом объекте Drawer.

+0

Привет, спасибо за ответ. Извините, я не был ясен. Таблица представляет собой ящик, поэтому я хочу, чтобы таблица отображала носки в этом конкретном ящике. Я могу это сделать, но я не знаю, как установить критерии сортировки, чтобы он отображал носки в правильном порядке, в зависимости от упорядоченного отношения родительских сущностей (ящика). Я уточню свой вопрос. Еще раз спасибо. – Damien

5

Damien,

Вы должны просто сделать NSFetchRequest использовать форму массив упорядоченного множества. Он будет работать нормально. Контроллеру нужен атрибут для сортировки.Следовательно, вам также нужно будет указать это.

Andrew

+0

Привет, Андрей. Большое спасибо за то, что нашли время, чтобы ответить на вопрос. Я думаю, что понимаю, что вы говорите, и я знаю, что я могу получить NSArray из упорядоченного набора. Я просто не уверен, как я это передаю в NSFetchRequest. Я, наверное, переусердствовал. Не могли бы вы подтолкнуть меня в правильном направлении? – Damien

+7

Damien, простой предикат - это все, что вам нужно. Например: '@" self in% @ ", orderedSet.array'. Дескриптор сортировки должен быть одинаково простым - выберите атрибут, который не изменит порядок сортировки. Andrew – adonoho

+1

Привет, Андрей, спасибо миллион за помощь. Это сработало. Это был порядок сортировки, который на самом деле не изменился, это было то, о чем я думал. Соболезнования в сущности, которой может быть трудно найти такой атрибут, поэтому я иногда думаю, что у меня может быть атрибут фиктивного типа, который не изменит порядок сортировки. Кажется, что NSFetchedResultsController, возможно, придется немного догнать упорядоченные отношения – Damien

3

Вы можете дать носка атрибут указательный и заказать носки ими:

sock01.index = [sock01.drawer.socks indexOfObject:sock01]; 
+0

+1 см. Также [упорядочение основных данных с помощью UITableView и NSOrderedSet] (http://stackoverflow.com/questions/9875557/core-data-ordering-with-a-uitableview-and-nsorderedset/11188696#11188696) –

+1

Doesn Это означает, что вы выбираете все носки в sock01.drawer, и это именно то, что вы используете NSFetchedResultsController, чтобы этого избежать? –

2

Я нашел эту тему, ища ответ на точный вопрос, заданный ОП.

Я не нашел примеров представления таких данных в tableView без добавления дополнительного поля сортировки. Конечно, добавление поля сортировки в значительной степени устраняет любую выгоду при использовании упорядоченных отношений. Поэтому, учитывая, что я получил эту работу, я подумал, что это может быть полезно другим людям с тем же вопросом, если я разместил здесь свой код. Это оказалось довольно простым (гораздо проще, чем использование дополнительного поля сортировки) и, по-видимому, с хорошей производительностью. То, что некоторые люди, возможно, не осознали (включая меня, изначально), состоит в том, что тип (NSOrderedSet) атрибута отношения «упорядоченный ко многим» имеет способ получения objectAtIndex и что NSMUtableOrderedSet имеет методы для вставки и удаления objectAtIndex ,

Я избегал использования NSFetchedResultsController, поскольку некоторые из предлагаемых плакатов. Я не использовал массив, никакого дополнительного атрибута для сортировки и никакого предиката. Мой код имеет дело с tableView, в котором есть один объект маршрутизации и множество объектов места, где itinerary.places является полем «упорядоченные для многих». Я включил редактирование/переупорядочение, но не удаляет ячейки. Метод moveRowAtIndexPath показывает, как я обновил базу данных с переупорядочением, хотя для хорошей инкапсуляции я, вероятно, должен переместить переупорядочение базы данных в файл категории для объекта, управляемого объектом. Вот весь TableViewController.m:

// 
// ItineraryTVC.m 
// Vacations 
// 
// Created by Peter Polash on 8/31/12. 
// Copyright (c) 2012 Peter Polash. All rights reserved. 
// 

#import "ItineraryTVC.h" 
#import "AppDelegate.h" 
#import "Place+PlaceCat.h" 
#import "PhotosInVacationPlaceTVC.h" 


@interface ItineraryTVC() 

@end 

@implementation ItineraryTVC 

#define DBG_ITIN YES 

@synthesize itinerary ; 

- (id)initWithStyle:(UITableViewStyle)style 
{ 
    self = [super initWithStyle:style]; 
    if (self) { 
     // Custom initialization 
    } 
    return self; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    self.navigationItem.rightBarButtonItem = self.editButtonItem ; 
} 

- (void) viewWillAppear:(BOOL)animated 
{ 

    [super viewWillAppear:animated] ; 

    UIManagedDocument *doc = UIAppDelegate.vacationDoc; 

    [doc.managedObjectContext performBlock:^ 
    { // do this in the context's thread (should be the same as the main thread, but this made it work) 

     // get the single itinerary for this document 

     self.itinerary = [Itinerary setupItinerary: doc ] ; 
     [self.tableView reloadData] ; 
    }]; 

} 

- (void)viewDidUnload 
{ 
    [super viewDidUnload]; 
    // Release any retained subviews of the main view. 
    // e.g. self.myOutlet = nil; 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); 
} 

#pragma mark - Table view data source 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return 1; 
} 

- (NSInteger)tableView:(UITableView *)tableView 
numberOfRowsInSection:(NSInteger)section 
{ 
    return [self.itinerary.places count ]; 
} 


- (UITableViewCell *) tableView: (UITableView *) tableView 
      cellForRowAtIndexPath: (NSIndexPath *) indexPath 
{ 
    static NSString *CellIdentifier = @"Itinerary Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier ]; 


    if (cell == nil) { 
     cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: CellIdentifier]; 
    } 

    Place *place = [self.itinerary.places objectAtIndex:indexPath.row]; 

    cell.textLabel.text  = place.name; 
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%d photos", [place.photos count]]; 

    return cell; 
} 


#pragma mark - Table view delegate 


- (BOOL) tableView: (UITableView *) tableView 
canMoveRowAtIndexPath:(NSIndexPath *) indexPath 
{ 
    return YES; 
} 

-(BOOL)  tableView: (UITableView *) tableView 
canEditRowAtIndexPath: (NSIndexPath *) indexPath 
{ 
    return YES ; 
} 

-(void) tableView: (UITableView *) tableView 
moveRowAtIndexPath: (NSIndexPath *) sourceIndexPath 
     toIndexPath: (NSIndexPath *) destinationIndexPath 
{ 
    UIManagedDocument * doc = UIAppDelegate.vacationDoc ; 

    [doc.managedObjectContext performBlock:^ 
    { // perform in the context's thread 

     // itinerary.places is the "ordered, to-many" relationship attribitute pointing to all places in itinerary 
     NSMutableOrderedSet * places = [ self.itinerary.places mutableCopy ] ; 
     Place *place     = [ places objectAtIndex: sourceIndexPath.row] ; 

     [places removeObjectAtIndex: sourceIndexPath.row ] ; 
     [places insertObject: place atIndex: destinationIndexPath.row ] ; 

     self.itinerary.places = places ; 

     [doc saveToURL: doc.fileURL forSaveOperation: UIDocumentSaveForOverwriting completionHandler: ^(BOOL success) { 
      if (!success) NSLog(@"Error saving file after reorder, startPos=%d, endPos=%d", sourceIndexPath.row, destinationIndexPath.row) ; 
     }]; 
    }]; 

} 

- (UITableViewCellEditingStyle) tableView: (UITableView *) tableView 
      editingStyleForRowAtIndexPath: (NSIndexPath *) indexPath 
{ 
    return (UITableViewCellEditingStyleNone) ; 
} 

- (void) prepareForSegue:(UIStoryboardSegue *) segue sender: (id) sender 
{ 
    NSIndexPath *indexPath = [self.tableView indexPathForCell: sender] ; 
    PhotosInVacationPlaceTVC * photosInVacationPlaceTVC = segue.destinationViewController ; 

    Place *place = [self.itinerary.places objectAtIndex:indexPath.row ]; 

    photosInVacationPlaceTVC.vacationPlace  = place ; 
    photosInVacationPlaceTVC.navigationItem.title = place.name ; 

    UIBarButtonItem *backButton = 
    [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:nil action:nil]; 
    self.navigationItem.backBarButtonItem = backButton; 

} 


@end 
1

Как я только что ответил here, я предпочитаю просто добавить новое свойство к моему NSManagedObject через категорию.

Просто добавьте метод:

- (NSUInteger)indexInDrawerSocks 
{ 
    NSUInteger index = [self.drawer.socks indexOfObject:self]; 
    return index; 
} 

Затем в NSFetchedResultsController, использование сортировки дескриптора:

fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"indexInDrawerSocks" ascending:YES]]; 
+5

Это, похоже, не работает с SQL-настройками. Я попробовал это, и запрос на выборку выдает исключение: '*** Завершение приложения из-за неотображенного исключения 'NSInvalidArgumentException', причина: 'keypath indexInBookChapters, не найденный в сущности '' – acoward

0

Чтобы добавить еще некоторую ясность в ответ от adonoho (спасибо товарищу), который помог мне работу это вместо того, чтобы пытаться указать отношение «многие» как любой ключ сортировки, который я также не мог получить, укажите отношение «принадлежность к предикату» для выбора тех объектов, которые вы хотите в выбранном контроллере результатов, и укажите принадлежит к соотношению как сортировка k еу.

Это удовлетворяет основную цель получения результатов в NSFetchedResultsController со всей этой добротой и уважает порядок во взаимоотношениях со многими.

В этом конкретном примере (выборка носки от ящика):

// socks belong-to a single drawer, sort by drawer specified sock order 
fetchRequest.sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:@"drawer" ascending:YES]]; 

// drawer has-many socks, select the socks in the given drawer 
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"drawer = %@", drawer]; 

По существу, это использует данный ящик, чтобы указать, какие носки должны идти в NSFetchedResultsController и упорядоченность, как указано в отношении к-многим ,

Глядя на сгенерированного SQL (аннотированный из моего примера, используя различные имена сущностей) через ядро ​​SQL данные отладки:

CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, ...fields..., t0.ZDRAWER, t0.Z_FOK_DRAWER FROM ZSOCKS t0 WHERE t0.ZDRAWER = ? ORDER BY t0.Z_FOK_DRAWER 

вы можете увидеть порядок SQL, используя столбец Z_FOK_DRAWER, который использует ядро ​​данных для положение этого носка.

Смежные вопросы