Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

saveWithBlock:completion: not saving #656

Closed
arsenius opened this Issue · 6 comments

4 participants

Timothy Costa Tony Arnold Saul Mora jaysonjh
Timothy Costa

Hi, and thank you for your great library!

I'm having trouble getting my objects to save using the method saveWithBlock:completion. When I switch over to using normal blocks it works fine. Using version 2.2develop. The [NSObject execute:] methods just wrap dispatch_async.

Here's the code that works. I have commented out the saveWithBlock: parts. In the code below executeBlockOnMainThread: replaces completion:.

I'd be grateful for any help!

- (void)requestRelatedPhrasesForCard:(Card*)card completionDelegate:(id)delegate{
[card.managedObjectContext MR_saveToPersistentStoreAndWait]; // This is necessary because the fragment may otherwise get lost.

//  [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
[NSObject executeBlockInBackground:^{

    Card *localCard = [card MR_inContext:[NSManagedObjectContext MR_contextForCurrentThread]]; //MR_inContext:localContext];
    NSRange range = [localCard.fragment rangeOfString:localCard.term options:NSCaseInsensitiveSearch];
    if (range.location == NSNotFound){
        return; // Why would you set a fragment with no term in it?!
    }

    NSString *fragmentString = [localCard.fragment stringByReplacingOccurrencesOfString:@" " withString:@"+"];
    NSString *url = [NSString stringWithFormat:@"https://www.lingq.com/api/languages/%@/phrases/?word=%@&frag=%@&start=%@", appDelegate.currentLanguage, localCard.term, fragmentString, @(range.location)];
    NSMutableURLRequest *request = [LQAPI requestForURL:url body:nil HTTPMethod:@"GET"];
    NSData *response = [LQAPI executeURLRequest:request];

    NSDictionary *responseDictionary = [LQAPI dictionaryFromJSONData:response];
    if (responseDictionary == nil){
        return; // There was no response or it was not a dictionary, meaning there are no phrases.
    }

    NSArray *phrases = [responseDictionary objectForKey:@"phrases"];
    NSMutableArray *cards = [NSMutableArray array];
    int index = 0;
    for (NSDictionary *d in phrases){
        Card *c = [self cardFromDictionary:d content_id:localCard.content_Id index:index type:BlueCard];
        c.parentID = localCard.mId; // This marks it as a phrase
        [cards addObject:c];
        index++;
    }
    [localCard.managedObjectContext MR_saveToPersistentStoreAndWait]; // This shouldn't be necessary using saveWithBlock: and it didn't help when I tried it.
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"parentID = %@", localCard.mId];
    NSArray *phrases2 = [Card MR_findAllWithPredicate:predicate]; // All the objects appear fine here
    [NSObject executeBlockOnMainThread:^{ // This would have been in the completion block below
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"parentID = %@", card.mId];
        NSArray *phrases = [Card MR_findAllWithPredicate:predicate];
        [delegate didFetchPhrases:phrases forCard:card];
    }];
}];
/*   completion:^(BOOL success, NSError *error) {
     NSPredicate *predicate = [NSPredicate predicateWithFormat:@"parentID = %@", card.mId];
     NSArray *phrases = [Card MR_findAllWithPredicate:predicate]; // This doesn't find any objects
     [delegate didFetchPhrases:phrases forCard:card];
 }];*/
}
Tony Arnold
Owner

Hi @arsenius — thanks for the kind words!

Card *localCard = [card MR_inContext:[NSManagedObjectContext MR_contextForCurrentThread]]; //MR_inContext:localContext];

Don't do that — MR_contextForCurrentThread is unreliable and deprecated. You had it right the first time:

Card *localCard = [card MR_inContext:localContext];

