iphone: tab bar controller: how to call methods? - iphone

i need some help:
i have several views (view xib): login, sign up, settings, and so on.
i have created a project, added a tab controller and the tabs are working fine.
The problem is that: we have 2 sign up 'ways' and my boss want them in two different tabs. The code is almost equal, so my idea is:
instead of having 2 different views with copied & pasted code, i would like to create a general sign up view and just 'fire' the signUp_method1 if the user presses the first tab, also if the user presses the second tab i will fire the signUp_method2. the question is how should i do this?.
also, i'm worried that i will not be able to customize the view depending of the action: i have to show 2 different fields and labels according to the sign up way. i have been looking for some way, i read about viewDidLoad and actually i'm using it for initialization but that does not solve the problem.
Perhaps i should not use tab controller, so, if you have suggestions i'm happy to read them.
Thanks for reading.

Use the UITabBar delegate methods. You need to make sure the view that the tab bar is in implements the "UITabBarDelegate" in the class header.
This method might do the trick:
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
// You can put logic in here to check on what item was pressed and fire the different methods depending on what you put.
if ([[item title] isEqualToString:#"Libraries"]) {
NSLog(#"Pressed on libraries tab!!");
} else if ([[item title] isEqualToString:#"Search"]) {
NSLog(#"Pressed on search tab!!");
}
}
As long as you have your components linked up in IB to your controller properly, you should be able to programmatically manipulate them as needed.

Related

VoiceOver ignores visible views, and speaks accessibilityLabels of hidden views

I have UIView, that can contain one of two views. When I removeFromSuperview first view and addSubview second view I can still hear accessibiliyLabel of hidden view. And only in 1-2 seconds I can hear correct accessibiilityLabel.
I see that it is common situation when hidden state of view is changed, accessibility can be frustrated and still speak hidden views, and does not note visible views.
Also if in UITableViewCell UIButton is hidden and then hidden state changes to NO, VoiceOver ignores it like it is still hidden. Only manual implementation of UIAccessibilityContainer protocol for cell resolves mentioned problem
No Notifications can solve this issue. Even playing with accessibilityElementsHidden did not help. Struggling with this during several days
Please can you recommend is there any way to say Accessibility that hierarhy of views was changed
You can post a UIAccessibilityScreenChangedNotification or UIAccessibilityLayoutChanged to alert UIAccessibility that the view changed. Since you didn't post any code, I can only give you a generic example, e.g.:
UIAccessibilityPostnotification(UIAccessibilityLayoutChanged,accessibilityelement)
...where "accessibilityelement" would be a button or text field or other accessibility element that VoiceOver switches to next.
Reference: UIKIt Reference
Just ran into this myself with a third party side menu library and had to use accessibilityElementsHidden to fix it. I first tried leveraging the accessibilityViewIsModal property, but that only works on sibling views.
#pragma mark - IIViewDeckControllerDelegate
- (void)viewDeckController:(IIViewDeckController *)viewDeckController didOpenViewSide:(IIViewDeckSide)viewDeckSide animated:(BOOL)animated
{
if (viewDeckSide == IIViewDeckLeftSide) {
[self.topViewController.view endEditing:YES];
self.viewDeckController.leftController.view.accessibilityElementsHidden = NO;
}
}
- (void)viewDeckController:(IIViewDeckController *)viewDeckController didCloseViewSide:(IIViewDeckSide)viewDeckSide animated:(BOOL)animated
{
self.viewDeckController.leftController.view.accessibilityElementsHidden = YES;
}

Refreshing the content of TabView

Ok I am trying to refresh the tab content of each of my tabs after a web call has been made, and I have tried soo many different methods to do this that I have lost count. Could someone please tell me how this is possible?
The web call just calls JSON from a server and uses it to update the content of the tabs. For testing purposes I have a button set up inside my settings class. Settings class is a view within the home tab which has a button called refresh. When clicked this takes JSON stored on the device which is different to the one called from the web call on application start up. This saves me having to change the JSON on the server.
I will take you through some of the techniques I have tried and would be grateful if someone could tell me what I am doing wrong.
I tried making an instance of the class and calling the refresh method like this
DashboardVC *db = [[DashboardVC alloc] init];
[db refreshMe];
The refresh method in dashboard class is this
-(void) refreshMe
{
[self loadView];
[self viewDidLoad];
}
However no luck. This method will work if I call it inside the Dashboard class, but wont work if I call it from another class. I think it is become I am instantiating a new class and calling refresh on that. So I dropped that technique and moved onto the next method
This loops through all the tabBars and changes the tabTitles without any issues, so it I know it is definitely looping through the ViewControllers properly.
I also tried every varient of the view methods like ViewDidAppear, viewWillAppear etc, no luck.
I also tried accessing the refreshMe method I made in the dashBoard class through the tabController like this
[[[self.tabBarController viewControllers] objectAtIndex:0] refreshMe];
But again no luck, this just causes my application to crash.
I read through this guide
https://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewControllerPGforiOSLegacy/TabBarControllers/TabBarControllers.html
on the apple website but it doesn't seem to cover how to refresh individual tab content.
All I want is to have each individual tab refresh its content after the web call is made, and have spent ages trying to figure this out, but nothing is working.
So would be very grateful if someone could show me what I am doing wrong?
Thanx in advance....
EDIT:
Expand on what I have tried
After discussion with Michael I realised you should never call loadView as against Apple guidelines. So I removed any references to LoadView. I have now placed a method in all the main ViewControllers called RefreshMe which sets up the views, images texts etc in the class. And this method is placed inside the ViewDidLoad. Now I want to be able to call these methods after a web call has taken place, so effectively refreshing the application.
My viewDidLoad now looks like this in all my the main classes.
- (void) viewDidLoad {
[super viewDidLoad];
[self refreshMe];
}
And then the refreshMe method contains the code which sets up the screen.
The JSON data pulled from the web call will set up the content of each of the 5 tabs, so need them all to be refreshed after web call.
I tried looping through the viewControllers and calling viewDidLoad, which should in turn call the refreshMe method which sets up the class, however nothing happens. Code I used was this
NSArray * tabBarViewControllers = [self.tabBarController viewControllers];
for(UIViewController * viewController in tabBarViewControllers)
{
[viewController viewDidLoad];
}
For the time being I have also included
NSLog(#"Method called");
in the viewDidLoad of each class to test if it is being called. However the message is only being printed out when I first load the application or if I re-enter the application. This method should be called after I click the refresh button in the settings screen but it isn't and I have no idea why.
Anyone have any idea why this is not working?
From the question and your comments, it sounds like there are at least two problems:
You're having trouble accessing the view controllers managed by your app's tab bar controller.
You seem to be working against the normal operation of your view controllers.
The first part should be straightforward to sort out. If you have a pointer to an object, you can send messages to that object. If the corresponding method doesn't execute, then either the pointer doesn't point where you think it does or the object doesn't have the method that you think it does. Let's look at your code:
NSArray * tabBarViewControllers = [self.tabBarController viewControllers];
for(UIViewController * viewController in tabBarViewControllers)
{
[viewController viewDidLoad];
}
This code is supposed to call -viewDidLoad on each of the view controllers managed by some tab bar controller. Leaving aside the wisdom of doing that for a moment, we can say that this code should work as expected if self.tabBarController points to the object that you think it does. You don't say where this code exists in your app -- is it part of your app delegate, part of one of the view controllers managed by the tab bar controller in question, or somewhere else? Use the debugger to step through the code. After the first line, does tabBarViewControllers contain an array of view controllers? Is the number of view controllers correct, and are they of the expected types? If the -viewDidLoad methods for your view controllers aren't being called, it's a good bet that the answer is "no," so figure out why self.tabBarController isn't what you think.
Now, it's definitely worth pointing out (as Michael did) that you shouldn't be calling -viewDidLoad in the first place. The view controller will send that method to itself after it has created its view (either loaded it from a .xib/storyboard file or created it programmatically). If you call -viewDidLoad yourself, it'll either run before the view has been created or it'll run a second time, and neither of those is helpful.
Also, it doesn't make much sense to try to "refresh" each view controller's view preemptively. If your app is retrieving some data from a web service (or anywhere else), it should use the resulting data to update its model, i.e. the data objects that the app manages. When a view controller is selected, the tab bar controller will present its view and the view controller's -viewWillAppear method will be called just before the view is displayed. Use that method to grab the data you need from the model and update the view. Doing it this way, you know that:
the view controller's view will have already been created
the data displayed in the view will be up to date, even if one of the other view controllers modified the data
you'll never spend time updating views that the user may never look at
Similarly, if the user can make any changes to the displayed data, you should ensure that you update the model either when the changes are made or else in your view controller's -viewWillDisappear method so that the next view controller will have correct data to work with.
Instead of refreshing your view controllers when updating your tab bar ordering, why not simply refresh your views right before they will appear by implementing your subclassed UIViewController's viewWillAppear: method?
What this means is that each time your view is about to appear, you can update the view for new & updated content.

UIWebView delegate not working the second time

I have an rss feed which returns a json containing a title, short text and full-size text. The title and part of he short text is displayed in a TableView.
I have 3 controllers with 3 views.
View 1 displays a TableView containing articles from the json( the title and short text ), each article has a "Read more" button, in the IBAction of the button, i push a viewcontroller(2) into the navigation controller, the controller has a UIWebView(second View), which loads a html string. The string contains links, when the user taps a link, i want to present a modal view controller with another WebView(3), this time using the request(keep in mind that both WebViews have separate controllers and nibs).
The delegates are set properly on both of them, i tried both from code and using visual tools. In the delegate method shouldStartLoadWithRequest in the first WebView i check to see if the request parameter contains "http" or "www", because only then i want to call the second WebView. The second WebView works well the first time, the view is presented modally fine, but when i dismiss it and tap the same link or another, the shouldStartLoadWithRequest delegate method is not called, but the link loads in the same WebView(the first one).
I googled this but didn't find a similar case to mine, or a solution. I don't have that much experience with ios app development, but a colleague is pretty good, and we didn't manage to find a solution to this problem. We took the code apart and analyzed it, but we didn't find a potential source for this problem, and he has a separate project where he has the same problem, only he uses only one controller and one WebView (our controllers and nibs where created independantly). We were pretty thorough with the research and the code examination
It seems that the solution was quite easy. The first WebView, aparently looses the connection to it's delegate, so, in the second WebView controller just add
- (void)viewWillDisappear:(BOOL)animated {
[self.parentViewController viewWillAppear:YES];
}
and in the first controller of the first WebView:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
webView_.delegate = self;
}
I hope this helps someone

How to call method automatically when switching views in TabBar app with a single ViewController

My application uses UITabBarController with 4 tabs. Each tab will have a UIWebView along with other types of objects. When the app launches I need to call the method for this first webView to retrieve my web content.
I have this method in my viewdidLoad:
[self performSelectorInBackground:#selector(getAdvisory) withObject:nil];
The web content on the first tab works fine. I'm just at a loss to get my other tabs to load up. I think I would use a switch or if statement but I do not know how to tell which view is loaded.
I need to do the same for the rest of the tabs. The app has a single view controller.
When setting an action using a button everything works fine. I just do not know how to call the method when a different view (tapping tabs) loads.
Also when retrieving data from the network, what are the best methods to use to not tie up the main thread? I have read where NSOperation would be used in this scenario. Is this correct? If so how would I go about doing this?
Thanks in advance.
I was looking for a solution to this problem and there is a better method.
Simply override the viewDidAppear method and insert the code you want to execute when the view does appear!
As an example the following code will call myMethod.
-(void) viewDidAppear:(BOOL)animated {
[self MyMethod];
}
maybe by using a user delegate of your UITabBar and the method:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
Sent to the delegate when the user selects a tab bar item.
See reference.

navigationController will/did ShowViewController - How to tell which?

Given the UINavigationController delegate methods:
-(void)navigationController:(UINavigationController*)navigationController (will/did)ShowViewController:(UIViewController*)viewController animated:(BOOL)animated
How do you tell or compare which view controller instance is relevant to the event?
I am developing an app that renders touch-navigable graphs using OpenGL. The root view contains the graph, and pushed navigation controllers contain options. I'd like to disable animation(rendering) of the graph when the user navigates away from it and re-enable it when they return.
(I know rendering should be done after the touch events and not constantly with an on/off; the template openGL code I built the app on doesn't make that an easy change but I'll get around to it eventually!)
(Oh another thing; it's a tab bar app with a navigation controller on each tab. For some reason view(did/will)(appear/disappear) events only seem to get fired when changing tabs, not the position on navigation controller stack.)
Fixed with the following:
if(viewController == [self.viewControllers objectAtIndex:0])
{
NSString* bob = #"Your uncle";
}
Thanks for your direction.
You would keep a list of ViewControllers and then compare to the one that is being shown.
You can compare by just comparing the references
for(UIViewController *vc in viewControllerArray)
{
if(vs == viewController)
//do stuff
}
Does this help or did i misunderstand something?