Core data executeFetchRequest fail with exc_bad_access - ios

From my understanding, this is a memory issue, especially since I call the method from several places several times with different timers.
Code below that throw the exception:
- (NSMutableArray*)getAllTraps
{
#synchronized(self)
{
self.fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Trap"];
NSError *error = nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:self.fetchRequest error:&error];
if (!results)
{
NSLog(#"Error fetching traps: %#", error.localizedDescription);
NSLog(#"Reason: %#", error.localizedFailureReason);
NSLog(#"Suggestion: %#", error.localizedRecoverySuggestion);
abort();
}
if (error != nil)
{
// Handle error
NSLog(#"Error getting all traps");
}
else
{
// Handle success
NSLog(#"Success getting all traps");
}
NSMutableArray *arrayOfAllTraps = [[NSMutableArray alloc] init];
for (int i = 0; i < results.count; i++)
{
Trap *singleTrap = results[i];
NSMutableDictionary *singleDict = [[NSMutableDictionary alloc] init];
if (singleTrap.trapID.integerValue > 0)
{
singleDict[ID] = singleTrap.trapID;
singleDict[ALARMDISTANCE] = singleTrap.alarmDistance;
singleDict[ISACTIVE] = singleTrap.isActive;
singleDict[LAT] = singleTrap.lat;
singleDict[LON] = singleTrap.lon;
singleDict[POLYGONS] = singleTrap.polys;
// NSLog(#"Trap ID: %#, Trap Description: %#", singleTrap.trapID, singleTrap.trapDescription);
singleDict[DESCRIPTION] = singleTrap.trapDescription;
singleDict[ROADNUMBER] = singleTrap.roadNumber;
singleDict[TYPE] = singleTrap.type;
singleDict[DEGREES] = singleTrap.degrees;
singleDict[DIRECTION] = singleTrap.direction;
if (singleTrap.poly0 == nil)
{
singleDict[POLYGON_A] = #"";
}
else
{
singleDict[POLYGON_A] = singleTrap.poly0;
}
// Make sure not to set NULL value #1
if (singleTrap.poly1 == nil)
{
singleDict[POLYGON_B] = #"";
}
else
{
singleDict[POLYGON_B] = singleTrap.poly1;
}
if (singleTrap.poly2 == nil)
{
singleDict[POLYGON_C] = #"";
}
else
{
singleDict[POLYGON_C] = singleTrap.poly2;
}
// Make sure not to set NULL value #2
if (singleTrap.polygonAzimut1 == nil)
{
singleDict[POLYGON_A_AZIMUTH] = #"";
}
else
{
singleDict[POLYGON_A_AZIMUTH] = singleTrap.polygonAzimut1;
}
if (singleTrap.polygonAzimut2 == nil)
{
singleDict[POLYGON_B_AZIMUTH] = #"";
}
else
{
singleDict[POLYGON_B_AZIMUTH] = singleTrap.polygonAzimut2;
}
if (singleTrap.polygonAzimut3 == nil)
{
singleDict[POLYGON_C_AZIMUTH] = #"";
}
else
{
singleDict[POLYGON_C_AZIMUTH] = singleTrap.polygonAzimut3;
}
[arrayOfAllTraps addObject:singleDict];
}
}
return arrayOfAllTraps;
}
}
The fail come right after:
NSArray *results = [self.managedObjectContext executeFetchRequest:self.fetchRequest error:&error];
And not even go inside 'if'.

Try this,
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDescription = [NSEntityDescription
entityForName:#"Trap" inManagedObjectContext:self.managedObjectContext];
[fetch setEntity:entityDescription];
NSError * error = nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:fetch error:&error];

Related

I'm not able to resume download task in NSURLSession

I have create a demo for downloading a file from the server it is working fine with foreground and background, but when I'm going to resume it, It will giving below Error
I have stcuk here could help me so solved it, I search in internet but I couldn't find anything helpful.
Download file and Pause Downlaod is working fine I have issue to resume it.
Task <3AE5BF24-3A4E-4713-8FC2-A0032022C913>.<6> finished with error [-3003] Error Domain=NSURLErrorDomain Code=-3003 "(null)" UserInfo={_NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundDownloadTask <3AE5BF24-3A4E-4713-8FC2-A0032022C913>.<6>"
), _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundDownloadTask <3AE5BF24-3A4E-4713-8FC2-A0032022C913>.<6>}
Here is the final Xcode project
Downlaod xcode project
#import "NSURLSession+ResumeData.h"
#import <UIKit/UIKit.h>
#define IS_IOS10ORLATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10)
#pragma mark- private
static NSData * correctRequestData(NSData *data) {
if (!data) {
return nil;
}
// return the same data if it's correct
if ([NSKeyedUnarchiver unarchiveObjectWithData:data] != nil) {
return data;
}
NSMutableDictionary *archive = [[NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainersAndLeaves format:nil error:nil] mutableCopy];
if (!archive) {
return nil;
}
NSInteger k = 0;
id objectss = archive[#"$objects"];
while ([objectss[1] objectForKey:[NSString stringWithFormat:#"$%ld",k]] != nil) {
k += 1;
}
NSInteger i = 0;
while ([archive[#"$objects"][1] objectForKey:[NSString stringWithFormat:#"__nsurlrequest_proto_prop_obj_%ld",i]] != nil) {
NSMutableArray *arr = archive[#"$objects"];
NSMutableDictionary *dic = arr[1];
id obj = [dic objectForKey:[NSString stringWithFormat:#"__nsurlrequest_proto_prop_obj_%ld",i]];
if (obj) {
[dic setValue:obj forKey:[NSString stringWithFormat:#"$%ld",i+k]];
[dic removeObjectForKey:[NSString stringWithFormat:#"__nsurlrequest_proto_prop_obj_%ld",i]];
[arr replaceObjectAtIndex:1 withObject:dic];
archive[#"$objects"] = arr;
}
i++;
}
if ([archive[#"$objects"][1] objectForKey:#"__nsurlrequest_proto_props"] != nil) {
NSMutableArray *arr = archive[#"$objects"];
NSMutableDictionary *dic = arr[1];
id obj = [dic objectForKey:#"__nsurlrequest_proto_props"];
if (obj) {
[dic setValue:obj forKey:[NSString stringWithFormat:#"$%ld",i+k]];
[dic removeObjectForKey:#"__nsurlrequest_proto_props"];
[arr replaceObjectAtIndex:1 withObject:dic];
archive[#"$objects"] = arr;
}
}
// Rectify weird "NSKeyedArchiveRootObjectKey" top key to NSKeyedArchiveRootObjectKey = "root"
if ([archive[#"$top"] objectForKey:#"NSKeyedArchiveRootObjectKey"] != nil) {
[archive[#"$top"] setObject:archive[#"$top"][#"NSKeyedArchiveRootObjectKey"] forKey: NSKeyedArchiveRootObjectKey];
[archive[#"$top"] removeObjectForKey:#"NSKeyedArchiveRootObjectKey"];
}
// Reencode archived object
NSData *result = [NSPropertyListSerialization dataWithPropertyList:archive format:NSPropertyListBinaryFormat_v1_0 options:0 error:nil];
return result;
}
static NSMutableDictionary *getResumeDictionary(NSData *data) {
NSMutableDictionary *iresumeDictionary = nil;
if (IS_IOS10ORLATER) {
id root = nil;
id keyedUnarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
#try {
root = [keyedUnarchiver decodeTopLevelObjectForKey:#"NSKeyedArchiveRootObjectKey" error:nil];
if (root == nil) {
root = [keyedUnarchiver decodeTopLevelObjectForKey:NSKeyedArchiveRootObjectKey error:nil];
}
} #catch(NSException *exception) {
}
[keyedUnarchiver finishDecoding];
iresumeDictionary = [root mutableCopy];
}
if (iresumeDictionary == nil) {
iresumeDictionary = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainersAndLeaves format:nil error:nil];
}
return iresumeDictionary;
}
static NSData *correctResumeData(NSData *data) {
NSString *kResumeCurrentRequest = #"NSURLSessionResumeCurrentRequest";
NSString *kResumeOriginalRequest = #"NSURLSessionResumeOriginalRequest";
if (data == nil) {
return nil;
}
NSMutableDictionary *resumeDictionary = getResumeDictionary(data);
if (resumeDictionary == nil) {
return nil;
}
resumeDictionary[kResumeCurrentRequest] = correctRequestData(resumeDictionary[kResumeCurrentRequest]);
resumeDictionary[kResumeOriginalRequest] = correctRequestData(resumeDictionary[kResumeOriginalRequest]);
NSData *result = [NSPropertyListSerialization dataWithPropertyList:resumeDictionary format:NSPropertyListXMLFormat_v1_0 options:0 error:nil];
return result;
}
#implementation NSURLSession (ResumeData)
- (NSURLSessionDownloadTask *)downloadTaskWithCorrectResumeData:(NSData *)resumeData {
NSString *kResumeCurrentRequest = #"NSURLSessionResumeCurrentRequest";
NSString *kResumeOriginalRequest = #"NSURLSessionResumeOriginalRequest";
NSData *cData = correctResumeData(resumeData);
cData = cData ? cData:resumeData;
NSURLSessionDownloadTask *task = [self downloadTaskWithResumeData:cData];
NSMutableDictionary *resumeDic = getResumeDictionary(cData);
if (resumeDic) {
if (task.originalRequest == nil) {
NSData *originalReqData = resumeDic[kResumeOriginalRequest];
NSURLRequest *originalRequest = [NSKeyedUnarchiver unarchiveObjectWithData:originalReqData ];
if (originalRequest) {
[task setValue:originalRequest forKey:#"originalRequest"];
}
}
if (task.currentRequest == nil) {
NSData *currentReqData = resumeDic[kResumeCurrentRequest];
NSURLRequest *currentRequest = [NSKeyedUnarchiver unarchiveObjectWithData:currentReqData];
if (currentRequest) {
[task setValue:currentRequest forKey:#"currentRequest"];
}
}
}
return task;
}
#end

Only Able to Save The First Object

A problem I'm facing right now is that when I try to save objects, Core Data appears to only save the first one.
Code to save objects
- (void)savingResCore {
AppDelegate *delegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [delegate managedObjectContext];
ResultMO *resEntity = [NSEntityDescription insertNewObjectForEntityForName:#"Result" inManagedObjectContext:context];
if(indCheck == 1) {
resEntity.result1 = pena1;
resEntity.resuName1 = penaNam1;
}
if(indCheck == 2) {
resEntity.result2 = pena2;
resEntity.resuName2 = penaNam2;
}
if(indCheck == 3) {
resEntity.result3 = pena3;
resEntity.resuName3 = penaNam3;
}
_seqNameChk = [NSNumber numberWithInt:[_seqNameChk intValue] - 1];
if([_seqNameChk isEqual:#(0)]){
NSError *error = nil;
if (context != nil) {
if ([context hasChanges] && ![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
}
Code to fetch objects
- (void)fetchResCore {
AppDelegate *delegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [delegate managedObjectContext];
NSEntityDescription *descriptor = [NSEntityDescription entityForName:#"Result" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
request.entity = descriptor;
NSError *error;
NSArray *contArr = [context executeFetchRequest:request error:&error];
if(contArr == nil){
NSLog(#"Problems fetching data.");
}
else if(contArr != nil) {
if(contArr.count == 0) {
NSLog(#"No objects saved");
}
else {
NSManagedObject *resu = (NSManagedObject *)[contArr objectAtIndex:0];
NSLog(#"1 - %#", resu);
pena1 = [resu valueForKey:#"result1"];
penaNam1 = [resu valueForKey:#"resuName1"];
NSLog(#"%#", pena1);
pena2 = [resu valueForKey:#"result2"];
penaNam2 = [resu valueForKey:#"resuName2"];
NSLog(#"%#", pena2);
pena3 = [resu valueForKey:#"result3"];
penaNam3 = [resu valueForKey:#"resuName3"];
NSLog(#"%#", pena3);
NSLog(#"2 - %#", resu);
}
}
}
For example, I have a button that increments indCheck by one each time it is pressed and each time it calls up the fetchResCore method. Assume seqNameChk = 2. For the first time, the attributes result1 & resuName1 gets saved successfully. After the button is pressed consecutively, it no longer saves data. Hence, attributes result2, resuName2, result3 & resuName3 does not contain data when retrieved at the fetchResCore method.
Result printed in the console for resu
resuName1 = "(\n Alan\n)";
resuName2 = nil;
resuName3 = nil;
result1 = "(\n 100\n)";
result2 = nil;
result3 = nil;
Result printed in the console for contArr
result1 = \"(\\n 100\\n)\";\n result2 = nil;\n result3 = nil;\n
resuName1 = \"(\\n Alan\\n)\";\n resuName2 = nil;\n resuName3 = nil;\n
As Jon Rose had pointed out,
I would assume that they are all in the array contArr but you are only looking at the first one: NSManagedObject *resu = (NSManagedObject *)[contArr objectAtIndex:0];
I printed out contArr.count and it resulted in a 3. I've also printed out the contents of the array by using a for loop and again, 3 elements which were populated, was displayed.
To solve the problem, I had to rectify [contArr objectAtIndex:0] as it only displayed the first element in the array.
In the fetchResCore method
for(int i = 0; i < contArr.count; i++){
NSManagedObject *resu = (NSManagedObject *)[contArr objectAtIndex:i];
NSLog(#"1 - %#", resu);
if(pena1.count == 0 && penaNam1.count == 0){
pena1 = [resu valueForKey:#"result1"];
penaNam1 = [resu valueForKey:#"resuName1"];
NSLog(#"%#", pena1);
}
if(pena2.count == 0 && penaNam2.count == 0){
pena2 = [resu valueForKey:#"result2"];
penaNam2 = [resu valueForKey:#"resuName2"];
NSLog(#"%#", pena2);
}
if(pena3.count == 0 && penaNam3.count == 0){
pena3 = [resu valueForKey:#"result3"];
penaNam3 = [resu valueForKey:#"resuName3"];
NSLog(#"%#", pena3);
}
}
Thanks again, Jon Rose for pointing out a simple mistake that took me days to figure out.

CoreData objects not saved between screens

I have a screen that holds a UITableView, in this screen I have an array of NSManagedObjects. It's working just fine, but as I try move to another screen (click on a specific cell, and push a new screen), then return to the same UITableView screen, all the objects got lost.
What does it means? I try to print the array of the NSManagedObjects and it's fine, all the objects there, but as I print the description of each object, I get nil from all the object attributes.
Someone knows whats the cause of it? I don't know why but it worked just fine 12 hours ago, but now it's all messed up and I don't have a clue what have I done.
Thanks in advance!
Save method:
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
else {
NSLog(#"Context saved!");
}
}
}
This is how I save the objects:
NSDictionary *response = responseObject;
if ([[response valueForKey:#"status"] rangeOfString:#"ok"].location != NSNotFound)
{
NSArray *data = [response objectForKey:#"data"];
if (data.count != 0)
{
if (page.integerValue == 0) {
[[DownloadData sharedData] deleteAllObjectsFromEntityName:#"DbHomeCuisine"];
[[DownloadData sharedData] deleteAllObjectsFromEntityName:#"DbHomeCategory"];
[[DownloadData sharedData] deleteAllObjectsFromEntityName:#"DbHomeDish"];
}
NSMutableArray *homePageObjects = [[NSMutableArray alloc] initWithCapacity:data.count];
for (NSDictionary *object in data)
{
NSNumber *type = [object objectForKey:#"type"];
switch (type.integerValue) {
case 1:
{
NSDictionary *content = [object objectForKey:#"content"];
NSManagedObjectContext *context = [[MainDb sharedDb] managedObjectContext];
DbHomeCuisine *homeCuisine = [NSEntityDescription insertNewObjectForEntityForName:#"DbHomeCuisine" inManagedObjectContext:context];
NSInteger cuisineId = [[content valueForKey:#"cuisine_id"] integerValue];
homeCuisine.cuisine = [self gCuisineWithCuisineId:[NSNumber numberWithInteger:cuisineId]];
NSInteger count = [[content valueForKey:#"count"] integerValue];
homeCuisine.count = [NSNumber numberWithInteger:count];
homeCuisine.type = type;
[homePageObjects addObject:homeCuisine];
}
break;
case 2:
{
NSDictionary *content = [object objectForKey:#"content"];
NSManagedObjectContext *context = [[MainDb sharedDb] managedObjectContext];
DbHomeCategory *homeCategory = [NSEntityDescription insertNewObjectForEntityForName:#"DbHomeCategory" inManagedObjectContext:context];
NSInteger categoryId = [[content valueForKey:#"category_id"] integerValue];
homeCategory.category = [self gCategoryWithCategoryId:[NSNumber numberWithInteger:categoryId]];
NSInteger count = [[content valueForKey:#"count"] integerValue];
homeCategory.count = [NSNumber numberWithInteger:count];
homeCategory.type = type;
[homePageObjects addObject:homeCategory];
}
break;
case 3:
{
NSDictionary *content = [object objectForKey:#"content"];
NSManagedObjectContext *context = [[MainDb sharedDb] managedObjectContext];
DbHomeDish *homeDish = [NSEntityDescription insertNewObjectForEntityForName:#"DbHomeDish" inManagedObjectContext:context];
homeDish.dishId = [self gInt:content forKey:#"dish_id"];
homeDish.headline = [AppUtils checkForEmptyValue:[content valueForKey:#"title"]];
homeDish.text = [AppUtils checkForEmptyValue:[content valueForKey:#"description"]];
homeDish.cuisineId = [self gInt:content forKey:#"cuisine_id"];
homeDish.cuisine = [self gCuisineWithCuisineId:homeDish.cuisineId];
homeDish.creationDate = [AppUtils checkForEmptyValue:[content valueForKey:#"creation_time"]];
homeDish.userId = [self gInt:content forKey:#"user_id"];
homeDish.longitude = [self gDouble:content forKey:#"lng"];
homeDish.latitude = [self gDouble:content forKey:#"lat"];
homeDish.lastPromoteDate = [AppUtils checkForEmptyValue:[content valueForKey:#"last_promote_time"]];
homeDish.price = [self gInt:content forKey:#"price"];
homeDish.currency = [AppUtils checkForEmptyValue:[content valueForKey:#"currency"]];
homeDish.countryName = [AppUtils checkForEmptyValue:[content valueForKey:#"country_name"]];
homeDish.baseCurrency = [self gFloat:content forKey:#"base_currency"];
homeDish.exchangeRate = [self gFloat:content forKey:#"exchange_rate"];
homeDish.countryIsoCode = [AppUtils checkForEmptyValue:[content valueForKey:#"country_iso_code"]];
homeDish.mainPhoto = [AppUtils checkForEmptyValue:[content valueForKey:#"main_photo"]];
homeDish.like = [self gLikeWithDishId:homeDish.dishId];
homeDish.profileImageURL = [AppUtils checkForEmptyValue:[content valueForKey:#"profile_img_url"]];
homeDish.likeCount = [self gInt:content forKey:#"likes"];
homeDish.type = type;
[homePageObjects addObject:homeDish];
}
break;
default:
break;
}
}
// ##log -- Save data to core data and device
//
//
[[MainDb sharedDb] saveContext];
if (success) {
success(operation, homePageObjects);
}
}
}
Seriously, you should consider refactoring using a NSFetchedResultsController. Start from the template provided in Xcode (New Project -> Master/Detail -> check Core Data, the code is in MasterViewController.m).
I strongly discourage loading Core Data objects into an array to be displayed in a table view. Your problem is typical for such a setup, and you will run into memory and performance issues eventually as well.

load Game Center friends and their scores into UITableView

So I was wondering after reading the apple docs(https://developer.apple.com/library/ios/documentation/GameKit/Reference/GKLeaderboard_Ref/Reference/Reference.html#//apple_ref/occ/instp/GKLeaderboard/category) how would one create a UITableView and fill it with the localPlayers Game Center friends and there scores in a specific leaderboard. I know how to get the friends list and friends scores individually by using the loadScoresWithCompletionHandler: method.
Edit: So far I got this to get individual friends photo, score and displayname saved into one NSArray. But i can't figure out how to disply them in a UITableView.
- (void) loadPlayerData: (NSArray *) identifiers
{
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil) {
leaderboardRequest.playerScope = GKLeaderboardPlayerScopeFriendsOnly;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardRequest.category = #"MJ_IL";
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil) {
// handle the error. if (scores != nil)
}
if (scores != nil){
for (GKScore* score in scores) {
NSArray *playerIdArray = [NSArray arrayWithObject:score.playerID];
[GKPlayer loadPlayersForIdentifiers:playerIdArray withCompletionHandler:^(NSArray *players, NSError *error) {
GKPlayer *player = [players objectAtIndex:0];
[player loadPhotoForSize:GKPhotoSizeSmall withCompletionHandler:^(UIImage *photo, NSError *error) {
if (score.playerID == player.playerID) {
if (photo != nil) {
playerInfo = [NSArray arrayWithObjects:score, player.displayName, photo, nil];
} else if (photo == nil) {
playerInfo = [NSArray arrayWithObjects:score, player.displayName, nil];
}
if (error != nil) {
NSLog(#"%#", error.localizedDescription);
}
}
}];
}];
}
}
}];
}
}
- (void)compareLocalPlayerScoreWithFriends {
GKScore *friendScore = [playerInfo objectAtIndex:0];
NSString *friendDisplayName = [playerInfo objectAtIndex:1];
if ([playerInfo objectAtIndex:2] != nil) {
UIImage *friendPhoto = [playerInfo objectAtIndex:2];
if (friendScore.value > interactiveHighscore) {
[friendNameLabel setText:friendDisplayName];
[friendScoreLabel setText:(NSString *)friendScore];
friendImageView.image = friendPhoto;
}
}
}
Thanks guys,
Georges
Take a look at this tutorial by Ray Wenderlich, it explains how to display simple pictures and text in a UITableView - there are three parts and should get you working with, at least, a basic but working view.
At its very core level this is the code that does "the work" for displaying in a UITableView
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"MyBasicCell"];
ScaryBugDoc *bug = [self.bugs objectAtIndex:indexPath.row];
cell.textLabel.text = bug.data.title;
cell.imageView.image = bug.thumbImage;
return cell;
}
Update
Here is my code for generating leaderbord data with alias and photos, hope you can modify it appropriately but shouldnt be too different
-(void)getScoresAndAliasForLeaderboard:(GKLeaderboard *)leaderboardRequest{
if (leaderboardRequest == nil)
{
leaderboardRequest = [[GKLeaderboard alloc] init];
leaderboardRequest.playerScope = GKLeaderboardPlayerScopeFriendsOnly;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardRequest.category = #"HighScore";
leaderboardRequest.range = NSMakeRange(1,100);
}
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil)
{
// Handle the error.
}
if (scores != nil)
{
NSMutableArray *retrievePlayerIDs = [[NSMutableArray alloc] init];
for (GKScore *s in scores)
{
[retrievePlayerIDs addObject:s.playerID];
GCLeaderboardScore *playerScore = [[GCLeaderboardScore alloc] init];
playerScore->playerID = s.playerID;
playerScore->score = (int)s.value;
playerScore->rank = s.rank;
playerScores[s.playerID] = playerScore; //playerScores is a NSMutableDictionary
if ([s.playerID isEqualToString: leaderboardRequest.localPlayerScore.playerID]){
me = playerScore;
}
}
if (me == nil){
me = [[GCLeaderboardScore alloc] init];
me->playerID = leaderboardRequest.localPlayerScore.playerID;
me->score = leaderboardRequest.localPlayerScore.value;
me->alias = #"Me";
playerScores[me->playerID] = me;
}
[GKPlayer loadPlayersForIdentifiers:retrievePlayerIDs withCompletionHandler:^(NSArray *playerArray, NSError *error)
{
for (GKPlayer* p in playerArray)
{
GCLeaderboardScore *playerScore = playerScores[p.playerID];
playerScore->alias = p.alias;
[p loadPhotoForSize:GKPhotoSizeSmall withCompletionHandler:^(UIImage *photo, NSError *error) {
if (photo != nil) {
playerScore->photo = photo;
}
else{
playerScore->photo = [UIImage imageNamed:#"wordpress_avatar.jpg"];
}
if (error != nil) {
NSLog(#"%#", error.localizedDescription);
}
}];
}
}];
}
}];
}

CoreData and NSManagedObjectContext

I've got this function that will move objects from a "fallbackstore" to the iCloud store, fallbackstore is the store where objects where saved when iCloud is unavailable.
Bottom line, I need to move objects (with their relationship) from one context to another one.
But I'm getting this error:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Context already has a coordinator; cannot replace.'
* First throw call stack:
on:
foodSuccess = [moc save:&localError];
Anybody knows where I'm getting wrong (and why)? Thanks in advance!
- (BOOL)seedStore:(NSPersistentStore *)store withPersistentStoreAtURL:(NSURL *)seedStoreURL error:(NSError * __autoreleasing *)error {
BOOL success = YES;
NSLog(#"%s", __func__);
BOOL foodSuccess = YES;
BOOL sportSuccess = YES;
BOOL dailySuccess = YES;
BOOL activitySuccess = YES;
BOOL reportSuccess = YES;
BOOL userSuccess = YES;
BOOL ingredientSuccess = YES;
NSUInteger batchSize = 5000;
NSError *localError = nil;
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *seedPSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSDictionary *seedStoreOptions = #{ NSReadOnlyPersistentStoreOption : [NSNumber numberWithBool:YES] };
NSPersistentStore *seedStore = [seedPSC addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:seedStoreURL
options:seedStoreOptions
error:&localError];
if (seedStore) {
NSManagedObjectContext *seedMOC = [[NSManagedObjectContext alloc] init];
[seedMOC setPersistentStoreCoordinator:seedPSC];
// Food
NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:#"Food"];
fr.relationshipKeyPathsForPrefetching = #[#"daily", #"ingredient", #"ingredients"];
[fr setFetchBatchSize:batchSize];
NSArray *foods = [seedMOC executeFetchRequest:fr error:&localError];
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[moc setPersistentStoreCoordinator:_psc];
NSUInteger i = 1;
for (Food *f in foods) {
[self addFood:f toStore:store withContext:moc];
if (0 == (i % batchSize)) {
foodSuccess = [moc save:&localError];
if (foodSuccess) {
[moc reset];
} else {
NSLog(#"Error saving during seed (Food): %#", localError);
break;
}
}
i++;
}
if ([moc hasChanges]) {
foodSuccess = [moc save:&localError];
[moc reset];
}
// Sport
NSFetchRequest *fetchSports = [NSFetchRequest fetchRequestWithEntityName:#"Sport"];
fetchSports.relationshipKeyPathsForPrefetching = #[#"activity"];
fetchSports.fetchBatchSize = batchSize;
NSArray *sports = [seedMOC executeFetchRequest:fetchSports error:&localError];
NSManagedObjectContext *sportContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
sportContext.persistentStoreCoordinator = _psc;
NSUInteger iSports = 1;
for (Sport *s in sports) {
[self addSport:s toStore:store withContext:sportContext];
if (0 == (iSports % batchSize)) {
sportSuccess = [moc save:&localError];
if (sportSuccess) {
[moc reset];
} else {
NSLog(#"Error saving during seed (Sport): %#", localError);
break;
}
}
iSports++;
}
if ([sportContext hasChanges]) {
sportSuccess = [sportContext save:&localError];
[sportContext reset];
}
// Daily
NSFetchRequest *fetchDailies = [NSFetchRequest fetchRequestWithEntityName:#"Daily"];
fetchDailies.relationshipKeyPathsForPrefetching = #[#"food", #"user"];
fetchDailies.fetchBatchSize = batchSize;
NSArray *dailies = [seedMOC executeFetchRequest:fetchDailies error:&localError];
NSManagedObjectContext *dailiesContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
dailiesContext.persistentStoreCoordinator = _psc;
NSUInteger iDailies = 1;
for(Daily *d in dailies) {
[self addDaily:d toStore:store withContext:dailiesContext];
if(0 == (iDailies % batchSize)) {
dailySuccess = [dailiesContext save:&localError];
if (dailySuccess) {
[dailiesContext reset];
}
else {
NSLog(#"Error saving during seed (Daily): %#", localError);
break;
}
}
iDailies++;
}
if ([dailiesContext hasChanges]) {
dailySuccess = [dailiesContext save:&localError];
[dailiesContext reset];
}
// Ingredient
NSFetchRequest *fetchIngredients = [NSFetchRequest fetchRequestWithEntityName:#"Ingredient"];
fetchIngredients.relationshipKeyPathsForPrefetching = #[#"food", #"foods"];
fetchIngredients.fetchBatchSize = batchSize;
NSArray *ingredients = [seedMOC executeFetchRequest:fetchIngredients error:&localError];
NSManagedObjectContext *ingredientsContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
ingredientsContext.persistentStoreCoordinator = _psc;
NSUInteger iIngredients = 1;
for(Ingredient *i in ingredients) {
[self addIngredient:i toStore:store withContext:ingredientsContext];
if(0 == (iIngredients % batchSize)) {
ingredientSuccess = [ingredientsContext save:&localError];
if (ingredientSuccess) {
[ingredientsContext reset];
}
else {
NSLog(#"Error saving during seed (Ingredient): %#", localError);
break;
}
}
iIngredients++;
}
if ([ingredientsContext hasChanges]) {
ingredientSuccess = [ingredientsContext save:&localError];
[ingredientsContext reset];
}
// Activity
NSFetchRequest *fetchActivities = [NSFetchRequest fetchRequestWithEntityName:#"Activity"];
fetchActivities.relationshipKeyPathsForPrefetching = #[#"sport", #"user"];
fetchActivities.fetchBatchSize = batchSize;
NSArray *activities = [seedMOC executeFetchRequest:fetchActivities error:&localError];
NSManagedObjectContext *activitiesContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
dailiesContext.persistentStoreCoordinator = _psc;
NSUInteger iActivities = 1;
for(Activity *a in activities) {
[self addActivity:a toStore:store withContext:activitiesContext];
if(0 == (iActivities % batchSize)) {
activitySuccess = [activitiesContext save:&localError];
if (activitySuccess) {
[activitiesContext reset];
}
else {
NSLog(#"Error saving during seed (Activity): %#", localError);
break;
}
}
iActivities++;
}
if ([activitiesContext hasChanges]) {
activitySuccess = [activitiesContext save:&localError];
[activitiesContext reset];
}
// Report
NSFetchRequest *fetchReports = [NSFetchRequest fetchRequestWithEntityName:#"Report"];
fetchReports.relationshipKeyPathsForPrefetching = #[#"user"];
fetchReports.fetchBatchSize = batchSize;
NSArray *reports = [seedMOC executeFetchRequest:fetchReports error:&localError];
NSManagedObjectContext *reportsContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
reportsContext.persistentStoreCoordinator = _psc;
NSUInteger iReports = 1;
for(Report *r in reports) {
[self addReport:r toStore:store withContext:reportsContext];
if(0 == (iReports % batchSize)) {
reportSuccess = [reportsContext save:&localError];
if (reportSuccess) {
[reportsContext reset];
}
else {
NSLog(#"Error saving during seed (Report): %#", localError);
break;
}
}
iReports++;
}
if ([reportsContext hasChanges]) {
reportSuccess = [reportsContext save:&localError];
[reportsContext reset];
}
// User
NSFetchRequest *fetchUsers = [NSFetchRequest fetchRequestWithEntityName:#"User"];
fetchUsers.relationshipKeyPathsForPrefetching = #[#"activities", #"dailies", #"reports"];
fetchUsers.fetchBatchSize = batchSize;
NSArray *users = [seedMOC executeFetchRequest:fetchUsers error:&localError];
NSManagedObjectContext *usersContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
usersContext.persistentStoreCoordinator = _psc;
NSUInteger iUsers = 1;
for(User *u in users) {
[self addUser:u toStore:store withContext:usersContext];
if(0 == (iUsers % batchSize)) {
userSuccess = [usersContext save:&localError];
if (userSuccess) {
[usersContext reset];
}
else {
NSLog(#"Error saving during seed (User): %#", localError);
break;
}
}
iUsers++;
}
if ([usersContext hasChanges]) {
userSuccess = [usersContext save:&localError];
[usersContext reset];
}
// Result
success = foodSuccess && sportSuccess && dailySuccess && ingredientSuccess && activitySuccess && reportSuccess && userSuccess;
} else {
success = NO;
NSLog(#"Error adding seed store: %#", localError);
}
if (NO == success) {
if (localError && (error != NULL)) {
*error = localError;
}
}
return success;
}
- (void)addFood:(Food *)food toStore:(NSPersistentStore *)store withContext:(NSManagedObjectContext *)moc
{
NSEntityDescription *entity = [food entity];
Food *newFood = [[Food alloc] initWithEntity:entity insertIntoManagedObjectContext:moc];
newFood.alcol = food.alcol;
newFood.amid = food.amid;
newFood.bookmark = food.bookmark;
newFood.calcium = food.calcium;
newFood.cho = food.cho;
newFood.cholesterol = food.cholesterol;
newFood.complex = food.complex;
newFood.copper = food.copper;
newFood.dirty = food.dirty;
newFood.edible = food.edible;
newFood.fat = food.fat;
newFood.fatMono = food.fatMono;
newFood.fatPoli = food.fatPoli;
newFood.fatSat = food.fatSat;
newFood.fibre = food.fibre;
newFood.iron = food.iron;
newFood.kcal = food.kcal;
newFood.lookback = food.lookback;
newFood.magnesium = food.magnesium;
newFood.name = food.name;
newFood.note = food.note;
newFood.phosphorus = food.phosphorus;
newFood.potassium = food.potassium;
newFood.pro = food.pro;
newFood.recipe = food.recipe;
newFood.recordUUID = (food.recordUUID == nil) ? [[[NSUUID alloc] init] UUIDString] : food.recordUUID;
newFood.serving = food.serving;
newFood.servingDesc = food.servingDesc;
newFood.sodium = food.sodium;
newFood.userAdd = food.userAdd;
newFood.vitA = food.vitA;
newFood.vitC = food.vitC;
newFood.vitE = food.vitE;
newFood.water = food.water;
newFood.zinc = food.zinc;
newFood.dosePeople = food.dosePeople;
newFood.daily = food.daily;
for(Ingredient *i in food.ingredients) {
NSEntityDescription *entityIngredient = [i entity];
Ingredient *newIngredient = [[Ingredient alloc] initWithEntity:entityIngredient insertIntoManagedObjectContext:moc];
[newFood addIngredientsObject:newIngredient];
}
NSMutableSet *ing = [food mutableSetValueForKey:#"ingredient"];
for(Ingredient *i in ing) {
NSLog(#"%s Name: %#", __func__, i.food.name);
NSEntityDescription *entityIngredient = [i entity];
Ingredient *newIngredient = [[Ingredient alloc] initWithEntity:entityIngredient insertIntoManagedObjectContext:moc];
[newFood addIngredientsObject:newIngredient];
}
[moc assignObject:newFood toPersistentStore:store];
}
It might or might not be the cause for the error you're getting but if you initialize a MOC with NSPrivateQueueConcurrencyType you should strictly access it through -performBlock: and -performBlockAndWait:. See this related question.

Resources