2010-11-01 10 views
6

Sto scrivendo una piccola app per iPhone per la mia azienda che mostra le prenotazioni per ogni dipendente una settimana alla volta. Utilizzo i dati principali per ottenere un elenco di "Prenotazioni" per una determinata settimana e desidero visualizzarli in un UITableView suddiviso in una sezione al giorno della settimana.Aggiunta di ulteriori sezioni a un NSFetchedResultsController

Il problema è che ho bisogno di mostrare 7 sezioni per ogni giorno della settimana (mostrando una cella 'No Bookings' dove una sezione/data non ha prenotazioni).

io ho uno screenshot dell'app così com'è here (purtroppo non pubblicare immagini ancora come io sono nuovo a StackOverlow)

Al momento sto raggiungimento di questo utilizzando un 'fetchResults 'il metodo che ottiene i prenotazioni e li organizza in un array di possibili date:

- (void)refetchResults {  

// Drop bookings Array, replacing with new empty one 
// 7 slots for 7 days each holding mutable array to recieve bookings where appropraite 
self.bookings = [NSArray arrayWithObjects:[NSMutableArray array], 
        [NSMutableArray array], [NSMutableArray array], 
        [NSMutableArray array], [NSMutableArray array], 
        [NSMutableArray array], [NSMutableArray array], nil]; 

// Create the fetch request for the entity. 
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Booking" inManagedObjectContext:self.managedObjectContext]; 
[fetchRequest setEntity:entity]; 

// Limit to this weeks data 
[fetchRequest setPredicate: 
[NSPredicate predicateWithFormat:@"(date >= %@) && (date <= %@) && (resource == %@)", 
    firstDate,lastDate,resourceId]]; 

// Edit the sort key as appropriate. 
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:YES]; 
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"recId" ascending:YES]; 
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, sortDescriptor2, nil]; 
[fetchRequest setSortDescriptors:sortDescriptors]; 

// Fetch records in to array 
NSError *error; 
NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 
if (results == nil) { 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    abort(); 
} 

[fetchRequest release]; 
[sortDescriptor release]; 
[sortDescriptor2 release]; 
[sortDescriptors release]; 

// Walk through records and place in bookings Array as required 
for (Booking *item in results) { 
    // Decide on array index by difference in firstDate and booking date 
    int idx = (int)[[item date] timeIntervalSinceDate:firstDate]/86400; 
    // Add the item to the approp MutArray 
    [(NSMutableArray *)[bookings objectAtIndex:idx] addObject:item]; 
} 

// Reload table 
[tableView reloadData]; 

}

la mia domanda è: esiste un modo per ottenere lo stesso risultato utilizzando NSFetchedResultsController? In qualche modo avrei bisogno di ottenere il NSFetchedResultsController per avere 7 sezioni, una per ogni giorno della settimana, alcune delle quali potrebbero non avere prenotazioni.

Qualsiasi aiuto molto apprezzato :)

risposta

2

non ho usato questo molto, ma si potrebbe verificare il protocollo NSFetchedResultsSectionInfo. Può essere usato in questo modo, a quanto pare:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
NSInteger numberOfRows = 0; 
if ([[fetchedResultsController sections] count] > 0) 
    { 
    id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section]; 
    numberOfRows = [sectionInfo numberOfObjects]; 
    } 
return numberOfRows; 
} 

Buona fortuna.

+0

Grazie per la risposta. A meno che manchi qualcosa, dovrei comunque fare un esercizio di mappatura per trovare la sezione appropriata, ovvero: tableView richiede la sezione da 0 a 6 (che rappresenta, ad esempio, dal 1 novembre al 7 novembre), ma il NSFetchedResultsController potrebbe avere solo sezioni 0, 1 e 2 (che rappresentano, forse, le prenotazioni per il 2 novembre, 3 novembre e 6 novembre). Potrei fare questo mapping ogni volta che ho bisogno di fare riferimento alle Bookings o potrei memorizzare la mappatura quando costruisco il NSFetchedResultsController ma spero che ci sia un modo più bello/più ordinato per farlo. – Paul80nd

+0

Hai ragione. Mi dispiace non essere di maggiore aiuto. Lo sperimenterò più tardi, me stesso, come il tempo consente. Curioso di sapere se/come lo risolvi. – westsider

+0

In realtà, riflettendo un po 'su questo penso che una soluzione utilizzabile al momento è quella di creare un NSFetchedResultsController come al solito, ma alla fine di questo impostare i campi di una matrice' mapping 'per tradurre le sezioni di tableview nelle sezioni di NSFetchedResultsController. Questo dovrebbe significare che posso ottenere le notifiche dell'oggetto dal resultsController (che è bello;) - Devo solo aggiornare l'array 'mapping' quando le notifiche arrivano per gli elementi aggiunti/rimossi dal resultsController. In ogni caso, se trovo una soluzione migliore, la scriverò qui. – Paul80nd

7

Quindi, visto che il tempo non è molto bello, ho provato a rispondere alla mia domanda e ad implementare la "soluzione" descritta nella mia risposta a Westsider.

L'idea è di mantenere una matrice di 'mapping' (solo un semplice array di 7 slot int che mapperà la sezione che tableview richiederà alla sottostante sezione fetchedresultscontroller. Ogni slot dell'array avrà l'indice di sezione appropriato o '-1' dove non ci sono sezioni sottostanti (e dove invece dovrebbe essere mostrata una cella 'Nessuna prenotazione').

Quindi, il mio metodo refetchResults diventa:

