I have a Navigation based view controller and in the view controller i have hidden the top navigation bar and use a custom UIView as the navigation bar.
The UIView bar has a back button and I use Delegate methods(I have declared a protocol) to communicate to the view controller when the back button is preesed.
I use delegate in my CustomNavigation Bar
id delegate;
and In the main View Controller when i allocate the navigation bar i set the delegate
topBar = [[TopNavigationBar alloc] initWithFrame:CGRectMake(0, 0, 480, 40)];
topBar.lblTitle.text = #"Shop";
topBar.delegate = self;
I release this Bar in the ViewControllers dealloc.
Now when i press the back button I use delegate method to call a popViewController in the main ViewController.
//in Custom Bar
-(void)ButtonPressed {
[delegate TopNavigationBarBackButtonPressed];
}
//In View COntroller
-(void)TopNavigationBarBackButtonPressed {
[self.navigationController popViewControllerAnimated:YES];
}
Now the ViewController is poped and the control goes to the previous viewController but the dealloc is not fired in both the ViewController and the UIView
What am i doing wrong?
OK! Finally understood what the problem was.
Yes it was the delegate. So in my "back button pressed" method, I need to set the delegate to NIL.
-(void)TopNavigationBarBackButtonPressed {
topBar.delegate = nil;
[self.navigationController popViewControllerAnimated:YES];
}
And voila, all the dealloc get called. Damn you custom Protocol. 2 Days of my life i will never get back.
EDIT:
OK no need to set the delegate to nil.
I was having all the problems because in the property i was retaining the delegate.
#property(nonatomic, retain)id <ASNavigationDelegate>delegate;
This should be
#property(assign)id <ASNavigationDelegate> delegate;
Related
I'm trying to call the setSelectedIndex of my tabBarViewController via a delegate method in another viewController.
I've got the whole delegate part working, and the method call in my tabBarViewController correctly Logs to the console as being called.
The problem I'm having is, that it doesn't change my tabBar to the correct index. This is the method being called in my tabBarViewController.m
-(void)passNewSelectedIndex{
NSLog(#"delegate method called"); //This correctly outputs to the logs when the delegate method is called.
[self setSelectedIndex:1];
}
But it doesn't work.
Now, if I call [self setSelectedIndex:1]; in my viewDidLoad of the tabBarViewController.m, it works, and it correctly displays the tab at index:1. But that's obviously not where I want to set it. I think I might be missing something really obvious, but I just cant figure out what.
EDIT Posted the code for the concerned .h's and .m's
ScoreViewController.h:
#protocol ScoreViewControllerDelegate <NSObject>
- (void)passNewSelectedIndex;
#end
#interface CEWSoreViewController : UICollectionViewController{
id <ScoreViewControllerDelegate> scoreDelegate;
}
#property (nonatomic, weak) id<ScoreViewControllerDelegate> scoreDelegate;
#end
ScoreViewController.m:
- (void)passNewSelectedIndex{
CEWTabBarViewController *instanceOfTabBarCont = [[CEWTabBarViewController alloc] init];
self.scoreDelegate = instanceOfTabBarCont;
NSLog(#"I was called, hurray");
[instanceOfTabBarCont passNewSelectedIndex];
}
TabBarViewController.h
#import "CEWFinalScoreViewController.h"
#interface CEWTabBarViewController : UITabBarController <UITabBarControllerDelegate, ScoreViewControllerDelegate>{
}
#end
tabBarViewController.m:
-(void)passNewSelectedIndex{
NSLog(#"delegate method called");
NSLog(#"self.tabBar: %#", self.tabBar);
[self setSelectedIndex:1];
}
AppDelegate.m
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
CEWTabBarViewController *tabViewController = [[CEWTabBarViewController alloc] init];
self.window.rootViewController = tabViewController;
[self.window makeKeyAndVisible];
return YES;
Hope this makes a bit more sense now.
The problem is exactly as I expected:
- (void)passNewSelectedIndex{
CEWTabBarViewController *instanceOfTabBarCont = [[CEWTabBarViewController alloc] init];
self.scoreDelegate = instanceOfTabBarCont;
NSLog(#"I was called, hurray");
[instanceOfTabBarCont passNewSelectedIndex];
}
You're instantiating a new tab bar controller and calling the passNewSelectedIndex method on that. The problem is, that tab bar controller isn't the one controlling the tab bar your view controllers are in.
Try this:
[(CEWTabBarViewController*)self.tabBarController passNewSelectedIndex];
Depending on your navigational setup, you may need this instead:
[(CEWTabBarViewController*)self.view.window.rootViewController passNewSelectedIndex];
We would need a LOT more of your project to figure out exactly the best way to get a reference to the right Tab Bar Controller (I'm not recommending you do this), but the point is, we have to get a reference to the already instantiated tab bar controller that is already controlling our tab bar, not simply instantiate a new one and expect it to magically control our current tab bar.
The reason it works in viewDidLoad of your tab bar controller is because every instance of your tab bar controller calls viewDidLoad on its own. When moved into passNewSelectedIndex, this method is only called when someone else calls it.
selectedIndex is a property of UITabBarController
[self setSelectedIndex:1];
This would work only if the current controller is a subclass of UITabBarController.
For your scenario, you would have to pass the UITabBarController as a parameter
-(void)passNewSelectedIndex:(UITabBarController *)tabBar {
NSLog(#"delegate method called");
[tabBar setSelectedIndex:1];
}
If the view controller which declares your delegate method is itself a subclass of UITabBarController, then the [self setSelectedIndex:1];
would result in calling its own tabBar and not the one on which the delegate method is set.
Why UISearchBar does not get Focus and keyboard does not appear when UIViewController is pushed to navigation controller for the 2nd time? It seems as no element on the whole view has a focus.
MY USE CASE: I have 2 View Controllers: A and B. Transition is A->B. A, B are pushed to navigation controller.
When I show B for the first time focus is set to the searchbar and keyboard appears.OK.
Then I go back to the A. And again from A->B. Now for the second time there is no focus and keyboard does not appear. It is WRONG.
MY CODE: On the B UIViewController IBOutlet connection to the searchbar is created:
#property (weak, nonatomic) IBOutlet UISearchBar *mySearchBar;
Delegate of the mySearchBar is also set.
I set focus on the searchbar in B UIViewController in viewDidAppear method:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self performSelector:#selector(setCorrectFocus) withObject:NULL afterDelay:0.2];
}
-(void) setCorrectFocus {
[self.mySearchBar becomeFirstResponder];
}
Transitions between controllers are done manually in code like this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"myStoryboard" bundle:nil];
AController *a = [storyboard instantiateViewControllerWithIdentifier:#"A"];
[self.navigationController pushViewController:a animated:NO];
Try this
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self setCorrectFocus];
}
-(void)setCorrectFocus
{
[self.mySearchBar becomeFirstResponder];
}
After long searching I found Error. Somewhere in storyboard old connection for UISearchBar with the name mySearchbar was left. Another thing that I had to correct was that the method
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar;
returned NO, every time I went back to previous Controller. But it should return YES to be able to set focus on search bar next time.
Was strugling with the same - had a UISearchBar inside a UITextView's keyboard accessory and even after [self.searchBar becomeFirstResponder] was called, keyboard input was still received by the text view.
This is what finally helped:
[self.searchBar.window makeKeyAndVisible];
Apparently the keyboard accessory is part of a different UIWindow than the UITextField.
Note: To continue typing in the text view, you should then call something like [self.textView.window makeKeyAndVisible]; ...
Have you tried adding self.mySearchBar.delegate = self;
You should use strong in your property
#property (strong, nonatomic) IBOutlet UISearchBar *mySearchBar;
Always set strong in your property for IBOutlet. When you pop B from navigationController, mySearchBar has released, so you push back to B, [self.mySearchBar becomeFirstResponder] is not work.
There are two views in a tabbarviewcontroller. And the first tab has its view controller called myViewController which contain its IBOutlet. Pressing the button on the first view will present a view controller. After dismissing the view and back to the tab, the viewWillAppear of myViewController won't be called,but viewWillAppear of tabbarviewcontroller will. I need to reload the information on the first tab. If I use viewWillAppear in tabbarviewcontraller, how do I change the values of these property in myViewController? If anyone has idea ? Thanks.
If you want to call viewWillAppear of the viewController, you can add this to viewWillAppear of the TabBar
for (UIViewController *viewController in tabBarController.viewControllers)
{
[viewController viewWillAppear:YES]
}
I have a button in my popover controller. I want to use it to dismiss the popover, so I am trying to access a method (dismissPopover) of the presenting view controller (the "root" view controller).
Note: the method to dismiss the popover is already set up and working, in the root VC, which is the delegate. If I call it it will dismiss the popover. I just need to access the method from the popover.
To do this I set up a property in the AppDelegate, and get an instance of the rootVC like this: self.rootController = (ViewController*)self.window.rootViewController;. Then I imported the root VC class and the AppDelegate to the popover's view controller's class, as below. Seems to give me access to the rootVC, and the methods, but the results do not fire the method. Any idea what I am missing here?
#import "ViewController.h"
#import "AppDelegate.h"
Action connected to button:
- (IBAction)dismissPopover:(id)sender {
//Checking the button works, it does:
NSLog(#"dismissPopover, from popover");
//Trying to get an instance of the rootViewController, the "presenting view controller"
ViewController *rootVC = [(AppDelegate *)[[UIApplication sharedApplication] delegate] rootController];
//trying to access the method in the rootVC that dismisses the popover
[rootVC dismissPopover];
//Tried the following code, does nothing:
//[self dismissPopoverAnimated:YES];
}
NOTE: I ended up abandoning the use of a popover for this as it became a bit over complicated. I tried loading my view controller into a UIView (so I could load the contents of a nib to a pop-up view). That also became a bit complicated. So, for now I am just building my desired interface in a UIView programatically. So far works great.
dismissPopoverAnimated: is a method of UIPopoverController class. so, you need a popover controller reference in your 'root' view controller.
MyRootViewController.myPopoverController = thePopover;
the button is in your 'root' view controller, and in it's action method:
[self.myPopoverController dismissPopoverAnimated:YES];
In iOS 8, you can dismiss the popover (if it's coming from a segue, at least) with dismissViewControllerAnimated:completion: from within the popover. Doesn't work in iOS 7 (or below), however.
Popover automatically dismissed when clicking outside it , as you order a button to dismiss it you can simply use the following code inside your dismissPopover method :
[self.popoverController dismissPopoverAnimated:YES];
you don't need all this tedious work !
[self dismissViewControllerAnimated:YES completion:nil];
is the solution;
you just need an IBoutlet or add target to your button and then call above line
I had the same problem
just do in your buttonClickMethod:
[yourPopoverController dismissPopoverAnimated:YES];
hope you help!
cheers
I have a view controller,that is a UINavigationController, that at some point pushes (navigationcontroller pushViewController: animated:) a second view that later pushes a third view where I have a button that pops back to the root view (popToRootViewController: animated:). The problem is that after the view is poped back to the root one, the method viewWillApper of the root view is not being called. I've set some breakpoints to check it and it's just not passing through it. I have a method to reload some contents of my root view placed in the viewWillApper and its being completely passed by after the popToRootViewController: animated.
Any idea of what's going on?
Thanks
I used a delegate method to force the update of my view after popToRootViewController. My rootViewController called a network upload class and, on completion, I wanted to reset the form fields on the rootViewController.
In the network upload class, I created a delegate protocol:
#protocol MyNetworkDelegate <NSObject>
#required
- (void) uploadCompleted;
#end
#interface MyNetworkUploader : NSObject{
id <MyNetworkDelegate> _delegate;
}
#property (nonatomic,strong) id delegate;
//other properties here
+(id)sharedManager;
-(int)writeAssessments;
#end
In MyNetworkUploader.m:
-(int)writeAssessments{
//code here to do the actual upload
//.....
//this is a non-view class so I use a global navigation controller
//maybe not the best form but it works for me and I get the required
//behaviour
[globalNav popToRootViewControllerAnimated:NO];
[[globalNav.view viewWithTag:1] removeFromSuperview];
[_delegate uploadCompleted];
}
Then, in my rootViewController:
//my upload is done within a completion block so I know when
//it's finished
typedef void(^myCompletion)(BOOL);
-(void) uploadAssessment:(myCompletion) compblock{
//do the upload
sharedManager=[MyNetwork sharedManager]; //create my instance
sharedManager.delegate=self; //set my rootViewController as the network class delegate
int numWritten= [sharedManager writeAssessments];
compblock(YES);
}
#pragma mark - protocol delegate
-(void)uploadCompleted{
//this is a local method that clears the form
[self clearTapped:nil];
}
I'm NOT proposing that this is the best solution but it worked a treat for me!
When using a navController to push, assuming VC1 is pushing VC2 and you are using a custom presentation style to push your VC2, depending on which style you choose viewWillAppear of VC1 will not be called when VC2 is popped. Here is a list of when is called according to its presentation style.
UIModalPresentationStyle, iPhone, iPad
.fullScreen YES YES
.pageSheet YES NO
.formSheet YES NO
.currentContext YES YES
.custom NO NO
.overFullScreen NO NO
.overCurrentContext NO NO
.blurOverFullScreen  only on tvOS - N/A, N/A
.popover YES NO
.none CRASH CRASH
reference found here