GTLServiceYouTube executeQuery callback not called - ios

GTLServiceYouTube executeQuery callback not called when I execute it in background thread.Video wont get uploaded. It works fine when I execute it in main thread.I get callbacks and video is also uploaded. I can solve this by forcing executeQuery to run in main thread but that affects the UI performance. How can I solve this issue?
My code goes like this ,
self.uploadFileTicket = [service executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
GTLYouTubeVideo *uploadedVideo,
NSError *error) {
// code to handle
}

I found a solution! Here whats happening is, when I run the code in background thread, before the callback comes the thread is detached. Hence we don't get the callback. When I run it in main thread, main Thread remains alive throughout. Hence we do get callback. Hence this problem can be solved by making current thread to wait using following code.
[[NSRunLoop currentRunLoop] runUntilDate:stopDate];

Related

dispatch_semaphore_signal never being executed because of the wait

I am trying to take two pictures and want them to run in order. The method for capturing pictures is done using a method that runs asynchronously. I currently use semaphores to try to synchronize this, but it stops the program from running. I believe this is because the completionHandler is run on the same thread, and since the thread is locked, it can't execute to free the semaphore.
Here is my current code:
camera_sema = dispatch_semaphore_create(0);
[photoOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)
{
[flash turnOffFlash];//turning off flash for second picture
//perform needed work
dispatch_semaphore_signal(camera_sema);
}];
dispatch_semaphore_wait(camera_sema, DISPATCH_TIME_FOREVER);
 Is there a way I can use dispatch_async for this case or a way to run the completionHandler on another background thread so it is able to execute?
UPDATE 1:
This works but not sure if its the best way to do it.
-(void*)method: (int) iteration {
[photoOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)
{
[flash turnOffFlash];//turning off flash for second picture
//perform needed work
//base case
[method: iteration-1];
}];
}
So basically I call the method recursively to ensure that it only repeats once the callback has been reached. It will essentially run an async task synchronously. Unfortunately, for the final design, I need to be able to run it infinitely. Doing this recursively will fail. Please let me know if there is better way to do this.

Asynchronous NSURLConnection breaks timers

I have a class set up to handle my web API calls. This is done using an NSMutableURLRequest and an NSRLlConnection. I initially used connectionWithRequest: delegate: and that worked well for the most part, except when I depended on this request being truly asynchronous, not just partially executing in the main run loop.
To do this, I thought I would just use the ever so convenient sendAsynchronousRequest: queue: completionHandler: and at first in all of my unit tests I thought this worked great. It performed asynchronously, my semaphores were waited on and signaled correctly, it was great.
Until I tried to re-use this new modified version of my Web service class in my actual app. Part of my app plays a video and uses a repeating NSTimer to update part of the screen based on the current playback time of the video. For some unknown reason, as long as I have executed at least one of these new asynchronous NSURLConnections both the video playback and the timer no longer work.
Here is how I initialize the connection:
[NSURLConnection sendAsynchronousRequest:requestMessage
queue:[[NSOperationQueue alloc] init]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
if ( data.length > 0 && connectionError == nil )
{
_webServiceData = [data mutableCopy];
[self performSelector:#selector(connectionDidFinishLoading:) withObject:nil];
}
else if ( connectionError != nil )
{
_webServiceData = [data mutableCopy];
[self performSelector:#selector(webServiceDidFinishExecutingWithError:) withObject:connectionError];
}
}];
Here is how I initialize my repeating timer:
playbackTimeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(checkPlaybackTime) userInfo:nil repeats:YES];
And I have absolutely no idea why the asynchronous NSURLConnection is causing aspects of my app that are completely unrelated to stop functioning.
EDIT:
For clarification I have ViewControllerA that performs the web requests to retrieve some data. When that data is successfully retrieved, ViewControllerA automatically segues to ViewControllerB. In ViewControllerB's viewWillAppear is where I set up my movie player and timer.
In the future, do not use semaphores to make the test wait. Use the new XCTestExpectation, which is designed for testing asynchronous processes.
And unlike the traditional semaphore trick, using the test expectation doesn't block the main thread, so if you have completion blocks or delegates that require the main thread, you can do this in conjunction with the test expectation.
You're clearly doing something that isn't working because you're running this on the background queue. Typical problems include
If you were trying to run that timer from the background thread, that wouldn't work, unless you used one of the standard timer workarounds (scheduling it on main runloop, dispatching the creation of the timer back to main thread, using dispatch timer, etc.).
Having earlier described these alternatives in great detail, it turns out you're initiating the timer from viewWillAppear, so that's all academic.
any UI updates (including performing segues, reloading tables, etc.).
care should be taken when synchronizing class properties updated from background thread (these might best be dispatched to main thread, too).
Anyway, you might remedy this by just tell sendAsynchronousRequest to run its completion block on the main queue:
[NSURLConnection sendAsynchronousRequest:requestMessage
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
...
}];
Then, the completion block would have run on the background queue, and everything would probably be fine. Or you can manually dispatch the calling of your completion handlers back to the main queue.
But make sure that any UI updates (including the performing a segue programmatically) are run on the main thread (either by running the whole completion block on the main thread, or manually dispatching the relevant calls to the main thread).

Executing synchronous queries to Google Cloud Endpoints on iOS

