UITableVIew didSelectRowAtIndexPath can't go to new page - iphone

When I selected the table row, nothing happened it didn't go to ContentController and I can't find the UILabel that I declared on ContentController.h when I want to link it to resultLabel
http://dl.dropbox.com/u/31849498/Diet.zip

you're using self.navigationController, but you don't have navigation controller embedded in your application - that's why nothing happens, when you literally call:
[nil pushViewController: detailview animated: YES];

因為你的root view是一個view controller ,並不是一個TableViewController ,所以可能會沒有Navigationcontroller
Denis說的是對的。

I have checked your code but with the following mistakes:-
1) navigation Controller is not present but you are calling
[self.navigationController pushViewController:detailview animated:YES];
2)In the contentController you have not given the iboutlet for uilabel. Hence no mapping is done.
remedies
1)use the presentmodelviewcontroller if you want to go from one view to another
syntax:
[self presentModalViewController:detailview animated:YES];
or
declare the uinavigation controller in the appdelegate and lauch the navigation controller inside the function didFinishLaunchingWithOptions in appdelegate.m
2) IBOutlet UILabel *resultLabel;
#property (nonatomic, retain) IBOutlet UILabel *resultLabel;
replace your code with this.
*Note when ever you try to add Library objects make the iboutlet which is used for doing mapping between the object variable and object.

Related

Pushing a UIViewController from a UIView

I need to push a UIView into my UINavigation controller. I am doing it by
[self.view addSubview:showContactFlow];
And on a button click in UIView I need to push another UIViewController over the UIView. From the UIView I am not able to access self.navigationcontroller How can I do this?
Edit:
I have set the UIView as the view of a new UIViewController I am pushing into, the before mentioned UIViewController . Now I would like to know, how to handle the UIView button event inside its UIViewController, in which's view it is set.
Add a UINavigationController ivar to the UIView and assign it to the main view controller's. Then you should be able to access it from the UIView.
Edit:
Your UIView subclass:
// CustomView.h
#interface CustomView: UIView {
// ...
// your variables
// ...
UINavigationController *navController;
}
#property (nonatomic, assign) UINavigationController *navController; // assign, because this class is not the owner of the controller
// custom methods
#end
// CustomView.m
#implementation Customview
// synthesize other properties
#synthesize navController;
// implementation of custom methods
// don't release the navigation controller in the dealloc method, your class doesn't own it
#end
Then before the [self.view addSubview:showContactFlow]; line just add [showContactFlow setNavController:[self navigationController]]; and then you should be able to access your hierarchy's navigation controller from your UIView and use it to push other UIViewControllers.
You should try to work with an MVC approach. So your controller has access to all that stuff and can keep pushing and popping views, so the view doesn't need to know too much about the controller.
Otherwise, and for this case you can solve it fast by using delegation. So:
showContactFlow.delegate = self;
[self.view addSubview:showContactFlow];
So later in the UIView, you can just say:
[self.delegate addSubview:self];
This is gonna work, but it's not likely to be the best approach you should use.
On button click, you can present a view controller like,
-(void)buttonFunction{
ThirdVC *third= [[ThirdVC alloc]initWithNibNme];......
[self presentViewController:third animated:NO];
}
Using Core animation you can make NavigationController's pushviewController like animation on writing code in ThirdVC's viewWillAppear: method.
where do you add the UIButton is it in showContactFlow view or in the ViewController's view??
In regard to the modalViewControllers issue the correct method is
[self presentModalViewController:viewController animated:YES];
the standard animation in upwards

Advice with Tab Bar and Nav Bar

