Can't call View Controller method from app delegate - ios

I'm trying to build the sample app from facebook iOS SDK but I'm using storyboards so it's a little different.
I'm doing this check in my AppDelegate.m application didFinishLaunchingWithOptions:
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
// To-do, show logged in view
} else {
// No, display the login page.
[self showLoginView];
}
return YES;
I've created a segue from my main ViewController to a navigation controller. The segue works fine if I trigger it using a button in my ViewController view, but I can't call that method from my AppDelegate.
The name of the method(that performs the segue) is -displayLoginView but I canĀ“t find a way to point to the particular instance of my ViewController that is active at launch.
Any ideas?

Your UIApplicationDelegate is not a view controller so it cannot initiate any segues.
You probably want to call self.window.rootViewController to get the viewcontroller in question but it might be easier to put that code in your viewController's viewDidAppear or viewWillAppear method instead of the app delegate.

Related

Custom iOS UITabBarController Delegate Triggers viewDidLoad

Issue:
An UITabBarController delegate method calls viewDidLoad and negates/ignores the screen selection.
Background:
I am making a split-view controller for small iOS screens. So, far the screen looks something like this:
Custom Split-View Controller
For the Detail View (RS), I'm using a UITabBarController, with the TabBar removed. You can find the code for this here.
The user selects the buttons on left, and a delegate sends the button's tag id to the UITabBarController delegate method.
The delegate method looks like this:
// delegate method in subclass of UITabBarController
-(void) screenSelected:(int)screenNum
{
NSLog(#"delegate arrived: %d", screenNum);
self.selectedIndex = screenNum;
// code goes to viewDidLoad
}
With breakpoints in place, I determined that the screen does not actually change.
If this screenSelected method is instead called from the UITabBarController viewDidLoad method (when the app first opens), the method works fine and the selectedIndex is changed as expected.
I'm trying to figure out why the delegate is triggering viewDidLoad. Does the delegate reset the view?
Thanks
Yes, viewdidload will call every time because you are initializing tabs again. setSelectedIndex intialize tabbarcontroller evrytime from UITabbarcontroller class. You should not do that from uitabbarcontroller class. just initialize tabbarcontroller onece.
You should not use tabbarcontroller like this way. according to your requirement you not need to use tabbar just shows viewController on button click.
hope this will work.

Objective-C : Keep a View Controller active when dismissed?

In my chatting application, I have a ChatViewController.m that allows users to message with the QuickBlox framework.
When a user sends an image, a background upload begins and a UIProgressView displays the progress of the upload.
But what if the user backs out of that view during the upload, and returns in, say, 10 seconds while the upload is still happening. I want the UIProgressView to still be active and accurate based on that upload. But dismissing the ViewController doesn't allow me to do that.
Can someone suggest what I should be doing in this situation?
EDIT: This is how I present the ChatViewController.m, depending on the chat selected from the CollectionView:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.destinationViewController isKindOfClass:ChatViewController.class]){
ChatViewController *destinationViewController = (ChatViewController *)segue.destinationViewController;
if(self.createdDialog != nil){
destinationViewController.dialog = self.createdDialog;
self.createdDialog = nil;
}else{
QBChatDialog *dialog = [ChatService shared].dialogs[((UICollectionViewCell *)sender).tag];
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.dialog = dialog;
}
}
}
EDIT 2: I have implemented the ViewController as a singleton in my didSelectItemAtIndexPath. But now, the app presents only a black screen.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
QBChatDialog *dialog = [ChatService shared].dialogs[indexPath.row];
ChatViewController *chatView = [[ChatViewController alloc] init];
chatView.dialog = dialog;
[self presentViewController:chatView animated:YES completion:nil];
}
You should change the way you display your chat view controller. Don't use a segue.
Instead, set up your chat view controller as a singleton. Set up an IBAction or other code triggered by the user selecting an item in your collection view.
In that IBAction or didSelectItem code, fetch a reference to your singleton, configure it as needed, and present it modally yourself using presentViewController:animated:completion:
That way your view controller will preserve it's contents between views.
As the other poster said in a comment, you might pull the download logic out of your view controller and into a separate download manager class. It depends on whether you need the ability to do asynchronous downloads in places other than your chat view controller.
I'm assuming based on your question that you are creating the view controller each time that you are presenting it. Instead of re-allocating and creating a new view controller each time you present the messaging view, make only one view controller that you can call and present from any other view controller.
A couple possible ways to do this are:
Create a singleton that has the messaging view controller as a property
Add the messaging view controller as a property on your route view controller
Make the messaging view a singleton itself so only one gets created in the entire life of the application
Doing any of these will make sure that the view persists each time that it's dismissed.
If that still doesn't fix the problem, you may be resetting the view in viewDidLoad or viewDidAppear which I don't think is actually what you want to do.

