I'm fairly new at this, but I think what I'm looking to do makes sense. I have a xib that is displayed in portrait and one that is displayed in landscape. Both views are similar, but have a few differences. Some of the buttons, labels and textfields are the same.
I can reveal one and hide the other when the orientation is changed - that's not the problem.
Basically I'm looking to have one place where I can handle all of the common button click responses or text changes. When a user is in portrait mode and enters text or selects a button, then they change to landscape mode the corresponding buttons and text will be updated.
I tried adding an NSObject in interface builder and assigning it to a new class that has outlets and actions for the buttons and textfields, but when I interact with a button I get an "unrecognized selector sent to instance" error in xcode.
Any help would be great.
Best,
Ward
Objects you add in Interface Builder are instantiated when the XIB loads, you cannot have the same object in multiple XIBs.
What you use to connect multiple XIBs is the "File's Owner" object you see in each XIB. When you load a XIB using [NSBundle loadNibNamed:#"myXIB" owner:self] then what you pass in as owner object is ending up as the File's Owner in the loaded XIB and Cocoa will connect the IBOutlets and IBActions you have in it (be sure to set the proper class of the File's Owner object in Interface Builder).
So then you could make the controller object of your landscape view the owner of the portrait view XIB and put all IBActions in that controller, where they will be accessible from both XIBs (through the controller in one and through the File's Owner in the other).
Don't forget that xibs aren't templates — they are freeze-dried objects. A button in one has no connection to a button in the other.
Related
I'm trying to create outlets using the Interface Builder, however when drag the UILabel from the IB to my controller's .h file the big lock symbol flashes for a few seconds and it doesn't actually create the bind between the UILabel and the outlet (although the code is generated). I also noticed an empty circle is created by this new definition. When it worked, a filled in circle was created on the side).
I've checked the UILabel and all parent views and have checked that their "Lock" property is set to "Inherit (Nothing)" (and have even set them all to "Nothing").
In the IB the UILabel doesn't show the "x" that appear when a UILabel is locked either.
So I have no idea if I'm missing to unlock something, or what I'm doing wrong to be able to create this outlet.
I don't know if this is relevant, but I'm using a custom view controller, and I'm using this same view controller subclass for 2 different view controllers in the same storyboard. I had no problems creating outlets this way for the first view controller.
Tryed reopening XCode (using 4.4.1) with no luck.
Any help is appreciated!
So are you dragging both UILabels from each View Controller into the same file? I don't think that this is possible, on the second view controller, try to Ctrl drag to the file owner within the IB view, that is, assuming that both views are connected to the same instance.
Also, in your identity tab in storyboard, under Localization Locked, make sure your storyboard locked setting is set to default as mentioned in https://stackoverflow.com/a/11169636/720175
I tried adding a totally new scene and would also get the lock symbol. So it wasn't only the scenes, but the whole storyboard. So a quick search on SO lead me to the answer:
https://stackoverflow.com/a/11169636/720175
My View has a button, myButton, in my XIB. In the XIB the File's Owner is of class HelloWorldViewController. And the view for File's Owner is my View in the XIB.
In the HelloWorldViewController(which resides in MainWindow.XIB) I have - (IBAction) doMyButton:(id)sender and I have the corresponding definition in the HelloWorldViewController.h file.
For my View I have Events (again in the XIB) Touch Up Inside --> File's Owner doMyButton.
For File's Owner I have Received Actions doMyButton --> Rounded Rect Button Touch Up Inside.
I have a debug point on the first line of code that is inside the 'doMyButton' method. When I touch the button (with my mouse in the simulator) I do not hit my break point.
WTF?
Screen Captures of IB if it helps:
Overview
Properties Of Button
If every thing is fine then you are not setting the break point i.e. you are running your code using cmd+R use cmd+y or cmd+enter. cmd+r will run without considering your break points.
Do any of your IBOutlet items function?
If they don't (and since you renamed your XIB file), be sure the File's Owner has the correct custom class set in the interface builder. Otherwise it could be calling the wrong class which could be why your break point isn't firing.
Note: This is unlikely as such an issue should cause a build problem, but I've seen stranger things happen.
Thanks to a co-worker I found out what the problem was. The view I had with the button was in my HelloWorldViewController.xib as it is supposed to be. However, I had drug that view into the Main.xib to be the primary view for the NavController I had setup. I was editing the view in the HelloWorldViewController.xib when I should have been editing (read: making the connections) in the Main.xib where the view was duplicated for the NavController.
I assumed that NavController was simply pointing to the other XIB where my original view was defined, not running off a copy of it. Kind of messed up for a newb perspective.
Can anyone summarize the relationship between the following items?
Content View
View Controller
Nib
the view, subclass of UIView
Application delegate
I got very confused about these. Coz some people say the "content view" contains the "nib" while other people say "content view" and "nib" are not containing each other.
Many thanks!
Oh man… that's not so easy. But I'll try.
Application is being launched from main().
Application delegate receives callbacks from Application during runloop. For example, when app finished launching or something else.
Usually application contains single instance of UIWindow, that is the root of all view hierarchy.
UIWindow can have UIViews, they can have UIViews by themselves. So, there's a hierarchy of UIViews (a tree)
Each view has controller, that gets user input and other events and controls UIView (for example, tells it to redraw itself because of user tap). Controller can be standard or custom, written by developer.
Content View is a normal view. Usually within a table cell. UITableViewCell instance has a property that is called contentView. It's a normal view and it can be any UIView subclass.
NIB is another story. You can create whole view hierarchy by yourself. But there is an alternative way: use Interface Builder. After creating views/subviews in the interface builder — you can save this hierarchy with all its properties as a single (serialized) file. And load it at once during application run.
NIB has three main objects. File Owner is an object, that you'll get when you send some message like
+ (BOOL)loadNibNamed:(NSString *)aNibName owner:(id)owner
Here owner will be filled with all properties of File Owner from the NIB.
First responder - first receives input. You can simply forget about it for now.
View — is the main view. Usually it is linked to a view property of File Owner.
It's a veeery short overview of all these things. You really have to read documentation to understand it better.
In Interface Builder... when I drag a VIEW into the document window... and then double-click on it... it opens and displays the VIEW window. (As expected)
... but when I drag a VIEW CONTROLLER into the document window... and then double-click on it... it also opens and displays the VIEW window, too. (It says "view" right on it.)
Is that right? (Or am I totally misunderstanding things?)
I thought a VIEW was the actual object to draw/drag things into. No?
I thought a VIEW CONTROLLER was just the CODE for your view. No?
I dont have experience with Interface Builder, but a a controller object provides the custom logic needed to bridge the application’s data to the views. In iPhone applications, a view controller is a specific type of controller object that you use to present and manage the views of your application.
Each ViewController has a View property associated to it, which is the one you are seeing in interface builder.
The view stored in this property represents the root view for the view controller’s view hierarchy. Whenever you present the view controller on screen (either modally or as part of view controller–based interface), this view is retrieved and displayed in the application window. The default value of this property is nil
Each view controller object is the sole owner of its view. You must not associate the same view object with multiple view controller objects.
Apple wants you to follow the Model-View-Controller system when you develop apps, and it's pretty straightforward and logical.
The Model is the core of your app. It processes databases, network connections and whatever you need. It's basically custom classes you create in Xcode.
The View is the interface between your app and your users. You can create them in Interface Builder and put them in NIB files (preferably one view every file).
The Controller is the glue between your view and your model. It defines the behavior and state of views (button enabled, label content, etc.) based on what it gets from the model (like a database). It also performs actions on the model based on the events it receives from the views it managers (controls), like changing records in a database or changing variables in objects.
The idea behind all this is that the model can be used in every platform with minimal modification.
Every controller should be linked to one view, and one view only, like a table (UITableViewController) or a screen's view (UIViewController). You subclass the controller you want and you add it to the NIB of the view it's associated with. That's how you do it:
In the NIB, select the File's Owner.
In the Identity inspector, set the class to the view controller you created in your project.
In your custom controller class, create IBOutlets for every view (such as deleteButton) in the associated view you need to have access to. Create and synthesize the properties for every outlet.
Create IBActions for every event you want to register (such as addButtonClicked).
In the NIB, drag a line with your secondary mouse button from the File's Owner to the wanted outlet view and then select which connection you want to make. Repeat until all your IBOutlets are properly connected.
Drag a line with your secondary mouse button from the view you want to register events from to the File's Owner and then select which connection you want to make. Repeat until all your IBActions are properly connected.
Write your code for the controller.
I am trying to send actions from button touches to a controller other than the one acting as File's Owner. I have four distinct areas of the screen that I would like managed by four separate controllers (buttonController, toolbarController, textController and graphicController) with a fifth controller (mainController) controlling the other four. mainController is also the one associated with File's Owner. To get button presses to be handled by mainController is easy:
MainController.h file:
- (IBAction)buttonIsTouched:(id)sender;
MainController.m file:
- (IBAction)buttonIsTouched:(id)sender {
..handle button touch event etc.
}
Then in Interface Builder, associate the button Touch Down event with File's Owner and select buttonIsTouched and away you go. All works fine.
However, when I do exactly the same thing for a controller that is not the File's Owner controller the application crashes. Here is what I did:
Create four controllers as instance variables of mainController.
Instantiate them in -[MainController viewDidLoad].
Provide a button handling method exactly as above
In Interface Builder, drag an Object template from Library (four times) onto the mainController.xib browser.
Set the type for these objects to ButtonController, ToolBarController, TextController and GraphicsController respectively.
Associate the Touch Down button event with the ButtonController object and select the buttonIsTouched entry (in the little pop-up box)
Build and run the application
Click the button
Crash - sorry, I didn't write down the error code but it was akin to INVALID_ACCESS
Of course, I can have all the input go first to mainController and then delegate down to each individual controller but this seems an inelegant solution especially since I want the lower controllers to do some work before messaging upstream to mainController. Having to go through mainController and then back kind if irks me.
If anyone knows how to do this and has some sample code that does something similar to what I want to do I would appreciate it.
ac
One problem of your approach is that your instantiate two objects for each of your four sub controllers ButtonController, ToolBarController, TextController and GraphicsController. You’re creating the controllers programmatically in viewDidLoad, but they have already been instantiated from the loaded nib.
You shouldn’t create the controllers in viewDidLoad, but instead use retaining IBOutlet properties in your MainController to wire them up in IB.
Then the controller objects are owned by the MainController and are not removed after nib loading. This will also remove your memory error.