开发者

iPhone by-date sorting core data NSFetchedResultsController

The program I am working on is a modified version of "CoreDataBooks", taken from Apple iPhone sample code. In "CoreDataBooks" there is a list of authors, some of whom have multiple books. A navigation controller is set up, with the sections d开发者_StackOverflowivided up by author name. In each section, there is a list of books for each author.

So I took this code and am trying to make a list of names, arranged by section. My entity is called "Patient". Each entity has attributes myDate and myName, as well as a few others. I want to arrange sections by myDate, with a list of names in each section, all of which have the same date.

I am having difficulty with the NSFetchedResultsController method. When the dates are created using a date picker, they all have a timestamp. This timestamp makes them different, and they will be placed into separate sections if you sort by myDate in the sectionNameKeyPath method.

I did fairly extensive searching online, and came up with the solution below. You create another transient attribute, an NSString, and then use it to sort the sections. This is done by creating a date formatter, which is shown below. I include my setter for my NSString, as well as the NSFetchedResultsController method.

Any help will be greatly appreciated.

- (NSFetchedResultsController *)fetchedResultsController {

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

 PatientsAppDelegate*appDelegate=[[UIApplication sharedApplication]delegate];
 NSManagedObjectContext*managedObjectContext=appDelegate.managedObjectContext;

 // Create and configure a fetch request with the Book entity.
 NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
 NSEntityDescription *entity = [NSEntityDescription entityForName:@"Patient" inManagedObjectContext:managedObjectContext];
 [fetchRequest setEntity:entity];

 // Create the sort descriptors array.
 NSSortDescriptor *dateDescriptor = [[NSSortDescriptor alloc] initWithKey:@"myDate" ascending:YES];
 NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"myName" ascending:YES];
 NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:dateDescriptor, nameDescriptor, nil];
 [fetchRequest setSortDescriptors:sortDescriptors];

// NSLog(@"%@",myFormattedDate);

 // Create and initialize the fetch results controller.
 NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                        managedObjectContext:managedObjectContext 
                          sectionNameKeyPath:@"transactionDay" 
                             cacheName:@"Root"];
 self.fetchedResultsController = aFetchedResultsController;
 fetchedResultsController.delegate = self;

 // Memory management.
 [aFetchedResultsController release];
 [fetchRequest release];
 [dateDescriptor release];
 [nameDescriptor release];
 [sortDescriptors release];

 return fetchedResultsController;
} 

- (NSString *)transactionDay{
 [self willAccessValueForKey:@"transactionDay"];
 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"MM dd,yyyy"];
 NSString*someString=[dateFormatter stringFromDate:[self valueForKey:@"myDate"]];
 [self didAccessValueForKey:@"transactionDay"];
 return someString;
}

The current error I am getting is "the entity Patient is not key value coding-compliant for the key "transactionDay""

Thanks, again.


When specifying the sectionNameKeyPath, you have to include the entity attribute that you want to apply the transient attribute to ( i.e., entityAttribute.transientAttribute). So if you have an entity Patient with an attribute myDate of type NSDate:

// Create and initialize the fetch results controller.
NSFetchedResultsController *aFetchedResultsController = 
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                                    managedObjectContext:managedObjectContext 
                                      sectionNameKeyPath:@"myDate.transactionDay" 
                                               cacheName:@"Root"];

The transient attribute can be defined in your Patient implementation file by adding the following to the top:

@implementation NSDate (TransactionDayFormat)

- (NSString *)transactionDay{
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"MM dd,yyyy"];
    NSString*someString=[dateFormatter stringFromDate:self];
    return someString;
}

@end

@implementation Patient
...

transactionDay will process your myDate attribute further, allowing you to specify sections to stricter formats. Note that NSDateFormatter is quite a bulky object to initialise, so it may be worthwhile to declare it earlier and reference it later for efficiency.


The -transactionDay method should be a property that you implement on your Patient class, and then this class (a view controller, I'm guessing) can choose to sort or section based upon it.


Sounds like your are trying to initialise your fetchedResultsController with a sectionNameKeyPath that hasn't been declared as an attribute in your object model for Patient.

Can you confirm that transactionDay is defined as a NSString attribute in your Patient object model?

Also this sounds like a bit of a round about way to go about what you are trying to achieve. Perhaps you should try to remove the timestamp from your NSDate attribute instead? I did a quick search on SO can found this possible solution to removing NSDate's timestamp

-(NSDate *)dateWithOutTime:(NSDate *)datDate
    if( datDate == nil ) {
        datDate = [NSDate date];
    }
    NSDateComponents* comps = [[NSCalendar currentCalendar] components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:datDate];
    return [[NSCalendar currentCalendar] dateFromComponents:comps];
}

The link to the question is Removing time components from an NSDate object using Objective C/Cocoa

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