iOS presentViewController doesn't invoke viewDidLoad

I'm implementing my own 'back' button. Where onClick, the following code is executed in the ViewController (VC) being dismissed:
Dismiss current VC (VC#1)
Pop current VC (VC#1) off my custom navigationStack
Get the last VC (VC#2) from the navigationStack, and present it using
presentViewController
What happens is the back works visually works - i.e. current VC disappears, previous VC appears. However, the viewDidLoad method is not called. So the screen isn't updated with data updates from viewDidLoad.
[self dismissCurrentViewController:self completion:^{
[TWStatus dismiss];
FHBaseViewController *vcToDisplay = [[FHDataManager sharedInstance] popNavigationStack];
[vcToDisplay.homeVC presentViewController:vcToDisplay animated:NO completion: ^{ }];
}];
Questions:
I was under the impression that viewDidLoad always gets called when presentViuewController is used??
I 'build' the screen using a method called ONLY from viewDidLoad in VC#2. How is iOS displaying the screen without coming into viewDidLoad?
btw, I'm not using storyboards. Any help is appreciated!
My guess is that viewWillAppear is being called but viewDidLoad is not, at least not when you expect it is. viewDidLoad should be called once, but depending on how you're managing the view controllers, viewDidLoad may not be triggered every time your view appears (which happens after loading).
The completion handler is called after the viewDidAppear: method is called on the presented view controller. from presentViewController doc
so put this in your code with a breakpoint on the call to super and verify it is getting called when this transition occurs.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
edit: since you verified that viewWillAppear is getting called, then I would say that it's coming down to how you are managing the view controller life cycle. Even with a standard UINavigationController, viewDidLoad is not called when a view is shown as a result of popping items on the navigation stack. I would move your logic to viewWillAppear if you are dead set on not using UINavigationController
When I make a back button pragmatically I use:
[self.navigationController popViewControllerAnimated:YES];
This will invoke the viewDidLoad method. Use that instead of your current code.

Perform segue on viewcontroller's startup

I have a login screen and what I want to do is to detect whether the user is already logged in and eventually popup a modal.
I created a custom segue that shown the modal with no animation.
#implementation NonAnimatedSegue
-(void) perform {
[self.sourceViewController presentModalViewController:self.destinationViewController animated:NO];
}
The thing is that calling this segue from viewDidLoad or viewWillAppear takes no effect. If I call it from viewDidAppear, the login screen flicks for a while before the modal opens.
Any idea how to solve this?
The way I got around this problem was to check in the application finished launching and set the root view controller as needed. Like so:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
/*stuff*/
/*get the view controller from storyboard/nib*/
[self.window setRootViewController:CorrectViewController];
}
It wouldn't show a modal view but just show the login on launch.

Suggestions to manage Login/Logout transitions

I have an application that can be used only if the user is authenticated. In particular, I created two different UIViewController. The first is called LoginViewController while the second is called HomeViewController. In applicationDidFinishLaunching: method, LoginViewController is created and then added to rootViewController property like this:
LoginViewController* loginCtr = ... // alloc and initiWithNibName...
self.window.rootViewController = loginCTr;
[loginCtr release];
Whitin LoginViewController I created a method that performs the login. When the user has been authenticated, I perform a method, called performLogin.
- (void)performLogin
{
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate switchView];
}
where swicthView method has been implemented inside the Application delegate class.
- (void)switchView
{
if(VIEW_TYPE == kLogin) // Display Login
{
// create a new LoginViewController and assign it to rootViewController
}
else // Display Home
{
// create a new HomeViewController and assign it to rootViewController
}
}
Given the previous code, is it possible to implement a more elegant mechanism to manage login / logout transition or does this type of implementation could be considered a valuable solution?
Thank you in advance.
Another option, I will set the HomeViewController as the rootViewController. In the viewDidLoad or viewDidAppear method (before I display any information on the HomeViewController), I will check whether the user has login credential. If not, I will display the loginViewController as a modal to request user login credential. In this case, I don't need to change the rootViewController of the window.
Starting from iOS 5 I started to manage login/logout transitions using the new containment API for UIViewControllers.
Implementing a Container View Controller
If iOS 5 is not available I would see a similar approach writing-high-quality-view-controller.
Hope that helps.

Resources