Swift logout process - ios

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.

Related

Best practice for initial loading in iOS app

Just starting out iOS development.
When starting my app, I'd like it to check if the user has a known account and if they do, "login" by acquiring an access token and then display the main / first view. If they don't have an account or if login fails, they should be redirected to a login / registration screen.
Initially I thought I'd hide this process (check for account + call to get access token) behind a splash screen, but apparently this is against Apples guidelines. Is there a common / recommended way to do this on iOS?
By referencing to application:didFinishLaunchingWithOptions: you can read that this method is good for initializing.
Use this method (and the corresponding
application:willFinishLaunchingWithOptions: method) to complete your
app’s initialization and make any final tweaks. This method is called
after state restoration has occurred but before your app’s window and
other UI have been presented. At some point after this method returns,
the system calls another of your app delegate’s methods to move the
app to the active (foreground) state or the background state. This
method represents your last chance to process any keys in the
launchOptions dictionary. If you did not evaluate the keys in your
application:willFinishLaunchingWithOptions: method, you should look at
them in this method and provide an appropriate response. Objects that
are not the app delegate can access the same launchOptions dictionary
values by observing the notification named
UIApplicationDidFinishLaunchingNotification and accessing the
notification’s userInfo dictionary. That notification is sent
shortly after this method returns.
There may be several ways. But using singleton for token and launching your app is one of the best ways. As you might not need to use that launcher class again. Just for checking user have token and if yes then show main view otherwise login view.
Hope it helps you !!

Handle Push Notification infos before login

My question is about a best practice to use to handle a push notification in a defined scenario.
My app has 3 ViewControllers:
Login: User authenticates to start using the app
TableView: A simple table view with a contacts like appearance
DetailView: A simple viewController containing details from selected row of TableView
I receive a remote notification with some info in the payload (let's say a phone number for example). I need to use that info on DetailView but at receiving time I'm not logged in (app not running), so I press notification and it opens my app (Login) but I need to keep somewhere notification payload (or an object created from it) and pass it to DetailView.
So question is:
what is best practice to pass data from the notification to an inner ViewController, if the notification is received before user is logged in?
My only solution right now is: evaluate an object in didReceiveRemoteNotification, keep it in AppDelegate and access it everytime user's login to open DetailView if object is present (and clean it after using of course) but I don't think it is a good one.
Any suggestion?
What you said is mostly right because the only place you will receive a notification in is your app delegate.
but keeping a global object with the data is not the right thing to do, specially if you would like to respect design pattern and isolation between the classes.
as I understand from you the data you will get in the payload will be used in other screens in the app, so what I think the best is :
save it in User defaults or data base and access it when ever you need, and keep overriding it every time you a new notification.
if you would like to use the data base option I would like to recommend you to use Realm as it way much easier than core data and didn't take much time implementing it.
Hint: if this is the only kind of data you gonna save in the app then use User defaults.
hope this answer your question
try to save this data in User Defaults then, when you are logged in, get the data from User Defaults. Second option - set some variable and initialize it whit this data, and after that pass the data to new ViewController/

Swift + Parse - How to force app to refresh after logout

How do I refresh all my UIViews to show the data for the new user.
(Scenario: User1 logs out and User2 logs in without closing the app.)
Right now I have a Logout button on my userVC. Upon pressing it the current user is logged out and the login view is presented. If a new user logs in the view dismisses and shows the userVC again. The userVC, because it was never refreshed keeps showing the data of the old user. (This is also true for all other VCs in this tabbed application.)
How do I get the views to reload their data? (Or redraw?)
There are several ways you can achieve this, but the first thing you should do is add an ACL to your userdata so that User2 does not have access to User1's data! Security is something you must take seriously when handling data for multiple users.
More info: https://parse.com/docs/ios/guide#security
If you log in a user, you could call a method for fetching the data. How is the data for your view retrieved? Whatever code you're using to fetch user data for the view, make sure this code is in its own function so that you can call it again upon login.
Update
Call the getInfo() in viewWillAppear() or viewDidAppear() instead. If that is too often, you can set a flag when a user logs in so that getInfo() is called only if it's a newly logged in user.

Get current location twice

I've got an iOS app in which it starts differently if the user has been logged in through Facebook account or not.
So the application flow is as follows:
1- I call app delegate, which creates a navigationController and shows it.
2- In the root view controller, it checks if the user is logged in or not. By default (for example during the first boot) it loads view controllers as not logged in, showing only contents for not logged user. if the user is logged with Facebook account it sends requests to a server and shows the contents for logged in user. The requests start with didupdatelocation delegated method, from which it gets the current location.
3- there are many places in which the app asks if you want to log in. If the user gets correct login, it creates a new navigation controller, as in app delegate, and displays it. The problem is that in this way it doesn't call the method didupdatelocation, and so it doesn't get current location and doesn't make any request to server.
How can you suggest me to solve the problem?
Your design should not rely on didUpdateLocation to be called. This method is called at non-predictable intervals by the system.
One way to force it to call however, is to stop the locationManager and start it again.
startUpdatingLocation
stopUpdatingLocation
However, I recommend you consult the CLLocationManager Class Reference and re-design your login check accordingly.

MFMessageComposeViewController feedback of editing of To: field

I have an application which is using standard SMS functionality provided by MFMessageComposeViewController. I have an array of recipients visible in TO: field of the SMS dialog. The user has a possibility to remove or add new recipients. This is ok but my application need to know when the user edit this TO: field, because I have to do some other actions when the receivers field is changed by the user.
Is there any way to know if the recipients field are edited or no, after Cancel button click or Send button click?
I have method callback in my code:
-(void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
This method has controller.recipients but this array contains the recipients before calling of the message controller view.
This is not possible as of iOS 7. The only information provided by the delegate method is whether the user chose to cancel the message, send the message, or the sending is failed.
From the documentation:
This method is called when the user taps one of the buttons to dismiss
the message composition interface. Your implementation of this method
should dismiss the view controller and perform any additional actions
needed to process the sending of the message. The result parameter
lets you know whether the user chose to cancel or send the message or
whether sending the message failed.
To add to Enrico's answer, not only is this not possible from public API standpoint, it is also not possible by trickery, as since iOS6, the mail and message compose view controllers are rendered by different processes than your own, and their view hierarchies are completely hidden to your application. Indeed, if you were to inspect the view hierarchy of the message compose view controller's view, you would notice that none of what is on screen is actually there in the hierarchy. During the remote view's loading, the settings given to the message compose view controller are passed to the remote view controller. However, this is a one-way operation, and the properties are not updated (or read from) after the remote view is loaded.
This is to protect the user's privacy. This is a fundamental design of iOS. You should accept this, and design your application accordingly.

Resources