Get the userID synchronously or asynchronously (iOS)? - ios

I have a requirement. Some of the screens are not account based. So the users can view them without login. But when they click the "favorite" button. The user will be asked to login in login page. After login, if the user does login, the previous favorite action should be continued. And if the user did not login, the previous action should be stopped.
So I think this an asynchronously login case. The usual synchronous way can not handle this. So my idea is to pass in a login completion block. Like this:
typedef void (^LoginComplete)(NSString *userID);
- (void)getUserIDWithCompletion:(LoginComplete)loginComplete;
Am I right? Or how do u guys usually handle this kind of case?

Usually, all networking is done asynchronously from the developers perspective, aka, completion closures. This is however a synchronous operation for the user, since they are blocked from viewing the rest of the content until the operation continues.
Either way, your approach is good.

Related

Rewarded Interstitials - How to react to a user cancelling an Ad? (AdMob Google Ads, iOS)

I'm implementing GADRewardedInterstitialAd into a game.
https://developers.google.com/admob/ios/api/reference/Classes/GADRewardedInterstitialAd
I'm using presentFromRootViewController:userDidEarnRewardHandler to react to the user finishing the ad.
Now I'd also like to know how to react to the user cancelling the ad.
If I continue directly after calling presentFromRootViewController, the callback handler will not have been called yet, because the systems works asynchonous, as is to be expected. So any game animations (e.g. screen fade, dialog close) will have to be stalled.
If I rely only on the handler, I won't get a callback when the ad was cancelled.
My solution would be to build in a timer that waits 30+1s to give the handler a chance to get called (hopefully on the next main thread dispatch cycle), and then react to it not being called yet (assuming a cancellation by the user).
I really hate that plan.
It's not deterministic.
It doesn't use callbacks/delegates/handlers (which are great exactly for this kind of thing)
I have to write the timer code and keep a boolean flag somewhere... it's messy.
It adds an arbitrary delay to the user experience (30+1s) when they close the ad!!
Am I thinking the wrong way about this or is this just the way Google has made it and I'll have to live with it?
Edit: please note that I'm talking about the new GADRewardedInterstitialAd API, not GADRewardedAd.
I've figured it out; it works by setting GADFullScreenContentDelegate fullScreenContentDelegate and implementing adDidDismissFullScreenContent.
In there you can check if this particular instance of GADRewardedInterstitialAd did not get a reward yet (as notified by userDidEarnRewardHandler...)
This all hinges on the assertion that adDidDismissFullScreenContent gets called AFTER the userDidEarnRewardHandler, else I will already have assumed there was no reward. Let's hope that is always the case.
https://developers.google.com/ad-manager/mobile-ads-sdk/ios/api/reference/Protocols/GADFullScreenContentDelegate

Automatically log out user when they leave the iOS app

I have an in-house app which is used by staff but the chances are the device it is used on could become consumer facing. With that in mind I want to ensure that should the staff forget to logout when they switch apps or just reopen the app that I have a command in there to effectively log them out.
After researching I think the best way for me would be to use:
optional func applicationWillEnterForeground(_ application: UIApplication)
and then force the app to go to the login page or the reverse so that when app enters background it forces the app to the logout URL.
Which do you think would be best and how can I use that command to then add in the chosen URL as described above?
So, while I agree with #Rakesha-Shastri in that ""app enters background it forces the app to the logout URL" This seems like bad UX. The first one where you display the login page on returning from background seems fine. It is important that the user is able to resume his work where he left off after logging in again," there does need to be a way, in-case a user is gone too long, that the credentials have passed. It seems in your case, that every time the user LEAVES or CLOSES the app, you want this to be unauthenticated. What if the user gets a phone call? Should it do that? You may want to use Timer, of say some period of time, 2-5 minutes maybe.
Any who, what you can do is force the user to have to RESTART the app, by either presenting a controller that has NO CAPABILITY of going anywhere, therefore forcing a restart, or providing a button that sends them to a login screen you have implemented.
Note:
I would definitely indicate to the user, "due to purposes of security, each time you exit the app, it requires an authentication to re-access. Please log back in". Then provide a button to the login screen.
As you did not provide code, and I'm not going to do this for you, a direction to take this would be to utilize optional func applicationWillEnterForeground(_ application: UIApplication) alongside with getting the current UIViewController. I would google how to do that. Then from there, you can create a new UIViewController that presents this button back to the login screen.

Swift logout process

I am building an app in swift which interacts with an API. There a two ways a user can be logged out, by clicking a logout button or by receiving a 401 response when calling the API.
I plan on using NSNotificationCenter in my API class to broadcast an event when an unsuccessfully response is received so generic handling of things like 401, 400, 500 can be handled in one place outside of the API class.
To prevent duplicating the logic involved with logging out in multiple places I have created a Class which will clear any existing tokens and present the login view controller. This class can then be used when the logout button is clicked in the view controller or when a 401 response is picked up by the response observer.
My problem is, since the logic is not inside a view controller I am unsure how I can present the login view controller as I do not have access to the method self.presentViewController
You're going to need to pass that responsibility to a view controller.
How I've handled this in the past is using a key-value observer (or RAC) to monitor the active token. When that token goes away, I swap out the root controller.
Where you do this depends on how you've structured things. The app delegate is a reasonable spot.

How to handle rapid like/unlike at updating UI ios

I have an app. In this app, a user can like/unlike something. If the user tap the button like, it would change text to unlike, vice versa.
To make the like/unlike event run seamlessly to user, i change the text first, and then make request to my API, saying that the user like/unlike this. The API decides whether the action is liking or unliking depends on value at database. The API then returns a message stating the action made ("liked"/"unliked"). The app receives it, and then update the UI according to the result, in case the action intended by user fails.
If all runs smoothly, the user won't detect the changes made by API result.
This is the flow of liking something
user like -> button text changes to "unlike"
-> app make a request -> request is queued to operation queue
-> request run -> API decides whether that something is liked/unliked by the user
-> API returns action (in this case, "liked") -> app updates button text ("unlike")
Now my question are:
How do I handle rapid button tap by user?
How do I handle failed requests (internet disconnected, or no signal) while handling the problem no. 1?
nb: I don't want to disable the button (the app has to run seamlessly. Facebook app don't do it either, i just checked). Oh, and I use AFHTTPRequestOperationManager and set its maxConcurrentOperationCount to 1.
I resolved my problem using this answer
with a bit modification. The first time user click the button, I set a request flag to false, so that even if the user click the button many times, request won't be made before the first request is done.

move to another tab while async request being sent ios

I have an app with tabbarcontroller. As of now when an async request is being sent on one of the tabs, the user cannot move to another tab. I want my app to function such that when the request is being sent, user is able to move to other tabs and the async request stays is progress still timeout. How can I achieve this?
If you are sending an async request from a view controller, the user will be able to move to another tab. That's the default behaviour. So unless you have built in logic to change that behaviour (i.e. waiting for an async until it has finished). If that's the case, then you should obviously remove that logic.
If that's not the case i suspect you are currently sending a synchronous request (and not an async request as stated in the question). Sending a synchronous request from a view controller would result in the behaviour as described in your issue. So if that's the case, you should rewrite that and make it an async request.
And if you are still unsure, just post your code!

Resources