I guess this is really a feature request to Google, but I'm curious if anyone knows a work around. I'd like to execute a synchronous query request to a GAE Endpoints api.
In Android executing a request is synchronous. Then you put it into an AsyncTask to make it work in the background.
In iOS executing a request is asynchronous. You simply pass in a callback block.
I'm converting an Android app into an iOS app and it'd be really nice if they used the same mechanism. For example there are times when I WANT a synchronous query. It just makes my code easier and I know to put it on a background thread.
So my question is this... is there any way (hacky or not) to block until the iOS query completes?
You can wait on the call to finish with code with a timeout using code similar to this. Obviously you wouldn't want to do this on a UI thread but this would ensure your completion handlers run in serial.
NSLog(#"Before API Call");
GTLServiceTicket *apiCall = [apiService executeQuery:query completionHandler:^(GTLServiceTicket *ticket,
GTLHelloworldHelloGreeting *object,
NSError *error) {
NSLog(#"Starting completion handler");
NSArray *greetings = [NSArray arrayWithObjects: object, nil];
greetingsRetrievedFromAPI = greetings;
[self performSegueWithIdentifier: #"DisplayGreetings" sender: self];
NSLog(#"Ending completion handler");
}];
[apiService waitForTicket:apiCall timeout:100000 fetchedObject:nil error:nil];
NSLog(#"After completion handler");

MagicalRecord : how to perform background saves

I am building a news application, which basically fetches data from a distant server, using AFNetworkOperation (all operations are put in a NSOperationQueue in order to properly manage the synchronisation process and progress).
Each completion block of each AFNetworkOperation creates/deletes/updates core data entities.
At the whole end of the synchronisation process, in order to make all changes persistent, I perform a full save with following lines of code
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(queue, ^{
NSLog(#"saveInBackground : starting...");
[[NSManagedObjectContext defaultContext] saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
NSLog(#"saveInBackground : finished!");
}];
});
Unfortunately it always blocks the main thread during my save operation.
I might not use MagicalRecord properly and so any advice would be welcome.
After digging deeper inside MagicalRecord, it seems that my code is working well and does not block main thread at all.
My issue is not on MagicalRecord, but on the way I should use it on completion blocks of afnetworking operation.
I Will start a new discussion to provide full details on it.

Executing Core Data saving on a background thread?

I've got a button which marks a selected entry in a Core Data SQLite as a "Favourite", meaning I'm just flipping a BOOL for that index from off to on.
Currently, when I do this, I call save on the managedObjectContext, which takes maybe 500ms, perhaps a little more, according to Instruments.
I have some code that executes at the same time which triggers a nifty little particle explosion ("Hooray, a favourite!"), but I'm running into an issue where that explosion is delayed until after the save has completed.
I'm not sure why, since the code to trigger the explosion is before the save call. I'm a relatively new programmer so perhaps I'm missing something, but doesn't code execute line by line in a case like this, in that the explosion would trigger, then the save would occur while it's going? The delegate call here may be taking some time too, but the same question applies, why would it matter if it's after those lines of code?
EDIT: Am I right in saying that the main thread is being blocked before the particles appear by the next lines of code, meaning the UI can't update itself?
Here's my code:
// Particle animation
LikeExplosion *likeExplosionView = [[LikeExplosion alloc] initWithFrame: CGRectMake(0, 0, 320, 400)];
[likeExplosionView setUserInteractionEnabled: NO];
[self.view addSubview: likeExplosionView];
[self.view bringSubviewToFront: likeExplosionView];
[likeExplosionView decayOverTime: 1.1];
// Delegate call to reload tableview elsewhere
[self.delegate detailViewControllerDidLikeLine];
// Update current object
[_selectedLine setIsLiked: [NSNumber numberWithBool: YES]];
[_selectedLine setIsDisliked: [NSNumber numberWithBool: NO]];
// Update context
NSError *error;
if (![[[CDManager sharedManager] managedObjectContext] save:&error]) NSLog(#"Saving changes failed: %#, %#", error, [error userInfo]);
First question: why is there a delay, when I'm calling the animation code first in the method?
Second question: would putting the save call on a background thread solve the problem, and is it safe / a good idea to do so?
Animations, and generally anything have to do with the UI is executed on the main thread. If you don't want the persistence to disk (the saving process) to hold up your UI (main thread) you need to put the context on it own private queue via NSManagedObjectContext's initWithConcurrencyType: method. The private queue will handle any background threads having to do with the context for you. The three types are:
NSConfinementConcurrencyType
NSPrivateQueueConcurrencyType
NSMainQueueConcurrencyType
You would want NSPrivateQueueConcurrencyType.
You could take a more complex architecture route by using child/nested managed object contexts with different concurrency types, but if you are new to Core Data, stick with a single context until you get a firm grasp of contexts and queues.
1) your animation will not start running until the main runloop complete its cycle. this cycle will not complete as save: is a blocking method.
2) Moving your save to a background thread will solve the issue, but you must access the main managedObjectContext in the main thread, so, you either have to use a background context:
NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:context];
[context performBlock:^{
//make changes
NSError* error = nil;
[context save:&error];
//remember to remove observer after the save (in mergeChanges: and dealloc)
}];
You might be able to start the animation without moving to background by scheduling the save on the main thread in the next runloop using: [self performSelectorOnMainThread:#selector(saveMain) withObject:nil waitUntilDone:NO];
Check out this great article on CIMGF.com! ;)
After reading the tutorial you should know how to approach this problem.

Resources