I'm working with Core Data for the first time, with the Stanford iOS app development course as a guide. I pretty much copied the code from the demo app (of course I adjusted it to my needs), but I'm having two problems currently.
My app is a map view which on the tap of a button presents a modal view controller. This modal view checks whether a UIManagedDocument
was created. If not, it creates one and inserts the data. This data is coming from a property list (258 items, so nothing too excessive). If it was created already (by previously displaying that view), if my logic holds, it should be safe to assume it also has content because the NSManagedObject
s are created at the same time a document is created. The first run works perfectly fine, the table loads and all my data is correctly displayed.
However, when I dismiss and then re-display my modal view, the table stays empty. I'm checking the document's state, which is UIDocumentStateNormal
, so querying it should be fine. But it isn't: my fetchedResultsController returns 0 rows. If I understand UIManagedContext
correctly, the behavior I'm experiencing could be caused by a wrong/different context, but I make sure that: 1) I pass my document (not just the context) to the modal view in prepareForSegue:sender
, and 2) I pass my document with the context back to the presenting view when the modal view is being dismissed. That's why I think it's probably not the context, but something else.
One other thing: inserting the 258 records when the app is first launched is fast enough in the simulator. However, on my phone it could take a whole 13 seconds. The insertion code is shown below (modified for readability):
+ (Department *)departmentName:(NSString *)name
withAttributes:(NSDictionary *)attributes
inContext:(NSManagedObjectContext *)context {
Department *department = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:context];
department.name = name;
NSArray *informationElements = [attributes objectForKey:@"information"];
for (int i = 0; i < [informationElements count]; i++) {
NSString *informationValue = [[informationElements objectAtIndex:i] objectForKey:@"value"];
if ([[[informationElements objectAtIndex:i] objectForKey:@"description"] isEqualToString:@"phone"]) {
department.phone = informationValue;
} else if ([[[informationElements objectAtIndex:i] objectForKey:@"description"] isEqualToString:@"email"]) {
department.email = informationValue;
} else if ([[[informationElements objectAtIndex:i] objectForKey:@"description"] isEqualToString:@"web"]) {
department.website = informationValue;
}
}
return department;
}
To be clear: this code works just fine, but it's really slow. It's encapsulated in a method which is called exactly 258 times. informationElements
has at most three elements, which means there are 258 * 3 = 774 loops maximum. In reality it's much less than that, but even if it were 774, that shouldn't take 13 seconds, right?
The snippet below shows the initialization of UIManagedDocument
:
if (![[NSFileManager defaultManager] fileExistsAtPath:[self.database.fileURL path]]) {
[self.database saveToURL:self.database.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
[self setupFetchedResultsController];
[self fetchDepartmentsIntoDocument:self.database];
}];
} else if (self.database.documentState == UIDocumentStateClosed) {
[self.database openWithCompletionHandler:^(BOOL success) {
[self setupFetchedResultsController];
}];
} else if (self.database.documentState == UIDocumentStateNormal) {
[self setupFetchedResultsController];
}
fetchDepartmentsIntoDocument
reads the property list and then runs a loop which calls departmentName:withAttributes:inContext
for every property list item.
If anyone could provide me with some help, it will be much appreciated!