I am creating an app in XCode 4.2 using the storyboard feature. I have 4 views connected on the basis of Navigation controller. In one of the view I have a textbox and a button. I have implemented the keyboard hide on return by adding the textbox as the deligate. Once I am done entering on the textbox box i will press the button and it should update the UIImageView.
I understand i need to establish some kind of relation between the UIImageView on the Interface Builder and the UIImageView IBoutlet i have declared on the interface file. But how do i do this in storyboard situation ?
In the abcViewController.h i have
#interface abcViewController:UIViewController {
IBOutlet UITextField *code;
IBOutlet UIImageView *qrImage;
}
#property (noatomic, retain) UITextField *code;
#property (noatomic, retain) UIImageView *qrImage
-(IBAction)textFieldReturn:(id)sender;
-(IBAction)goButton:(id)sender;
In the abcViewController.m i have
#synthesize code;
#synthasize qrImage;
-(IBAction)textFieldReturn:(id)sender{
[sender resignFirstResponder];
}
-(IBAction)goPressed:(id)sender{
[qrImage setImage:[UIImage imageNamed:#"qr.png"]];
}
In the Interface Builder MainStoryboard.storyboard I have established the relationship in the view's First Responder for the textbox's textFieldReturn and button's goPress to corresponding events and I have linked textbox as the deligate of this view. Now do i have to connect UIImageViewer to the `First Responder as well ? If yes how ?
I think you may be using a few terms incorrectly, but there are two different types of connections you can make between a view in Interface Builder and the code. When you say you "established a relationship" between the 1st reponder and the button and textfield, it sounds like you connected their Actions. What that does is creates a path from the view (button, text field, etc), to the object you connected it to (in this case, the first responded, which is essentially the abcViewController). Think of this as a one-way path; all it is does is tell these controls (the button and text field) where they should send a message when it's time to, because and event happened. So when the button get's clicked, it has a built in behavior of sending a message somewhere, if it's connected. You've connected it to the goPressed: action on abcViewController, so that's what it does.
The other side of the coin is making sure the view controller can send messages back to the controls. That's what outlets are for. It doesn't sound like you've set up any outlets, so the abcViewController has no way of sending a message to the image view that it should show up, or change it's image, or anything.
First thing you should do is define your properties as IBOutlets also, so like:
#property (noatomic, retain) IBOutlet UITextField *code;
Then when you go back to Interface Builder, if you go to the connections tab of the inspector, when the First Responder is selected, you will see it list out all of it's outlets. You will want to connect (drag from the dot) the outlet on the first responder (abcViewController) to the corresponding view. This creates a path from the view controller to the view (the opposite of what you did with the action).
Once that's done, if you tell the object to do something in your code, that message will get shuttled along to the object that gets created from the XIB when your view gets loaded up.
First you need to make sure that your view controller class is linked to the view controller you have created in your storyboard.
Then linked the objects you declared in code to the objects in your storyboard is drag and drop as it was with xibs.
Related
Using Xcode 4.3.3, I can't figure out how to connect outlets in a custom UIView class with objects created in Interface Builder.
In one ViewController, I have a variety of buttons, sliders, etc that I'm trying to group into Views. So, within that ViewController in IB, I added 3 views. Only 1 view will be visible at any given time.
I derived custom UIView classes to handle each of these 3 views. My view controller instantiates each of the classes. I selected the view(s) in IB, opened the Identity Inspector and set the Class(es) to my custom class(es). But when I tried dragging connections from the view and/or it's constituent controls to the custom view's .h file IB won't add a connection.
IB allows me to add outlets/actions by dragging to the parent view controller's .h, but not to the custom view's .h file. I thought once I set the View's class to be my custom class, I could drag outlets for the view's components to my custom class rather than in the view controller.
This question seems identical to mine: how to connect UIview outlets to a custom subview The two solutions (manually adding outlets and setting the view's class in IB) did not change the behavior for me. Here are the manual outlets I added:
customView3.h
#import <UIKit/UIKit.h>
#interface customView3 : UIView
#property (retain) IBOutlet customView3 *view3;
#property (retain) IBOutlet UISlider *slider;
#end
customView3.m
#import "customView3.h"
#implementation customView3
#synthesize view3, slider;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
#end
What am I missing here? What else do I need to set/check in order to add outlets to my custom UIView rather than the view controller?
Note that I did get this to work today, but had to insert/type the outlets by hand in the derived class, then I could drag from the header file to the UI element in the Storyboard, but not the other way around.
I opened a bug with Apple. If anything interesting happens, I'll update this answer.
Updated 10/4/13: After much research, it seems the root of the problem is that IB believes that I'm trying to connect objects to properties within a class, that I'm going to then create a swarm of instances of this class and then IB won't be able to tell which instance should handle the messages. So, it disallows the connection on the belief that I'm (potentially) making simultaneous connections from one object to multiple copies of a property across several instances of the class.
My view is that I only want a single instance of the custom UIView, and that I should be able to tell IB, "don't panic, you're only dealing with this one instance."
I'm now focused on a new project and haven't had a chance to retry this in Xcode 5; however, given the info above, I'm not optimistic it will work in Xcode 5, either.
What you're trying to do is certainly both sensible (IMO) and possible. XCode is however quite quirky when it comes to establishing connections to outlets in subviews.
I've found that cleaning, rebuilding and sometimes restarting XCode tends to help, but sometimes it just doesn't work. In some cases I got it working by manually creating the outlet and dragging from the outlet to the control rather than the other way.
This is not very helpful, I know, but I just wanted to make it clear that this is supposed to work and when it doesn't it is most certainly due to a bug in XCode.
In my experience, you add IBAction and IBOutlet to subclasses of UIViewController and not subclasses of UIView. So within the MVC model, your "1" UIViewController has all of these IBOutlets in it and then you use the data from these IBOutlets to update your views.
So you are fine creating the UIViews objects in IB and then creating the corresponding classes in code and then changing the class of the UIViews objects in IB to your UIView subclass. Just put all IBOutlets in the UIViewController that has all the UIViews under it, get the values you need from the IBOutlets and then pass them down to (set them in) your UIView subclasses.
Hope this helps.
I had the same problem and found a workaround:
1) Open the Assistant Editor with customView3.xib on the left and customView3.h on the right
2) ctrl + drag from UISlider in customView3.xib to the customView3.h code on the right
3) An option to create a new Outlet connection will pop up.
4) Name the connection and click connect
It will then create a connected IBOutlet.
Just starting out with an iPhone application using xcode 4.2.
I understand that it is good practice to use a subclass of UIViewController for each view in my application, and I am able to write some basic code in these to test buttons etc on the associated view.
Now I want to perform some action on a text field in one of these views, let's say I will use the Value Changed event to log the textfield's contents on each keystroke.
Should I be creating some kind of UITextField controller subclass? Or do I deal with this kind of thing in the existing ViewController subclass that houses the textfield?
If the latter, how do I refer to the textfield in the view controller subclass, and make the connections?
You'll probably want your UIViewController to implement UITextFieldDelegate. Connections can be made via the Interface Builder and outlets or just setting the delegate on the text field and using the reference you get from the delegate callbacks.
You would use the existing ViewController subclass that houses the textfield. A good rule of thumb is one ViewController per screen of views (not including UINavigationController, Modal screens, uisplitviewcontroller, and popovers).
To refer to it, you would make a property in the .h of your custom UIViewController:
#property (nonatomic,weak) IBOutlet UITextField * myTextField;
Note the IBOutlet keyword. This will allow you to connect it in InterfaceBuilder (or your storyboard). To learn how to connect that I would recommend you watch a video about IBOutlets since its more of a visual thing.
This is my second question today and the first was an incredibly stupid question so I'm fully expecting this one to be as well.
I have a view with an embedded MKMapView.
I want to some how be able to get at this MKMapView? Can I connect it up someway in the xib file? Or failing that ... can I just extract it directly from the parent view controller?
I want to do things like use setCoordinates but I can't figure out how to get at the MKMapView instance to call the function on.
How do I get at the MKMapView object.
In the place that you want to get at it from, set up an outlet. In the .h file, declare a mapview property
MKMapView *mapView;
then declare its property with an IBOutlet
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
You should be able to control-drag from File's Owner in your IB file to the mapview in your view to make a connection. Select "mapView" in the popup that appears and your file will be connected to the mapview object. Then you can use the property mapView in your .m file to set things on the mapview.
[self.mapView setCoordinates:myCoordinates];
Make sure you import your framework properly too.
It sounds like you are using Interface Builder to display this MKMapView. To be able to get the instance of MKMapView that is onscreen, follow these steps.
1) Open the .h file of the view controller for the view that contains the MKMapView.
2) In the instance variables section, add the line
IBOutlet MKMapView *mapView;
3) Go back to interface builder, and click on the map view you added to the XIB
4) Press Control, and while holding it down click and drag on the map view. This should make a blue line follow your mouse from the spot on the map view.
5) Drag the blue line over to the list of objects in your XIB. For a normal view controller xib, this list should be something like File's Owner. First Responder, and View. Unclick on the 'Files Owner' object.
6) This should bring up a list of connections. Click on the one that says 'mapView'
7) Profit! Now inside of your view controller, you can access the instance of the map view by using the mapView instance variable.
Make sure you set your delegate methods for the MKMapView and the methods should fire on your delegate class.
If I have a UIScrollView set up in the view via the Interface Builder, how do I get a reference to it in the ViewController implementation? I want to programmatically add labels to the scroll view.
For example, in C# if you have a textbox declared in the UI/form, you can access it by simply using the ID declared for that textbox. It doesn't seem this simple in objective c.
Thanks
Kevin
Assuming I understand you rightly and you are instantiating a view controller from a .xib containing subviews including the UIScrollView you want, there are two ways - first, you can find it in the subviews array that is owned by the view controller. Second, you can add an IBOutlet reference to it in your header file, then in interface builder make the connection using the connections inspector. Then you can refer to the object in your code, change frame, add labels etc.
You need to wire your ViewController up to your Nib files. This is pretty straightforward. This is your basic workflow for using Interface Builder on the iPhone/iPad:
Set the Class of the 'File's Owner' to the class of your view controller. You can do this by selecting the 'File's Owner' object in your nib window, pressing Command-4, and setting the class via the drop-down.
Create properties in your View Controller with the following format:
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
The IBOutlet keyword is a macro that evaluates to nothing. So it doesn't actually do anything to your code, it just exists to let Interface Builder know that the 'scrollView' property can be bound to.
Control-drag from the object you'd like to bind to your ViewController. In the popup you can select the property you'd like to bind to the scroll view object.
This sort of stuff is pretty basic Xcode stuff. If you read any tutorial out there it'll cover this. Good luck, and enjoy!
edit:
I should add that if you used the default "New UIViewController Subclass" from the New File dialog, it will have done step one for you. You'll have a nib file and a View Controller that already know about each other.
Yes, the code you wrote is all you need in your header. Just make sure you connect the Scroll View object to the property in Interface Builder.
Yup! 'viewDidLoad' is added after all the connections specified in the Nib file have been made, so you can be confident that scrollView point to the correct object (assuming everything in the Nib is wired correctly, which is an easy mistake to make)
I am developing an application that currently has a View Controller (call it ViewControllerX). The MainWindow.xib file contains the following:
File's Owner UIApplication
First Responder UIResponder
AppX App Delegate myAppDelegate
myViewControllerX myViewControllerX
Window UIWindow
When I look at the MainWindow.xib in Interface Builder it shows View Loaded from "myViewControllerX". The myViewControllerX.xib file for this contains the following:
File's Owner UIApplication
First Responder UIResponder
MainView UIView
Image View (image1.jpg) UIImage View (Inside MainView)
Rounded Rect Button UIButton (Inside MainView)
Rounded Rect Button UIButton (Inside MainView)
Table View UITableView (Inside MainView)
On the Table View, I have the Outlets set to dataSource = File's Owner and Delegate = File's Owner. The Referencing Outlet is set to mTableView which is defined using IBOutlet in XCode. When I run this all works fine and the table gets populated.
When the users clicks an Item within the Table View I want a new view to slide into place, which also contains a TableView (basically the first View Controller shows an overview list, when the user clicks on an Item I want it to show the details of the choice). In the myViewControllerX.m file, I have the following code:
- (void)tableView:(UITableView*)theTableView didSelectRowAtIndexPath:(NSIndexPath*)theIndexPath
{
[self.navigationController pushViewController:self.mViewControllerY animated:YES];
}
I have created a ViewControllerY and have the following files:
ViewControllerY.xib, ViewControllerY.m and ViewControllerY.h.
In the .xib file for ViewControllerY, I have:
File's Owner UIApplication
First Responder UIResponder
Table View UITableView
When I run this it works (so the code and the hook-ups in Interface Builder are ok). The Problem is it takes over the whole of the view whereas want I want it to have an Image (and other UI objects) as well as a Table View. I've tried changing the UITableView of ViewControllerY to be of type UIView and then adding an UIImageView and UITableView inside of the UIView in a similar way to ViewControllerX but I can't get it to work and now I'm not sure what to do! So, my question is, how do I go about Implementing this? I'd like to be able to have it setup in Interface Builder, so how to I change it to handle this? e.g How do I hook up the dataSource, Delegate and Outlets etc.
Thanks in Advance for any help in this. I've tried all kinds of things but I just can't seem to get it to work. I'm sure I'm almost there and must be missing something that is very obvious!
All the Best
Dave
Your UINavigationController uses a content view that more or less completely covers your device screen. And this view is used for your main view. If you ask this UINavigationController to push another view, he uses this very same view to swap in the ViewControllerYs view which also covers the complete screen.
To gain the behavior you need, you should create a second "embedded" Navigation Controller instance which is responsible only for that part that is initially by your table view. Display your table view as the main view and then ask this Navigation Controller to swap in your other views into this part of the screen.
After taking a step back and doing a bit more digging, I came up with the answer.
High Level Explanation.
ViewControllerY needs to be of class UIViewController, not UITableViewController. The ViewControllerY : UIViewController definition in the .h file should include the Table View Delegate and the Data Source protocols. A member of the ViewControllerY has to hold the UITableView* - call it mTableView and should be defined as an IBOutlet.
The table view delegate methods should then use self.mTableView to access the table.
In Interface Builder, the UIView Object needs to have an Outlet "view" hooked up to the File's Owner and the Table View inside the UIView needs to have the dataSounce and the Delegate set to File's Owner and the mTableView Outlet also needs to be hooked to the File's Owner.
Low Level Explanation.
in ViewControllerY.h do the following:
#interface ViewControllerY : UIViewController <UITableViewDelegate,UITableViewDataSource>
{
UITableView* mTableView;
}
#property (nonatomic, retain) IBOutlet UITableView* mTableView;
In ViewControllerY.m, in the Table View Delegate methods, access the mTableView like so:
myNewCell = (UITableViewCell*)[self.mTableView dequeueReusableCellWithIdentifier:myCellIdentifier];
(obviously you need to define and handle all the other Table View Methods in the normal way.
ViewControllerY.xib should have the following in it:
File's Owner ViewControllerY
First Responder UIResponder
View UIView
Image View UIImageView
Table View UITableView
Control Drag from the File's Owner to the View and select "view".
Control Drag from the Table View to the File's Owner and select Data Source.
Control Drag from the Table View to the File's Owner and select Deligate.
Control Drag from the File's Owner to the Table View and select mTableView.
That's it! You can then add other UI objects inside the UIView and hook them up as appropriate in the normal way. I'm not sure if this is the only or best solution but is works and I'm happy with it.
Hope this helps someone with the same or similar problems. It's a bit confusing til you get the hang of it.