Strategy for getting data before app launch - ios

I have an app that the first thing it does is to register itself in an API, with a simple HTTP POST. I've been doing this in func application(application: UIApplication, willFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?), as Apple states that this is the point do to URL calls. As it is important to never block the main thread, this call is done async.
The problem is that as it is done async, the first screen opens and immediately a call to the API is done. As this is faster then the first API call, the second call gets a 401.
In order to avoid that, I am doing a very cheesy thing before starting the second call:
dispatch_async(dispatch_get_global_queue(priority, 0)) {
// do some task
while (InformationFromFirsCall == nil)
{
sleep(1)
}
}
Is there a better strategy to do this? I was thinking about using a dispatch_once at the beginning of every call to the API and implementing the code inside the callback of InformationFromFirstCall.
Is that reasonable?
Thanks!

Instead of using sleep, you can save CPU time by using a semaphore:
// declared somewhere where you can access it
dispatch_semaphore_t sema;
// willFinishLaunching
sema = dispatch_semaphore_create(0);
// when your async call completes
dispatch_semaphore_signal(sema);
// in your main UI — this is the same as the sleep call you have, but doesn't waste CPU time
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
A semaphore is an efficient mechanism for forcing one part of your app to wait while another app is doing something — a call to dispatch_semaphore_wait causes the current thread to hang until the semaphore's value becomes non-zero, which happens when dispatch_semaphore_signal is called.
See this answer for more details.
Note: this is C code; you will need to adapt it to Swift syntax if you are coding your app in Swift.

Related

Is asynchronous code always run on a different thread?

