How to make a FetchRequest in a callback block asynchronously

Does anyone know how to start a new asynchronous method in the completion block of the first asynchronous communication?

I am testing the code to make an NSFetchRequest call (coz STACKMOB iOS SDK internally synchronize with the server) asynchronously in completing a callback to another asynchronous Facebook connection. Code execution abruptly terminates in the NSFetchRequest line. I understood one of the reasons why it does not work correctly. I assume that the completion block was freed from memory as soon as [managedObjectContext executeFetchRequest: error fetchRequest: & error] is called. but I don’t know a better solution to fix this. Thanks for any help.

The SDK uses:

  • (void) queueRequest: (NSURLRequest *) request parameters: (SMRequestOptions *) options onSuccess: (SMFullResponseSuccessBlock) onSuccess onFailure: (SMFullResponseFailureBlock) onFailure

https://github.com/stackmob/stackmob-ios-sdk/blob/master/Classes/SMDataStore%2BProtected.m

I tried:

:

- (IBAction)checkFacebookInfo:(id)sender { //completion block of facebook info void(^onCompleteBlock)(NSDictionary*) = [[^(NSDictionary* userInfo) { NSManagedObjectContext *managedObjectContext = nil; managedObjectContext = [[SingletonCoreData sharedManager] managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"User"]; //for STACKMOB, customized NSFetchRequest internally sync to the server. It is Asynchronous method. NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];// failed //Not reached here //set userInfo to results here } copy] autorelease]; //invoke onCompleteBlock after executing asynchronously, client(SMClient object for STACKMOB) [client getLoggedInUserFacebookInfoWithOnSuccess:onCompleteBlock onFailure:^(NSError *error) { NSLog(@"No user found"); }]; } 

Edited: I tried this as described below, then it works successfully. But I feel it slowly. I put part of the code in the dispatch_async block. I am waiting for another better solution.

  - (IBAction)checkFacebookInfo:(id)sender { //completion block of facebook info void(^onCompleteBlock)(NSDictionary*) = ^(NSDictionary* userInfo) { dispatch_queue_t gQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(gQueue, ^{ NSManagedObjectContext *managedObjectContext = nil; managedObjectContext = [[SingletonCoreData sharedManager] managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"User"]; //for STACKMOB, customized NSFetchRequest internally sync to the server. It is Asynchronous method. NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];// success //set userInfo to results here }); }; //invoke onCompleteBlock after executing asynchronously, client(SMClient object for STACKMOB) [client getLoggedInUserFacebookInfoWithOnSuccess:onCompleteBlock onFailure:^(NSError *error) { NSLog(@"No user found"); }]; } 
+4
source share
1 answer

If you are trying to synchronize several asynchronous operations (over the network or otherwise), I cannot recommend enough using promises. For a general introduction to promises, a recent Los Techies blog entry is pretty good:

http://lostechies.com/derickbailey/2012/07/19/want-to-build-win8winjs-apps-you-need-to-understand-promises/

However, there is a good library called KSPromise , which I used quite a lot in iOS: https://github.com/kseebaldt/deferred

Using promises, you can execute a fetch request after completing one or more asynchronous calls. For example, the promise of union will be resolved only after all of its dependent promises have also been resolved! I think you will find that with promises your code becomes more organized and easier to read, especially if you are doing something complicated.

However, here's a pretty far-fetched example showing a possible way to write code using promises (written against the SDK for iOS 3.1):

 - (IBAction)checkFacebookInfo:(FBSession *)session { KSDeferred *dfd = [KSDeferred defer]; FBRequest *meRequest = [[FBRequest alloc] initWithSession:session graphPath:@"/me"]; [meRequest startWithCompletionHandler: ^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) { if (error) { [dfd.promise rejectWithError:error]; } else { [dfd.promise resolveWithValue:user]; } }]; [dfd.promise whenResolved:^(KSPromise *p) { NSDictionary *userInfo = p.value; NSManagedObjectContext *managedObjectContext = [[SingletonCoreData sharedManager] managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"User"]; NSError *error; NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error]; // Do whatever with results and userInfo here }]; [dfd.promise whenRejected:^(KSPromise *p) { NSError *e = (NSError *)p.value; NSLog(@"Error: %@", [e localizedDescription]); }]; } 

Last: Be very careful when using Core Data with streams and dispatch_async . You can run all kinds of hard-to-debug concurrency issues.

0
source

Source: https://habr.com/ru/post/1447201/


All Articles