- (void)refetchResults {  

    // Create the fetch request for the entity. 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Booking" inManagedObjectContext:self.managedObjectContext]; 
    [fetchRequest setEntity:entity]; 

    // Limit to this weeks data 
    [fetchRequest setPredicate: 
    [NSPredicate predicateWithFormat:@"(date >= %@) && (date <= %@) && (resource == %@)", 
     firstDate,lastDate,resourceId]]; 

    // Edit the sort key as appropriate. 
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:YES]; 
    NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"recId" ascending:YES]; 
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, sortDescriptor2, nil]; 
    [fetchRequest setSortDescriptors:sortDescriptors]; 

    // Set up FRC 
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"date" cacheName:nil]; 
    self.fetchedResultsController = aFetchedResultsController; 
    self.fetchedResultsController.delegate = self; 
    [aFetchedResultsController release]; 
    [fetchRequest release]; 
    [sortDescriptor release]; 
    [sortDescriptor2 release]; 
    [sortDescriptors release]; 

    // Run up FRC 
    NSError *error = nil; 
    if (![fetchedResultsController_ performFetch:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 

    // Update FRC map 
    [self updateFRCMap]; 

    // Reload table 
    [tableView reloadData]; 
} 

La mappatura si trova nel metodo seguente. Questo viene chiamato ogni volta che è necessario aggiornare la mappatura, ad esempio quando ricevo le richiamate dal comando fetchedresults per gli elementi che sono stati aggiunti/eliminati/ecc.

- (void)updateFRCMap { 

    // Set mapping table for seven days of week to appropriate section in frc 
    for (int idx=0;idx<7;idx++) { frcMap[idx] = -1; } // Reset mappings 
    // For each section 
    for (int sidx=0; sidx<[[self.fetchedResultsController sections] count]; sidx++) 
    { 
     // If section has items 
     if ([[[self.fetchedResultsController sections] objectAtIndex:sidx] numberOfObjects] > 0) 
     { 
      // Look at first booking of section to get date 
      NSDate *date = [(Booking *)[self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:sidx]] date]; 
      // Decide on array index by difference in firstDate and booking date 
      int idx = (int)[date timeIntervalSinceDate:firstDate]/86400; 
      // Set map 
      frcMap[idx] = sidx; 
     } 
    } 
} 

Questo può probabilmente essere ottimizzato un po 'ma funziona OK per ora. Sospetto che potrebbe soffrire di problemi di modifica dell'orologio GMT/BST che dovranno essere risolti ... non che i problemi di cambio dell'orologio siano così urgenti, eh Apple? ; P

Dopo di che è solo un caso di utilizzo della matrice di mappatura quando risponde alla Tableview:

#pragma mark - 
#pragma mark Table view data source 

// Gets the booking from the fetchedResultsController using a remapped indexPath 
- (Booking *)bookingForMappedIndexPath:(NSIndexPath *)indexPath { 
    return (Booking *)[self.fetchedResultsController objectAtIndexPath: 
         [NSIndexPath indexPathForRow:indexPath.row inSection:frcMap[indexPath.section]]]; 
} 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return 7; // 7 days viewed 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 

    // Rows in section or 1 if no section 
    if (frcMap[section] != -1) { 
     id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:frcMap[section]]; 
     return [sectionInfo numberOfObjects]; 
    } else { 
     return 1; 
    } 

} 

- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

    static NSString *CellIdentifier = @"RegularCell"; 

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; 
    } 

    // Configure the cell. 
    [self configureCell:cell atIndexPath:indexPath]; 
    return cell; 
} 

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { 

    // If no actual bookings for section then its a blank cell 
    if (frcMap[indexPath.section] == -1) { 

     // Configure a blank cell. 
     cell.textLabel.text = @"No Bookings"; 
     cell.detailTextLabel.text = @""; 

     cell.textLabel.font = [UIFont systemFontOfSize:16]; 
     cell.textLabel.textColor = [UIColor lightGrayColor]; 

     cell.accessoryType = UITableViewCellAccessoryNone; 
     cell.selectionStyle = UITableViewCellSelectionStyleNone; 

    } else { 

     // Regular cell 
     Booking *booking = [self bookingForMappedIndexPath:indexPath]; 
     cell.textLabel.text = booking.desc; 
     cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ %@", booking.location, booking.detail]; 

     cell.textLabel.font = [UIFont systemFontOfSize:14]; 
     cell.textLabel.textColor = [UIColor darkTextColor]; 
     cell.detailTextLabel.font = [UIFont systemFontOfSize:12]; 

     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 
     cell.selectionStyle = UITableViewCellSelectionStyleBlue; 
    } 
} 

Qualsiasi commento o modi migliori di scrivere questo sono molto benvenuti :)

+0

Grazie per questo. Ho lo stesso identico problema in un'app a cui sto lavorando, cercando di visualizzare "Ieri, oggi, domani" - gli eventi con una cella "Nulla oggi" nelle sezioni vuote. In realtà sono andato con la stessa soluzione prima di vederlo. È male che FetchedResultsController non abbia alcun supporto per questo ... – Accatyyc

1

ho avuto anche questo problema.Ho scritto una sottoclasse di NSFetchedResultsController per risolvere il problema:

https://github.com/timothyarmes/TAFetchedResultsController

Tim

+0

Apprezzo il duro lavoro di Tim, ma un'impressione onesta della tua soluzione è che non è facilmente scartata in un progetto esistente. Creare una nuova entità per supportare questo e gestire la logica di cancellazione è molto più di quanto mi aspetti di "aggirare questo piccolo problema" –

Problemi correlati