I really think that if code in Swift in iOS runs asynchronously, then it is by the nature of itself that it runs on a separate thread than the thread the code is called from - usually the main thread. It seems obvious to me, but I am uncertain and would like to receive verification of this. I can't think of any conditions in which an asynchronous code would run on the same code that it was called from. It seems almost a certainty by definition that an asynchronous code runs on a different thread than the thread it was called from.
What do you think? Would you agree and verify this?
I ask this question while trying to understand the #escaping keyword as it applies to completion handlers. The Swift documentation on Closuressays that the #escaping keyword causes the completion handler that is designated as escaping to run asynchronously and to run after the function (that receives the completion closure as an argument) finishes running. The documentation, however, does not say whether the escaping completion handler runs on a different thread or on the current thread - which would be the main/UI thread.
I'm trying to hunt where a run-time error is coming from. The error message says: "Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread."
It might be coming from the completion handler of CNContactStore requestAccess(for:completionHandler:), but I need to know if #escaping causes the closure it applies to to run on a different thread than the thread the closure was called from, since the completionHandler parameter is defined as escaping by the #escaping keyword in the definition of CNContactStore requestAccess(for:completionHandler:).
Is the error I'm getting coming from code inside the completion handler of that function that modifies the layout engine or any completion handler marked as escaping?
These posts on stackoverflow helped me clarify my question, but they do not answer my question:
Does Asynchronous code run in the UI thread or a new/different thread to not block the UI?
async - stay on the current thread?
#escaping does NOT determine which thread the closure is ran on. The documentation does.
For that specific function (https://developer.apple.com/documentation/contacts/cncontactstore/1402873-requestaccess/):
The system executes completionHandler on an arbitrary queue. It is recommended that you use CNContactStore instance methods in this completion handler instead of the UI main thread.
If you are doing any sort of UI work inside of the completionHandler callback, it means you MUST call DispatchQueue.main.async { update_my_UI_here() } to execute your code safely on the main thread.
Example:
requestAccess(for: .contacts) { [weak self] permissionGranted, error in
//All code in here is ran on an ARBITRARY background queue
if let error = error {
log(error)
return
}
//CNContactStore - Any CNContactStore functions should run here, and not inside `DispatchQueue.main`
guard let self = self else { return }
// Any UI updates or any code that interacts with `UI*` or constraints, must be done on main
DispatchQueue.main.async {
self.update_my_ui_here(permisionGranted) //Safely update UI from the main queue
}
}
Marking a function as #escaping just means that it may POTENTIALLY be called at a later time or stored as a variable somewhere. That's all it means. It does NOT mean that is will be ran on the same OR a different thread. It doesn't have any guarantees about threads and it doesn't have any guarantees about when it will run.
After all, DispatchQueue.main.async(completion: #escaping () -> Void) has an escaping parameter, and yet it always runs the completion on the exact same main thread. main is the only queue with such guarantee, regardless of whether the parameter is escaping or not.

How do I wait for an asynchronous call in Swift?

So I've recently come back to Swift & iOS after a hiatus and I've run into an issue with asynchronous execution. I'm using Giphy's iOS SDK to save myself a lot of work, but their documentation is pretty much nonexistent so I'm not sure what might be happening under the hood in their function that calls their API.
I'm calling my function containing the below code from the constructor of a static object (I don't think that's the problem as I've also tried calling it from a cellForItemAt method for a Collection View).
My issue is that my function is returning and execution continues before the API call is finished. I've tried utilizing DispatchQueue.main.async and removing Dispatch entirely, and DispatchGroups, to no avail. The one thing that worked was a semaphore, but I think I remember reading that it wasn't best practice?
Any tips would be great, I've been stuck on this for waaaaaay too long. Thanks so much in advance
GiphyCore.shared.gifByID(id) { (response, error) in
if let media = response?.data {
DispatchQueue.main.sync {
print(media)
ret = media
}
}
}
return ret
My issue is that my function is returning and execution continues before the API call is finished.
That's the whole point of asynchronous calls. A network call can take an arbitrary amount of time, so it kicks off the request in the background and tells you when it's finished.
Instead of returning a value from your code, take a callback parameter and call it when you know the Giphy call has finished. Or use a promise library. Or the delegate pattern.
The one thing that worked was a semaphore, but I think I remember reading that it wasn't best practice?
Don't do this. It will block your UI until the network call completes. Since you don't know how long that will take, your UI will be unresponsive for an unknown amount of time. Users will think your app has crashed on slow connections.
You could just add this inside a method and use a completion handler and therefore do you not need to wait for the response. You could do it like this:
func functionName(completion: #escaping (YOURDATATYPE) -> Void) {
GiphyCore.shared.gifByID(id) { (response, error) in
if let media = response?.data {
completion(media)
return
}
}
}
Call your method like this
functionName() { response in
DispatchQueue.main.async {
// UPDATE the UI here
}
}

Why we need the synchronous operation in ios

I want to know As we all know how asynchronous task are necessary for concurrency but Wanted to know why we need the synchronous tasks. while we can achieve the same with the normal usage of function.
Thanks & regards
Rohit
When you calls something synchronously, it means that 'the thread that initiated that operation will wait for the task to finish before
continuing'. Asynchronous means that it will not wait for finish the task.
synchronous calls stops your current action and returns when the call returned. with asynchronous calls you can continue.
synchronous is the opposite of asynchronous code, and therefore is ordinary code.
At the end, if asynchronous is totally out of scope then you will not emphasize the word synchronous.
It helps to synchronise threads, as the name suggests.
consider a typical usage of GCD async and sync (pseudo)
async background_thread {
//1 call webservice or other long task that would block the main thread
sync main_thread {
//2 update UI with results from 1
}
//3 do something else that relies on 2
}
now if 2 was in an async and you needed to do something at 3 that relies on the updates at 2 to have happened, then you are not guaranteed (and most likely wont) get the behaviour you are expecting. instead, you use a sync to make sure that the task is completed before continuing the execution in the background thread.
If you are asking now, why not just take out the sync/async around 2 so it executes in order anyway? the problem is, the UI must not be updated on a background thread otherwise the behaviour is undefined (which usually means the UI lags a lot). So in essence what happens is the background thread waits at 2's sync until the main thread gets round to executing that block, then it will continue with the rest of the execution on the background thread.
If you were dealing with a task that doesnt require the main thread (or some other thread) to execute properly, then yes you may as well take out the sync at 2.
This is just one example of how a sync is useful, there are others if you are doing advanced threading in your app.
Hope this helps
Typically it's because you want to do an operation on a specific different thread but you need the result of that operation. You cannot do the operation asynchronously because your code will proceed before the operation on the other thread completes.
Apple has a very nice example:
func asset() -> AVAsset? {
var theAsset : AVAsset!
self.assetQueue.sync {
theAsset = self.getAssetInternal().copy() as! AVAsset
}
return theAsset
}
Any thread might call the asset method; but to avoid problems with shared data, we require that only functions that are executed from a particular queue (self.assetQueue) may touch an AVAsset, so when we call getAssetInternal we do it on self.assetQueue. But we also need the result returned by our call to getAssetInternal; hence the call to sync rather than async.

Using while(true) statement a valid approach in iOS programming?

In objective C,
I am making my program to wait using while loop
doInitialize()
{
dispach_group_t loadDataGroup=dispatch_group_create();
dispatch_group_async(loadDataGroup,...get_global_queue(..),0),^{
renewauth();
}
dispatch_group_notify(loadDataGroup,...get_global_queue(..),0),^{
//Do other tasks once renew session has completed...
}
}
renewauth()
{
RenewAuthTokenInProgress=true;
startRenewThread();
**while (RenewAuthTokenInProgress);**
}
In turn startRenewThread() function also performs dispatch_async operation inside. So I have to make renewAuth() wait.
And async task in startRenewThread will update the bool variable once renewal is successful.
Is there any better approach of doing it other than dispatch_groups?
And is it good to make other threads wait with while (true) statement?
Manoj Kumar,
using a while loop to wait till the boolean variable change is not the correct approach to solve the problem. Here are few of the issues with this method
Your CPU is un-necessarily burdened with checking the variable regularly.
This will clearly show that developer isn't much equipted with basic skills of coding and features available with language.
If for any reason your variable will never change then your CPU will never stop checking the value of bool in while loop and blocks the execution of further code on the same thread.
Here are few of the correct approach :
Blocks or closures : Make use of blocks to execute the code asynchronously when the RenewAuthToken is done.
Delegates : if blocks are harder to understand, Make use of delegates and trigger the delegate when you are done with RenewAuthToken.
Notifications : Add observer for notifications in classes which needs to respond when RenewAuthToken is done and throw notification from the asynctask and let the class to catch it execute the code.
Locks : If it is necessary to block the execution of the thread till the response comes use locks to control the thread execution rather than using while loop
EDIT
As pointed out by fogmeister in comments
If you block the main thread for too long with a while(true) loop then
the app will actually be terminated by the iOS Watchdog as it will
assume it has crashed
Please have a look at the link : understand iOS watchdog termination reasons provided by fogmeister
Hope it helps.
I believe what you need it's a semaphore like:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
__block BOOL done = FALSE;
while (true) {
[self someCompletionMethod completion:^(BOOL success) {
if(success) { // Stop condition
done = TRUE;
}
// do something
dispatch_semaphore_signal(sem); // This will let a new iteration
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
if(done) {
dispatch_async(dispatch_get_main_queue(), ^{
// Dispatch to main
NSLog(#"Done!");
break;
});
}
}
});
Semaphores are an old-school threading concept introduced to the world by the ever-so-humble Edsger W. Dijkstra. Semaphores are a complex topic because they build upon the intricacies of operating system functions.
You can see a tutorial here about semaphore and check it out more links: https://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2
I hope this can help you.
What you do is absolutely lethal. It blocks the running thread (presumably the main thread) so the UI is frozen. It runs one core at 100% load for no reason whatsoever which empties the battery rapidly and heats up the phone. This will get you some very, very unhappy customers or very, very happy ex-customers.
Anything like this has to run in the background: startRenewThread should trigger some action that sets RenewAuthTokenInProgress = NO and sets whether there is a new token or not, and then triggers further action.
This is an absolutely essential programming pattern on iOS (and Android as far as I know).

ios: waiting for method to finish executing before continuing

I am new to IOS development and am currently facing a problem.
When method A is called, it calls method B and then it wait for delegate connectionDidFinish which connectionDidFinish will execute MethodC.
My question is how do I ensure that methodA to methodC has finished executing before executing NSLog?
I found that a way to solve this problem is to use notification center. Send notification to me after finishing executing methodC. I don't think this is a good solution. Is there another way to do this?
Example:
[a methodA];
NSLog(#"FINISH");
If any of those methods perform actions asynchronously, you can't. You'll have to look into a different way of doing this. I personally try to use completion blocks when ever I can, although it's perfectly fine to do this other ways, like with delegate methods. Here's a basic example using a completion block.
- (void)someMethod
{
[self methodAWithCompletion:^(BOOL success) {
// check if thing worked.
}];
}
- (void)methodAWithCompletion:(void (^) (BOOL success))completion
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, kNilOptions), ^{
// go do something asynchronous...
dispatch_async(dispatch_get_main_queue(), ^{
completion(ifThingWorked)
});
});
}
In the code you posted, methodA must finish executing before the log statement will execute.
However, if methodA starts an asynchronous process that takes a while to finish and returns before it is finished, then you need to do something different. Usually you don't want to freeze the user interface while you are waiting, so you set up a delegate, pass in a completion block, or wait for an "ok, I'm done" notification.
All those are very valid, good ways to solve the problem of waiting for asynchronous tasks to finish running.
Newer APIs are starting to use completion blocks. Examples are:
presentViewController:animated:completion:, which takes a completion
block that gets called once the new view controller is fully
on-screen and "ready for business.
animateWithDuration:animations:completion:, which takes a completion
block that gets executed once the animation is finished, and
sendAsynchronousRequest:queue:completionHandler:, which starts an
asynchronous URL request (usually an HTTP GET or PUT request) and
provides a completion block that gets called once the request has
been completed (or fails)

Resources