I'd just like to clear something up..
I have an app where the Main Window UI has a Tab bar with 3 tabs (opt1, opt2, op3). Each opt has its own xib file where i've drawn their own interfaces.
In my app delegate class I have included a UITabBar *rootController, and hooked this up to my tab bar in my Main Window xib file.
Now.. In the Tab bar, I have dragged in 3 navigation controllers (1 for each opt) and inside each one I have a 1) tab bar icon, 2) navigation bar and 3) view controller.
Back in my app delegate.h class I have included code for UINavigationController *nav1, nav2, nav3..and hooked these up accordingly in IB in MainWindow.xib (TabBar->navController1, navController2, navController3).
Is this the right way to do it? Also how can I make use of these nab bars in my opt1, opt2, opt3 class files?
here is my code:
app delegate.h
#import <UIKit/UIKit.h>
#class LoginViewController;
#interface myAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
UINavigationController *navigationController1, *navigationController2, *navigationController3;
IBOutlet UITabBarController *rootController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController1, *navigationController2, *navigationController3;
#property (nonatomic, retain) IBOutlet UITabBarController *rootController;
#end
appdelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window addSubview:[rootController view]];
[window makeKeyAndVisible];
LoginViewController *loginViewController = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:nil];
[self.rootController presentModalViewController:loginViewController animated:NO];
}
Then in my LoginController.m class , when the user enters correct credentials I call
[self dismissModalViewControllerAnimated:YES];
In my MainWindow.xib, I hook up my rootController to a TabBarController. In the TabBarController I have put 3 NavigationControllers inside it and linked them to 3 tabOption classes which each have their own .xib view.
The tab bar switches between the 3 option views nicely. However in 1 .xib view I have a button to open a new .xib. So in my tabOption1 class I have the following:
-(IBAction)openBook:(id)sender{
UIViewController *nextVC = [[PageViewController alloc] initWithNibName:#"PageView" bundle:nil];
[self.navigationController pushViewController:nextVC animated:YES];
}
However this does not open up my PageView.xib... I have connected it to my PageViewController class and everything too..and the button works because I've tested it with a UIDialog
Have you seen the Apple Programming Guides? They might give you a better understanding of how everything ties together - you could start here:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/NavigationControllers/NavigationControllers.html#//apple_ref/doc/uid/TP40007457-CH103-SW1
In answer to your question, that looks like an OK way of setting up. I really would recommend reading up a bit though :)
In response to your comment, that looks like a reasonable way to do what you're trying to achieve. If it works, then it works.
In response to your other issue then you can get the navigation controller object by doing this: self.navigationController
So you can "go to" a new view controller like this:
// make the view controller
UIViewController *nextVC = [[MyCustomViewController alloc] initWithNibName:#"MyCustomViewController" bundle:nil];
// push it onto the navigation stack
[self.navigationController pushViewController:nextVC animated:YES];
To add this to the click event on a button you need to create the button in interface builder and create an IBAction in your code. The IBAction might look like this:
- (IBAction)pushNextViewController:(id)sender {
UIViewController *nextVC = [[MyCustomViewController alloc] initWithNibName:#"MyCustomViewController" bundle:nil];
[self.navigationController pushViewController:nextVC animated:YES];
}
Then you need to link to it from interface builder. I'm not sure how to do this, I generally don't use interface builder, and certainly haven't used it since about XCode 3.
To do it programatically you can use this method:
[MyButton addTarget:self selector:#selector(pushNextViewController:) forControlEvents:UIControlEventTouchUpInside]; // always use touch up inside
Keywords to look up to help you find tutorials and stuff on the internet: ibaction uinavigationcontroller pushviewcontroller:animated: popviewcontrolleranimated:

UIPopover and UITableView data exchange

I have a UITableView in a UINavigationController. On the navigation bar I have a button called add. When this button is pressed it presents a UIPopoverController, where user can input data to be added as a new row/cell in the UITableView. My issue is how can I add a new cell to the UITableView from the UIPopover? Do I pass in the array data to the UIPopOver root controller?
There are two solutions to this that I'm aware of. One would be to send a notification from the popover to the root controller and apply the necessary code to update the tableView in the handleNotification method.
The other, one that I personally use, is to set up a delegate protocol for the popover. You'll have to set it up something like this:
#protocol PopoverDelegate
- (void)addNewCell; // you can add any information you need to pass onto this if necessary such as addNewCellWithName:(NSString *)name, etc.
#end
#interface MyPopoverViewController..... {
id <PopoverDelegate> delegate;
// the rest of your interface code;
}
#property (nonatomic, retain) id delegate;
// any other methods or properties;
#end
Then in your root view controller header file, you need to add the delegate
#interface RootViewController .... <PopoverDelegate> {
Then in your root view controller implementation file, assign the popover delegate when you instantiate it. For example:
MyPopoverViewController *vc = [[MyViewController alloc] init];
vc.delegate = self; // this is where you set your protocol delegate
myPopover = [[UIPopoverController alloc] initWithContentViewController:vc];
myPopover.delegate = self;
[vc release];
Finally, you'll add your protocol method somewhere in the code
- (void)addNewCell {
// do what you want with the tableView from here
}
Sorry that's a bit long. I just wanted to make sure I was thorough. Hope it helps

How to access data from one view to another view?

I have an UITabBarController with two tabs:
UINavigationController
OptionsViewController : UIViewController
How can I reach data (ie. UILabel.text) set in OptionsViewController, in a new added modal View which has been invoked from UINavigationController?
Edit1:
Scenario: After launching app I select the second tab bar called "Options" where I fill up a textField. The label is set to value from textField. Next I select first tab bar called "Main" where I have a button. I click the button and new modal View appears. In this new modal View I'd like to show the value from textField
I love MVC, but I'm not an absolute purist to the point of hurting yourself to accomplish a fairly trivial task, so the answers you've gotten here are good and useful. However, by creating an ivar to refer back to a specific type such as a label or other view controller, you are coupling things together that aren't necessary to couple. What you could do instead is make your first tab view controller a delegate of your second tab view controller. So do something like this in your app delegate.
OptionsViewController *optionsViewController = // ... get this from the tab view
FirsTabViewController *firstTabViewController = // ... same here
[optionsViewController setDelegate:firsTabViewController];
Which means that you need an ivar in your OptionsViewController:
#property (assign) id delegate;
Then, when whatever event you want to trigger the change occurs in your options view controller, see if the delegate can respond to a selector you've named. For example:
- (void)someEventHappenedLikeTyping:(id)sender;
{
if ([delegate respondsToSelector:#selector(setOptionsString:)]
[delegate performSelector:#selector(setOptionsString:) withObject:[label text]];
}
Notice you never specified any specific object types. You just check to see if the delegate (which was declared as id) can respond to that selector. If it can, it does what it's told and just is silent otherwise.
For this to work, you need an ivar for the optionsString in your FirstTabViewController and so it would be declared in the header as:
#property (copy) NSString *optionsString;
and then #synthesize it in the .m. This causes -setOptionsString to become a valid selector that will get called in the -someEventHappenedLikeTyping method.
Anyhow, now, if you ever need to to change which view controller references which, you don't have to go into the header and change the type of ivar referenced. You simply need to implement the selector (this is known as an informal protocol, by the way) in the view controller that is a delegate of your options view controller.
Just some food for thought there. Hope that helps. There is further de-coupling that could be done in the code I've added, but again it may be overkill for such a simple task. Let me know if you need clarification or want to understand what I mean by further decoupling.
Best regards,
p.s. Sometimes needing to share data between two tab bar view controllers, means you have a design flaw. If you are wanting to store preferences from your options view, you should just call
[[NSUserDefaults standardUserDefaults] setObject:[label text] forKey:#"option1"];
[[NSUserDefaults standardUserDefaults] synchronize];
Then you can pull from the NSUserDefaults back in your main tab with;
NSString *option1 = [[NSUserDefaults standardUserDefaults] objectForKey:#"option1"];
// Do something with option1
In your OptionsViewController, create a property:
#property (nonatomic, retain) UILabel *mylabel;
then after creating your OptionsViewController, but before displaying it, set the mylabel property. (Or perhaps you just want the text, so you can use an NSString* property.)
Edit:
So you probably want to do something like this:
OptionsViewController *vc = [[OptionsViewController alloc] init];
vc.mylabel = mySomethingLabel;
[self presentModalViewController:vc animated:YES];
So after creating the object, you set the property, and then you display the view controller.
I usually set IBOutlets in each of my viewcontrollers which point to the other controller.
So if I had view controllers A and B. A has an IBOutlet to B and B to A. Then whenever I want to access anything in B from A i just use a dot operator on B.
In your example UINavigationController would #include "OptionsViewController.h" and have an ivar IBOutlet OptionsViewController * ovc (which is set in IB) and then any instance variable from your options view controller can be referenced as ovc.UILabel.text from the navigation controller. This process can be reversed to access values from your navigation controller in your options view controller.
Example Navigation Controller (.h):
#include "OptionsViewController.h"
#interface UINavigationController // (whatever the name of this class is)
{
OptionsViewController * ovc;
}
#property (nonatomic, retain) IBOutlet OptionsViewController * ovc;
#end
Example OptionsViewController.h:
#interface OptionsViewController
{
UILabel * label;
}
#property (nonatomic, retain) IBOutlet UILabel * label;
#end
Then from UINavigationController (.m) you can just write ovc.label.text to access the text.
I have an easy way to access data between views. Let's try. You have two views named view1 and view2, you can define a View *vc1 property in view2.h, set the vc1 point to view1, when pop the view2, like this:
view1.m
//here pop out view1 code
View2 *view2 = [[View2 alloc] initWithNibName:#"View2" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:view2 animated:YES];
view2.vc1 = self; //transfer view1 instance to view2,use vc1 you may handle view1 in view2 directly
[view2 release];
view2.h
#import "view1.h"
#property (nonatomic, retain) IBOutlet View1 *vc1; //here you could name it as view1 as well :)
view2.m
vc1.lblTable.text = #"ok"; //you'll see "ok" in view1
[self.navigationController popViewControllerAnimated:YES]; //navigate to view1
//dont forget release vc1

TabBar application, moreNavigationBar and nibs with navigationBars

I have a TabBar application with several nibs, most with a NavBar. It works pretty well, except for the "views" that are inside the "More" section of the tabBar.
As expected, it will put a NavBar to return to the "More" list, as well as the NavBar i've placed in the nib.
I've tried to remove the view controllers from the moreNavigationBar and put the top controller from my nib's navBar, but I get and extra view from somewhere:
- (void)viewDidLoad {
TestAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
UITabBarController *ctrl = appDelegate.rootController;
UINavigationController *navCtrl = ctrl.moreNavigationController;
[navCtrl popToRootViewControllerAnimated: NO];
[navCtrl pushViewController: navController.topViewController animated: YES];
navController = navCtrl;
[super viewDidLoad];
}
My AppDelegate:
#interface TestAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UITabBarController *rootController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *rootController;
The MainWindow nib is that of a Window-based project with a TabBarController, linked to the rootController in my app delegate.
The other nibs have a view + navigationController and I have a UITableViewController subclass as my Root View Controller.
If I could get this to work it wouldn't still solve my problem, because I want to allow the user to place this anywhere in the tabBar, so, I must have some way of knowing if there's a navigationBar.
So, my question is, how do you know if there's a navigationBar (in this case, if the tabBar's navigationBar is being shown) and, if so, how do I get my navigationController to "become" the tabBar's navigationController?
Or, if you have another idea on how to solve this problem, i'd also be appreciated :)
The recommendation from apple is that you have the TabBar controller contain the Navigation controllers and not the other way around. I have a setup more or less like this, and I have the More tab hold a Nav controller, basically like this:
#interface SomethingNavViewController : UIViewController {
UIView* aview;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIView *aview;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#end
In the NIB, I have a separate Nav controller in the view of the more panel, I haven't replaced the tab bar item's view with a nav controller view, I've just added a Nav controller to the view.
In my implementation file, I have:
- (void)viewDidLoad {
[super viewDidLoad];
[[self view] addSubview:[navigationController view]];
SomeOtherController *aController = [[[SomeOtherController alloc ] initWithNibName:#"SomeOtherController" bundle:nil ] autorelease];
aController.title = #"Artwalks";
// lots of application logic here.
[self.navigationController pushViewController:aController animated:YES];
[self.navigationController setDelegate:self];
}
One key thing about this is that I have implemented the navigationController's delegate method, which is really handy when you're just inserting the nav controller. I found when I didn't do this, my views don't get viewDidAppear messages, so I implemented the protocol and added this method:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if ([viewController respondsToSelector:#selector(viewDidAppear:)]) {
[viewController viewDidAppear:animated];
}
}
and that solved a variety of my lingering problems.
Anyway, I hope this answer gave you the detail you needed. IF it didn't, please give more details about your question. I'm not quite sure what but I get and extra view from somewhere met, but it sounds like something I encountered before I found this solution.