I'm a web developer tasked with building a basic iOS app for internal use. A number of functions in the app require authentication, and I've successfully built the login view/controller which calls a webservice, authenticates the user etc etc.
I can currently load the "LoginView" with a button click and after authenticating the user, dismiss the view from the view stack returning to the original view, now with established credentials. None of that is my issue.
Now I'm looking for the equivalent of doing a 'redirect' as I would in developing for the web. I need to load the LoginView from any function in my application where authentication is required, and on success, load some other view which would be "passed in" (on the web I would provide a redirect Url) to the LoginView. I feel like this is a simple thing, and must be done all the time, but can not find a good example or explanation of this. I'm certain my obvious newbiness is preventing me from even searching for the right terms.
Hopefully someone can decipher my poor, yet best attempt at explaining what I am looking for. Thank you in advance.
One pattern I have used is to pass a success handler block to the authentication view controller.
This has an advantage over the delegate system in that you can set it to perform any action, including moving to any view controller, without modifying each and every view controller to match the delegate protocol.
For instance, one thing I might want to do after successfully authenticating is to pop the view controller stack back to the main menu, or to continue to process a web service request that was already underway. The delegate system doesn't really allow for this, while blocks are more flexible as you can pass in any code you want.
This is the perfect job for delegates. In your login view controller interface (please note I'm writing this off the top of my head so there might be a few typos/missing semi-colons etc:
#protocol LoginControlDelegate <NSObject>
- (void)loginDidSucceed:(BOOL)success
#end
#interface ...
{
...
}
#property (nonatomic, assign) id<LoginControlDelegate> delegate;
#end
And then in your implementation file, once you have established that the webservice has responded to the login request, you can call:
if (self.delegate != nil)
{self.delegate loginDidSucceed:<YES/NO depending on the webservice response>]
So every time you create an instance of your login view controller, you can assign the "parent" view controller as the delegate and then conform to the <LoginControlDelegate> by implementing the method loginDidSucceed:
LoginViewController *vc = [[LoginViewController alloc] init....];
vc.delegate = self;
[self presentModalViewController:vc animated:YES];
[vc release];
And the loginDidSucceed method:
- (void)loginDidSucceed:(BOOL)success
{
if (success)
// Logged in successfully, push the appropriate view
} else {
// Login failed...
}
Developing for mobile is not the same as developing for the web. In general, apps will have a user login once and then never gain (or at least only when the app is opened, like Mint). If possible, consider changing the design of the app to accommodate mobile design conventions rather than borrowing from the web world. It's a different ball game and your users will appreciate it.
That said, I might attack this by building a custom UIView based off of apple's design for the UIAlertView. Give it a delegate protocol and when it returns with an authenticated user, the controller from which you called it can make the appropriate changes to itself using the delegate method.
What #Rog posted will all work fine as stated. I would only suggest that if you already have something akin to a WebRequestManager which dispatches the calls to your web service (creates the connection, manages errors, returns the data) to not worry about delegation of the login, but instead manage that login view in the manager, isolating all of your views from needing this sort of delegate (which becomes a maintenance headache).
This way your views just initiate the request thru the manager and just expect the data to be returned, regardless if a login is required. Notably, the app doesn't even need to (or may not) know what requests require a login, only discovering that as a response from the server. At which point you can launch the login view, get the credentials, and then restart the request with the valid credentials.
And at that point I would keep the credentials, at least for the current run session, so any future requests do not require another login.
Related
This applies to iOS programming specifically using QuickBlox's API for video calls.
Obviously you don't want users to receive video calls in just one view controller in the app, so you need to make users be able to receive calls anywhere in the app.
Before I spend hours figuring out how to do this, I'm wondering how to tackle this issue.
I'm guessing that it has something to do with the - (void) chatDidReceiveCallRequestFromUser function in the AppDelegate, and having an alert view pop up over any view in the apps.
How do you make QuickBlox video calls receivable while being in any view of the app?
In my application I created singleton class which conform QBChatDelegate protocol. In this class I implemented all needed methods and created #property with my viewController in which I realized all video chat code. So when call request coming I make all needed operation and call viewController's QBChatDelegate methods and if I need - present view controller by using TabBarController or in any other way.
In my app there is authentication required, so when you launch one of the tabs on tab bar, "class A" checks are there credentials saved if not, "class B" modal view controller with fields to login launches.
So my question is : in which method in class A (loadView, viewWillAppear or maybe in another one) should be implemented checking if there are credentials saved and other stuff described above.
And my additional second question is:
is pushing modalviewcontroller correct way to show login screen, or i should do that differently?
Thank you for reply guys.
OH ! One More Thinh
And one more thing. I've done implementing LoginView by adding delegate and presenting ModalVC (Harkonian the Piquant's method). But in my tab bar app i have got very confusing problem. I mean when user taps login button (assume that everything was correct and he's able to secured data) how PROPERLY switch to tab where is secured info. I mean previously selected tab.
i did it by adding in
-(IBAction) login {
//some code
self.tabBarController.selectedIndex =1;
And it seem to work good but is it correct ?
I have a very similar use case in my app -- it requires a passcode to authenticate. After a lot of testing and tweaking I found the following design to be the best approach:
Don't use class A to launch your credentials VC -- use the app delegate instead.
For security purposes, typically you'll want the credentials VC to show before the user can view the underlying view. It's much easier to handle this in the app delegate than in a VC. In addition, you need to consider what happens when your app is backgrounded -- a screen shot is taken of the current state of the app. If you are using viewController A to show the credentials view, when the app relaunches the user will be able to see whatever sensitive information was visible on app close until the app finishes launching and VC A presents the credentials VC.
Don't insert your credentials view into an existing ViewController -- use a new UIWindow instead.
You don't ever want any other view to be able to sit on top of your credentials view. Ever. Even views that would normally always be on top, like UIAlertView. The easiest way to achieve this is to have a special UIWindow just for your credentials view. Show this window and hide the primary app window whenever you need to display the credentials view.
How does this approach look in practice?
If you are at all interested in how well this design works, you can check out the passcode feature in Audiotorium Notes for iPad. I spent a lot of time with this design to make sure it was as secure as possible.
If you have any specific implementation quests feel free to ask and I'll try to answer them.
Could anyone tell me when we use the AppDelegate.m and AppDelegate.h during iPhone programming? I have used only the ViewController.m and ViewController.h for basic learning. I just want to know when and why AppDelegate is used.
Both define classes, but the classes are used for different things. ViewController.h/m define a view controller class that manages a hierarchy of views -- basically, one screen of an application. You might have multiple screens that each have their own view controller.
AppDelegate.h/m define a class that manages the application overall. The app will create one instance of that class and send that object messages that let the delegate influence the app's behavior at well-defined times. For example, -application:didFinishLaunchingWithOptions: is sent when the app has finished launching and is ready to do something interesting. Take a look at the UIApplicationDelegate reference page for a list of messages that the app delegate can implement to modify the behavior of the application.
I would like to add the following to #Caleb's answer.
If care is not taken, the AppDelegate could easily become one of the most accessed objects in the application. I usually refrain from calling methods in the AppDelegate from any of my ViewControllers. Unless, something needs to be reported to the AppDelegate that would influence the behaviour of the whole application.
I keep my AppDelegate for the following:
initialization: whatever needs to be done on the very first launch (after an install or an update)
data migration from version to version (e.g. if you use CoreData and migrations)
configuration of objects linked via IBOutlets from MainWindow.xib
determining the initial orientation to launch in
saving uncommitted data / state prior to the application being terminated or entering background mode
registering for the Apple Push Notification Service and sending the device token to our server
opening one of the supported application URLs (e.g. maps://)
For other use case scenarios and a more thourough description of the AppDelegate, see the iOS Application Programming Guide.
The view-controller. h/m is responsible of controlling the connection between your model and your view (more on MVC here).
AppDelegate. h/m is responsible for the life-cycle of your application. What to do when the user press the home button and exit your app, what to do when the app enter background. Things like this.
My app has a main login/password screen where user enters credentials and submits the info to a web service. Once authenticated, web-service will also tell me what kind of user is loggin in. So user can be type "A", "B" or "C".
Now depending on kind of user I need to load different views (having functionalities) only that particular type of user can use. So I have home screens for "A-HOME" "B-HOME" and "C-HOME" which will then be a Nav Controller or a Tab Controller.
So basically if A logged in - next view loaded should be "A-HOME"
My layman's guess is to load view programmatically. However, I prefer to not do it as you can forget few steps and leak or screw the app. Is there any common design pattern that is used in such cases. The scenario seems pretty regular case to me. Are there any apps with sample code on apple's developer website that does the same thing?
Please give your suggestions.
Thanks.
If the views are "sufficient distinct" use different view controllers for each one, and load the approriate one. You can load the whole thing from a nib if you want, just wire this up in code, after your login procedure, i.e.
-(void) doLogin:(LoginType)loginType
{
if (loginType == LoginTypeA)
{
TypeAViewController *viewController = .... // Load from i.e. "TypeAViewController.nib"
// Add its view
}
}
I have setup and successfully logged in via xAuth using an extended class of MGTwitterEngine, my question is if I want to pass this to another view controller, how can I change the delegate class, as it is some sort of weak reference
#interface MGTwitterEngine : NSObject <MGTwitterParserDelegate> {
__weak NSObject <MGTwitterEngineDelegate> *_delegate;
Am I best wrap this up into a singleton class and pass around that way, seems overkill to login in each time, or have I missed a painstakingly obvious way of sharing this object around
At the moment I have added a setDelegate method to the MGTwitterEngine but feel as though I am fighting the framework unnecessarily
If you're sharing the engine across multiple objects then you would want to have some other object/singleton wrap the engine and act as its sole delegate. If you've done database programming then think of it like a database connection -- you probably wouldn't have each view controller create its own database connection. Instead you'd create some sort of data manager object that is shared by the views and possibly abstracts away some of the DB internals.
If different view controllers handle different tasks -- like login, looking up users, querying messages, etc. then the delegate methods in your wrapper should be able to pass the responses along to the appropriate view controller.
If you have different view controllers calling the same methods (and if so, why?), you could still route responses back to the corresponding view controllers. As the MGTwitterEngine docs say, "Each Twitter API method returns an NSString which is a unique identifier for that connection." You would just need to pass an object (your view controller) or a block as an extra parameter to each of your wrapped methods. You can cache the twitter id string and this object/block in a mutable dictionary when your wrapper sends the response, then look up the connection id in the cache when it's time to handle the response.
actually, you can.
The delegate, is nothing but a variable in the MGTwitterEngine. Just add a instance of it in the next view controller adding the proper header and inplementation calls.
after instatiating the new view controller set:
nextViewController._mgTwitterEngine = self.mgTwitterEngine;
nextViewController.mgTwitterEngine.delegate=nextViewController;
then call the nextViewController.
Do not forget to set the delegate back to the original view controller when you return to it (either on viewDidAppear or viewWillAppear)
Hope that helps...
Best Of luck!
Use NSNotifications in the delegate.
Make the view controller where you wish the delegate to be add an observer. Have the delegate method for MGTwitterEngine post the notification.