Access UI elements created in Interface Builder in the controller? - iphone

This is a very simple iPhone / Cocoa question. I have a button that transitions between two views. I set most of this up using interface builder. When I click the button and the second view is displayed, how do I programmatically change the text of the button (to say 'back', for instance)?

In your class declaration, declare a button object, and make sure it is specified as an IBOutlet:
IBOutlet UIButton* myButton;
Once you save this change, if you go back to Interface Builder, you should see this outlet when you right click on your File's Owner (assuming you have specified the File's Owner properly). Associate this outlet with the onscreen UIButton by right-click dragging.
Now the on screen object is associated with your in-code name.
Whereever you want to change the text on the UIButton, just say:
[myButton setTitle:#"Back - or whatever else you want it to say"
forState: UIControlStateNormal ];
// you can set different title text for each state
// of the button (selected, active, or normal)

Alternately, you can assign a unique tag to the control and use -[UIView viewWithTag:] to get a UIView pointer to the control. In most cases, outlets are the preferred mechanism, but tags are useful in things like table cells.

You'll need to set up an outlet for IB:
#interface MyViewController : UIViewController {
IBOutlet UIButton *myButton;
}
Save, bring up IB, set the file's owner to MyViewController, then create referencing outlets from both your UIView and UIButton to the appropriate points in the file's owner in the Connections Inspector.
Then in the implementation, you could do:
[myButton setTitle:#"Back" forState:UIControlStateNormal];
If you get lost with the connections, I'd recommend having a look at the lecture notes and video lectures at http://www.stanford.edu/class/cs193p/cgi-bin/index.php , which go into some detail about iPhone basics.
Hope that helps.

Most of the posts so far have focused on creating the button, and are very correct. The following answers the rest of the question:
When I click the button and the second view is displayed, how do I programmatically change the text of the button (to say 'back', for instance)?
The easiest way, if I understand your circumstance correctly, is to use the plug-n-play UINavigationBarController. First you want to push your second view controller onto the view stack:
// In firstViewController.m
self.navigationController = [[UIViewController alloc]initWithNibName:#"secondView" bundle:nil];
[self pushViewController:secondViewController animated:TRUE];
When your second view controller is shown, you should automatically get a back button on the left side of the nav-bar. If there is a need to change the text of that back button, you can simply refer to it like so:
// In secondViewController.m
-(void)ViewWillAppear
{
[self.navigationItem.backBarButtonItem setText:#"GoBack"];
}
There are also the left and rightBarButtonItem(s) which are handy for more complex navigation. Here is a less plug-n-play scenario:
// In secondViewController.h
-(IBAction)goBack; (this should appear as an action in your associated nib file)
// In secondViewController.m
-(void)viewDidLoad
{
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"GoBack" style:UIBarButtonItemStylePlain target:self action:#selector(goBack)];
}
-(IBAction)goBack
{
// logic to be done before going back
[self popViewControllerAnimated:secondViewController animated:TRUE];
}

You need to define and connect an "outlet". Take a look at the documentation, making note of the section on "Connections and Bindings".

Related

How to make multiple UIButtons connect to the same IBAction?

I need several UIButtons to all connect to the same IBAction so the buttons can all do the same thing without having to copy and paste the code. Please tell me if there is a way to do this! It might be right under my nose, but I can't find it. Thanks!
Simply add the same target and selector to each button:
[button1 addTarget:self
action:#selector(buttonClicked:)
forControlEvents:UIControlEventTouchUpInside];
[button2 addTarget:self
action:#selector(buttonClicked:)
forControlEvents:UIControlEventTouchUpInside];
// etc.
For this You need to use set IBOutlet for Each Button or Set tag for each button if you are using Outlet then used this code .h
#interface RootViewController_Phone : UIViewController
{
IBOutlet UIButton *btn1;
IBOutlet UIButton *btn2;
}
- (IBAction)buttonPressed:(id)sender;
-(void)CallButtonsMethod;
#end
Now in .m file
- (IBAction)buttonPressed:(id)sender{
if([sender isEqual:btn1])
{
[self CallButtonsMethod];
}
if([sender isEqual:btn2])
{
[self CallButtonsMethod];
}
}
-(void)CallButtonsMethod
{
//your Code
}
Use IBOutletCollections.
Here is tutorial for that:
http://useyourloaf.com/blog/2011/03/28/interface-builder-outlet-collections.html
I've found that I'm usually not able to hook up multiple buttons (or even a single button, for that matter) in IB to an already existing IBAction in code, by Ctrl-dragging from the button to the IBAction in the m file. Xcode tries to create a new action in the dragged-to file, but won't connect to an existing action. [This is true for Xcode 4.6.1 and several previous (maybe all) versions.]
The approach in the accepted answer in the following link works if the IBAction is in the view controller which is the "File Owner" for the view containing the button:
Connect object in .xib to existing IBAction
However if you want your IBAction to be in the view's own class, rather than the view controller's class, then the following approach works:
Drag only one button onto the canvas in IB first. Control-drag from
the button to the view's .m file.
Drop the dragged line in any vacant space in the implementation section of the code.
Define a new IBAction in the little popup dialogue box. So now you have one
button hooked up to an IBAction.
Now instead of dragging more buttons from the object library, hold
down the Option key and drag out a new button from the original one.
This new button will come hooked up to the same IBActions as the
original one. (If you need to create lots and lots of buttons and
this seems tedious, you can select a bunch of already created ones simultaneously and
Option-drag to create as many more in a single go.)

iPhone utility application, connection from FLipSideView to MainView?

I'm trying to learn Objective-C and iPhone programming, but I'm stuck with a problem. I have a utility application, and I have a text on my MainView and a button that change the text when I click it. Easy, and workes great. But what if I wan't to place the button on the "backside" in the FlipSideView, and still make it change the text on the frontside (MainView)? How do I get the views to talk together? I have tried a lot of different things, and searched for an answear, but can't seem to figure it out.
Would be great if someone had a answear, or maybe a link to a tutorial/example.
I suppose you've used the template which implements the following method in the MainViewController:
- (IBAction)showInfo:(id)sender {
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"FlipsideView" bundle:nil];
controller.delegate = self;
...
}
As you can see it sets the delegate of the FlipSideController to the instance of the MainViewController.
A way would be to put an action into your FlipSideViewController, something like this:
- (IBAction)changeTextInMainView
{
[(MainViewController *)self.delegate changeText];
}
which is triggered when touching your button on the backside. You've got to wire it in IB as well as add the method to the header.
Then implement something like this in your MainViewController
- (void)changeText
{
self.myLabel.text = #"text changed to this";
}
Add this method to the header as well.
Another more elegant approach would be to save the text of your label in a property(maybe in it's own model class) which can be accessed from any view, by passing it by reference down the controllers. Then add a Key Value Observer from each viewController to the property which should show the text and update the view.

TabBar Application with a View that has a UIButton on the View to goto another View outside the TabBar

I'm new to iPhone development, and multiple views (xib or nib) are really confusing me. This is what i'm trying to achieve...
using TabBarControllerAppDelegate
Have 5 different TabBar Items and have created 5 different Views thru the TabBarController
The First View has a UIButton that is a Next button that needs to go to another view called View2.XIB.
I setup a new UIViewController which references the View2 and an IBAction for the switchPage, etc but not able to get it to do anything when clicking on the button.
All of My TabBar buttons work but not able to Navigate to anything outside of the Tabbar
Any help in this regard will be highly appreciated. Anyone have any examples
IBAction switchPageButtonPressed:(id)sender
{
[self.tabbarcontroller.tabBar setSelectedItem:[self.tabbarcontroller.tabBar.items objectAtIndex:1]];
here 1 means ur 2nd tabbar
}
It is difficult to find the problem without the code, but I will assume your action code for the switchPage button is incorrect. You should use code similar to the following:
- IBAction switchPageButtonPressed:(id)sender
{
ViewController2 *view2VC = [[ViewController2 alloc] initWithNibName:#"View2" bundle:nil];
[self presentModalViewController:nview2VC animated:YES];
[view2VC release];
}
If you are confident your method works, then you will want to verify that the action is hooked up correctly. The easiest way to do this is to place a breakpoint on the method and run the app in Debug. When you click the button, the debugger should break on your method, if it doesn't, you will need to check your connections in Interface Builder.

How to set a subview's delegate to the superviews controller

In IB I created UIView inside of a UIScrollView. File's owner for both is a UIViewController named JLViewController. The UIView is wired to class BodyClock.
The BodyClock class draws a graph inside the view. It also creates several small views which act as touch hot spots. When a hot spot is touched it displays an informative alert with a button for more detail. I need to tell JLViewController to display the detailed information. I thought I could do this by making the ViewController the HotSpot's delegate. Being as how I am creating the hot spots in the BodyClock class, I can't figure out how to set the hot spot delegate to JLViewController. I am trying to do something like this..
//Code in BodyClock
//create the hot spot
id viewController = [self nextResponder];
HelpHotSpot *helpHotSpot = [[HelpHotSpot alloc] initWithFrame:CGRectMake(start_x, melatoninHeightEnd_y, 80, 40)];
helpHotSpot.delegate = viewController;
[viewController addSubview:helpHotSpot];
[helpHotSpot release];
//Code in the HotSpot after touch and request for more info
//notify JLViewController to display the details
if ([self.delegate respondsToSelector:#selector(hotSpotMore:)]) {
[self.delegate hotSpotMore:itemDetails];
}
Everything works except that respondsToSelector fails. If I NSLog viewController or self.delegate I get...
UIScrollView: 0x7443c20; frame etc...
I was expecting JLViewController: instead of UIScrollView: so I think this is the problem.
How do I set the delegate to the ViewController for these subviews?
Is it possible, or should I be using notification instead?
This:
id viewController = [self nextResponder];
isn't doing what you think it is doing. This doesn't get a view's controller but instead looks at the chain of responders and determines which is the next one for responding to events - these are typically views or controls (not to be confused with controllers). It appears that after your hot spot view, the scoll view is next.
You'll have to get the pointer to the controller correct. Maybe in your hot spot view you could add:
IBOutlet JLViewController *viewController;
And in interface builder connect this to your view controller.

What is the easiest way to add a row in a UITableView with a user-provided string?

I have a simple UITableViewController in a UINavigationController that displays a list of strings from an array with the default Edit/Done button on the right-hand side of the navigation bar.
When pressing the Edit button, the UITableView animates correctly and shows the red minus icons to delete. Pressing the delete button removes the row from the table view and the array (implemented in the tableView:commitEditingStyle:forRowAtIndexPath: method of the UITableViewController).
I would now like to allow the user to add a row to the view (and add the string to the underlying array), but I'm not sure how to go about doing so. The commitEditingStyle method has else if (editingStyle == UITableViewCellEditingStyleInsert), but I don't know how I can get the user to input the string.
I've read the Table View Programming Guide (more specifically the example of adding a table-view row), but this seems to require a whole new UIViewController subclass just to get a string from the user.
Is there no easier way?
Creating another view controller is probably going to be the easiest way in the long run. You can present it modally by calling
SomeViewController* theViewController = [[SomeViewController alloc] init];
[self presentModalViewController: theViewController animated: YES];
[theViewController release];
When the theViewController is ready to go away it can call
[[self parentViewController] dismissModalViewControllerAnimated: YES];
OR
you can setup a protocol for your new view controller so it can notify your original view controller of completion and send a value back, if you wanted an NSString back you might use
#protocol MyViewControllerDelegate
- (void)myViewControllerDelegate: (MyViewController*)myViewController didFinishWithValue: (NSString*)theString;
#end
MyViewController would then have a delegate property
#interface MyViewController
{
id<MyViewControllerDelegate> delegate;
}
#property(nonatomic,assign) id<MyViewControllerDelegate> delegate;
#end
If you use the protocol method your original view controller will adopt that protocol and will dismiss the modal view itself when it receives this message.
I hope that helps out, it may seem a little complicated at first, but it makes gathering data very easy.
You could use a UIAlertView or similar class yourself. Just pop up the modal view to request the string, establish the right callbacks, then pop it in your dataSource.
You can also insert a cell with a UITextView and a "Tap to Edit" placeholder, then on the textView Callbacks, remove the textView and display the string. Further editing would need to drill down or do something else