2009-10-22 3 views
4

J'ai chargé l'élément à partir des données de base dans un NSMutableArray. Chaque élément, lorsqu'il est créé, reçoit une date d'échéance que l'utilisateur choisit.Trier NSArray par NSDate, aujourd'hui

Comment trier, de sorte que seul l'élément dû aujourd'hui est affiché?

Voici ce que je suis arrivé à ce jour:

NSPredicate *predicate = [NSPredicate predicateWithFormat: @"dueDate == %@", [NSDate date]]; 

[allObjectsArray filterUsingPredicate: predicate]; 

Ce code ne fonctionne cependant pas.

Merci pour toutes suggestions

Répondre

0

La méthode -filterUsingPredicate: ne fonctionne que sur les tableaux mutables (de type NSMutableArray).

Essayez d'utiliser la méthode -filteredArrayUsingPredicate:, à la place:

NSString *formattedPredicateString = [NSString stringWithFormat:@"dueDate == '%@'", [NSDate date]]; 
NSPredicate *predicate = [NSPredicate predicateWithFormat:formattedPredicateString]; 
NSArray *filteredArray = [allObjectsArray filteredArrayUsingPredicate:predicate]; 
1

Le problème avec l'utilisation prédicats est que si elles utilisent la comparaison de date standard, cela ne fera que revenir les dates qui sont exactement la date et moment de la date donnée. Si vous voulez les dates « aujourd'hui », vous aurez besoin d'ajouter une méthode de -isToday quelque part (possible une extension NSDate), comme ceci:

-(BOOL)dateIsToday:(NSDate *)aDate { 

    NSDate *now = [NSDate date]; 

    NSCalendar *cal = [NSCalendar currentCalendar]; 
    NSDateComponents *nowComponents = [cal components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit 
             fromDate:now]; 

    NSDateComponents *dateComponents = [cal components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit 
              fromDate:aDate]; 

    return (([nowComponents day] == [dateComponents day]) && 
     ([nowComponents month] == [dateComponents month]) && 
     ([nowComponents year] == [dateComponents year])); 

} 

Une fois que vous avez cela, il est assez simple de trouver les qui sont aujourd'hui:

NSMutableArray *itemsDueToday = [NSMutableArray array]; 

for (MyItem *item in items) { 
    if ([self dateIsToday:[item date]) { 
     [itemsDueToday addObject:item]; 
    } 
} 

// Done! 
+0

Cette approche fonctionnerait, mais elle nécessite beaucoup de traitement de date et de calcul par article. Donc, s'il y avait quelques centaines d'articles (ou plus), le temps de traitement commencerait à s'accumuler. –

+0

Et en plus de cela il y a un coût supplémentaire à connaître: http://www.mikeabdullah.net/NSCalendar_currentCalendar.html –

12

que diriez-vous de calculer seulement aujourd'hui à 00:00, puis demain à 00h00, puis de comparer les dates dans le prédicat à ceux (> = et <). Donc, tous les objets de date doivent être dans ces deux dates pour être classés comme étant «Aujourd'hui». Cela vous oblige à calculer uniquement deux dates au départ, quel que soit le nombre d'objets de date dans votre tableau.

// Setup 
NSCalendar *cal = [NSCalendar currentCalendar]; 
NSDate *now = [NSDate date]; 

// Get todays year month and day, ignoring the time 
NSDateComponents *comp = [cal components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:now]; 

// Components to add 1 day 
NSDateComponents *oneDay = [[NSDateComponents alloc] init]; 
oneDay.day = 1; 

// From date & To date 
NSDate *fromDate = [cal dateFromComponents:comp]; // Today at midnight 
NSDate *toDate = [cal dateByAddingComponents:oneDay toDate:fromDate options:0]; // Tomorrow at midnight 

// Cleanup 
[oneDay release] 

// Filter Mutable Array to Today 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"dueDate >= %@ && dueDate < %@", fromDate, toDate]; 
NSArray *filteredArray = [allObjectsArray filteredArrayUsingPredicate:predicate]; 

// Job Done! 
+5

+1 c'est probablement votre meilleure option. Une alternative à '> = && <' est d'utiliser le mot-clé 'BETWEEN':' NSPredicate * predicate = [NSPredicate predicateWithFormat: @ "dueDate ENTRE% @", [NSArray arrayWithObjects: fromDate, toDate, nil]]; ' que vous n'avez pas besoin de construire un objet 'predicateString' lorsque vous utilisez' predicateWithFormat: ') –

+0

Merci pour le +1! Oui, j'ai pensé à utiliser le mot-clé 'BETWEEN', cependant comme le toDate est le jour suivant à minuit, alors je voulais que le prédicat soit inférieur à, mais pas égal à cette date. Si je me souviens bien, le 'BETWEEN' comprend les limites supérieure et inférieure. Vous avez également raison sur le 'predicateWithFormat:'! –