Also, everything in the block is executed before the save to disk occurs. Pushing things off using NSObject executeBlockOnMainThread: is highly unlikely to work (if it does, it won't work every time). Can you try reverting everything to how it should be — no calling save within the save block, always accessing/creating objects in localContext. And see what happens then?

Tony Arnold tonyarnold was assigned
Timothy Costa

Well, I don't know what was going on before, but it does work now. Honestly, I wrestled with that code for quite a while before posting it on here. All I did is revert all those parts I had commented out and it works fine now.

If you don't mind, could you explain about why executeBlockOnMainThread: is unlikely to work? I only just learned about saveWithBlock: a few days ago, and until then I had been using the method above quite a bit without major problems. It is quite convenient when I have fetched something from the server that I don't want to save via core data, but needs to reach the main thread.

Also, if MR_contextForCurrentThread is deprecated, is there a replacement for it? localContext obviously wasn't available with executeBlockInBackground:. What if I need to get a context in a background thread? Is it just always dangerous? I think I've got a few calls to that peppered throughout my code.

This works:
- (void)requestRelatedPhrasesForCard:(Card*)card completionDelegate:(id)delegate{
[card.managedObjectContext MR_saveToPersistentStoreAndWait]; // This is necessary because the fragment may otherwise get lost.

[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {

    Card *localCard = [card MR_inContext:localContext];
    NSRange range = [localCard.fragment rangeOfString:localCard.term options:NSCaseInsensitiveSearch];
    if (range.location == NSNotFound){
        return; // Why would you set a fragment with no term in it?!
    }

    NSString *fragmentString = [localCard.fragment stringByReplacingOccurrencesOfString:@" " withString:@"+"];
    NSString *url = [NSString stringWithFormat:@"https://www.lingq.com/api/languages/%@/phrases/?word=%@&frag=%@&start=%@", appDelegate.currentLanguage, localCard.term, fragmentString, @(range.location)];
    NSMutableURLRequest *request = [LQAPI requestForURL:url body:nil HTTPMethod:@"GET"];
    NSData *response = [LQAPI executeURLRequest:request];

    NSDictionary *responseDictionary = [LQAPI dictionaryFromJSONData:response];
    if (responseDictionary == nil){
        return; // There was no response or it was not a dictionary, meaning there are no phrases.
    }

    NSArray *phrases = [responseDictionary objectForKey:@"phrases"];
    NSMutableArray *cards = [NSMutableArray array];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"parentID = %@", localCard.mId];
    [Card MR_deleteAllMatchingPredicate:predicate];
    int index = 0;
    for (NSDictionary *d in phrases){
        Card *c = [self cardFromDictionary:d content_id:localCard.content_Id index:index type:BlueCard];
        c.parentID = localCard.mId; // This marks it as a phrase
        c.fragment = localCard.fragment;
        c.mId = @(arc4random());
        [cards addObject:c];
        index++;
    }
    NSArray *phrases2 = [Card MR_findAllWithPredicate:predicate];
    ALog(@"phrases: %@", phrases2);
}
completion:^(BOOL success, NSError *error) {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"parentID = %@", card.mId];
    NSArray *phrases = [Card MR_findAllWithPredicate:predicate];
    [delegate didFetchPhrases:phrases forCard:card];
}];

}

Timothy Costa arsenius closed this
Timothy Costa arsenius reopened this
Timothy Costa

Well, I don't know what to say. Here I am a few hours later and that same code above is no longer working as before. All my phrases disappear by the time the completion block is called. I guess it has to be some side effect from some code someplace else in the app?

Saul Mora
Owner
jaysonjh

I'm having trouble getting my objects to save using the method saveWithBlock:completion too.
when I call savewithBlock:completion, console is printing save finished & insert sql log.But ,when I call some 'fetch Method',there is empty in db.

my code like this:
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name= %@", @"test"];
[Person MR_deleteAllMatchingPredicate:predicate];
Person *p= [Person MR_createInContext:localContext];
p.name = @"sssss";
}
completion:^(BOOL success, NSError *error) {
if(!success){
NSLog(@"error:%@",error);
}
}];

Saul Mora
Owner
Tony Arnold tonyarnold closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.