Still fuzzy on creating objects in Code, IB, and combined - iphone

I'm still quite new to Xcode etc, so Im a bit fuzzy when it comes do creating/using objects in Xcode.
For example, I used a tutorial for creating a GestureRecognizer in code - it's pretty simple.
Right now I have only this in my .h:
#interface PlayPage : UIViewController <UIGestureRecognizerDelegate>
And this in my .m:
UITapGestureRecognizer *tapTwo=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doubleTap)];
[tapTwo setDelegate:self];
[tapTwo setNumberOfTapsRequired:2];
[tapTwo setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:tapTwo]; //adds it to view
Here are my question(s):
1) If I also want to see the GestureRecognizer in IB along with the above code (perhaps so I can change some settings since I'm not familiar with everything) how do I accomplish that?
2) How would you decide when to use all code vs. a mix of code/IB ? Is it strictly a matter of style/comfort/familiarity?
3) It seems declaring different objects requires different 'setup' code (UITextLabel vs GestureRecognizer vs UITextField,for example) - how do you know when to use which code?
Thanks for helping to clear this up.

In Xcode 4.x Interface builder there are UIGestureRecognizer objects that you can drag onto your views. So you would need to add the UIGestureRecognizer in Interface builder (if you need to do any more config in code then connect them up with an outlet as well).
I try and do anything I can in IB and drop to code when I have to but it is a matter of preference.
I'd rather eyeball the position of views and use the snap guides than spend a while figuring it out in code.
You can hide a lot of boiler plate code if you do it in IB
Start typing and look at the autocompletion options to jog your memory. But more importantly every time you use a class you have not used before you should at least skim the documentation to see what is suggested. Half of the questions on this site could easily be solved if the question poster actually bothered to look at the vast documentation available.
Update
You need to create the UIGestureRecognizer in Interface Builder not your code.
In Interface Builder ensure that the Utilities pain is visible and drag and drop a UIGestureRecognizer of the required class onto your view
This is what the UIGestureRecognizer class look like:
You then configure the object in the Utilities panel. If you want to be able to access this object in your code then you will need an IBOutlet.
In your classes header file add a new ivar for this
#property (nonatomic, retain) IBOutlet UITapGestureRecognizer *tapGestureRecognizer;
In the implementation file synthesize this
#synthesize tapGestureRecognizer = _tapGestureRecognizer;
Then back in Interface builder connect this up by ctrl + click + dragging from the File's Owner to the UIGestureRecognizer subclass. Then selecting your ivar from the window that appears:

Related

how to update label/textfield of storyboard uiviewcontroller from controller.m?

I am new to iphone development, and i'm currently using xcode 4.2.
I drew a UIViewController into the storyboard. I put some labels into the UIViewController. It is associated to a controller.m file.
How do I, from the viewdidload function of the controller.m file, update the text in the label?
I don't know how to get the variable name or handle name of the elements in the uiviewcontroller on the storyboard.
If you are creating things through storyboard, the easiest way is to create an IBOutlet property for each UI element. This creates an instance property for the UIElement which you can then reference in your code - to set state, get values, etc.
You can do this through Control-click-drag on the UIElement to your UIViewController.h file (split view: RETURN-Command-Option: to display counterparts). XCode will pop up a dialog enabling you to name it (the same gesture will also enable you to create IBActions - the function that is called when the UIElement gets interacted with). You can also Control-click-drag on the left sidebar listing of the UIElements in your ViewController if that is easier.
There are YouTube videos that show it better than my weak explanation. I was skeptical # storyboard/IB at first because I don't like UI magic and prefer to do things through code, or at least see the code that results from the magic, but it really does work pretty well and saves some of the tedium of UI coding.
One gotcha to be aware of: if you make an IBOutlet and then delete the UIElement, you will have code errors because of the errant reference. Those are easy to find and fix. The UIViewController object will also contain those references and will result in unpleasant crashes - so Control-click on the UIViewController object (or use the Inspector panel) and any element that has an orange triangle == broken.

How can I access various UIViews within a Nib, programmatically?

First, I am super-new to Objective-C/iOS development and, in fact, this question is for my first, test project. Also, I come from a C#/WinForms background so I'm coming into iOS development with certain pre-conceived notions of user interface design and application state. Please bear with me and help clear up my confusion.
I just created my first iOS application project which, consists of a Single View. I allowed Xcode to create all the files for me through the Single View project wizard. When it was finished, I opened my new applications, single UIView Nib file in the designer and I dropped three sliders onto the view.
The desired purpose of this application is very simple-- each slider corresponds to either the R, G or B values associated with the background color of my view.
I have figured out how to set the background of my view but I can not figure out how to access the values of each slider objects. Yes, I can hook-up and respond to an IBAction for each slider, but my plan is that each time a slider's value changes, I want the IBAction to call a refactored method that accesses the values of all three sliders and then set's the views Background Color based of the values associated with each one.
How can I access the values of my sliders? Specifically, how can I access the value of the sliders that I created by dragging and dropping them into the Nib designer window? I've seen code explaining how to programatically add a UISlider to your UIView and then access the value, but how do you access the value of a UISlider that's added to the Nib and, I assume, will be automatically "wired" in at compile time?
Hopefully this makes since? If I'm missing an intermediate step or critical concept, please let me know.
You create UISlider ivars/properties and make them IBOutlets:
#property (nonatomic, retain) IBOutlet UISlider* yourSlider;
You synthesize it in your .m file and the connect the IBOutlet in interface builder. The yourSlider pointer is then a reference to the object you connected it to. Note that it will only be loaded with the view of the UIViewController and therefore will be nil until viewDidLoad is called. You also must set it back to nil
self.yourSlider = nil;
in your viewDidUnload method (so that it is released). In Xcode 4 you have a convenient way of doing all the above steps in one action (see the "Interface Builder is Built-in" of What's new in XCode 4)
Similar to CTRL+dragging from the UISlider to the .m file to create the IBAction, you can CTRL+drag the UISlider from your .nib designer to the associated .h file and have it create a property for you. Then, from your .m file, you can access self.mySlider (or whatever you name the property).
There's a video on this page that shows binding to a UISlider specifically.
Another approach is to use the tag property of a view.
#property(nonatomic) NSInteger tag
- (UIView *)viewWithTag:(NSInteger)tag
You can set the tag property of a view in the interface builder and later reference that view in your controller.
UIView *myViewFromTag = [self.view viewWithTag:theNumberYouSetInIB];
In general, it's better to stick with IBOutlets. However, there are certain situations where it makes more sense to use tags.
Good luck!

Overwriting UINavigationBar to set a default titleView

What I want to do is a navigation bar with a image on it. I have a tab controller on my main view, and inside each tab I have a UINavigationController. From inside the UIViewController that my tab/navigationController calls, I could set the titleView without much problem, doing this inside the viewDidLoad method:
self.navigationItem.titleView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"mylogo.png"]] autorelease];
But, I want to replace all titles in my navigationBar for this view, and it seems ugly to repeat this everywhere. So I did this on the delegate (after linking all the Outlet stuff)
self.tabOneNavController.navigationBar.topItem.titleView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"mylogo.png"]] autorelease];
Again, it worked! ok, I'm almost getting there.
But the point is, I've 5 tabs and all of them have navigationControllers inside. I reduced the code repetition from every internal view to only 5 times, but it still. It requires that I do that for the NavController of each tab.
Then I tried to extend the UINavigationBar to create my own, where I could set this in the initializer, and use it in the interface builder as the object class. But it doesn't seem to work. Here is what I did:
#implementation MyNavigationBar
- (id)init {
self = [super self];
self.tintColor = [UIColor greenColor];
self.topItem.title = #"testing please work";
return self;
}
#end
in the interface file MyNavigationBar inherits from UINavigationBar. But this didn't work. Should I overwrite other method? which one? is this a good practice?
I'm not even sure if I should add one navigationBar for each tab, as I said, I have tabs and I want to have a navigation bar / navigate inside them. By now, after a near death experience trying to figure out how the interface builder / outlets and classes work, the code is working, I just would like to make unglify it.
Thank you!
The problem of repeating code which you describe has an elegant solution. Objective-C supports something called a "category", which allows you to add methods to a class. A common use for this is to customize navigation and tab bars. In Xcode 4, you would do something like this to add a category on UINavigationBar:
Hit Command+N or open the "New File" dialog. Next, choose "Objective-C category" from the Cocoa Touch menu:
Click Next and you will be prompted to enter the name of the class that you would like to add methods to as a category. It should look something like this:
Then, you should end up with a save file dialog. A quick note about convention here. Convention is to name a category after the original class, the plus sign, and then a description of what you're adding. Here's what yours might look like:
Once you save your file, you will need get something like this:
Look at that beauty. You can now override the default drawing/init methods as well as extend the functionality of the navbar.
I'd suggest looking into the init and drawRect methods, although I don't remember which ones people use. Also, please note that while under NDA, this may change in iOS 5, so just be prepared for that possibility.
Why not define a UIViewController subclass which sets the title view via self.navigationItem.titleView and have your other view controllers extend from that class? Then you're sharing that behavior across all of your controllers without repeating the implementation.

(iPhone,Obj-C) Where does this "view" property come from?

I ran across this segment of code (in .m implementation file in an IBAction instance method):
UIActionSheet *actionSheet = [[UIActionSheet alloc] ...];
...
[actionSheet showInView:self.view];
self refers to the button but I wanted to know where I could find out about this "view" property since I looked up UIButton, UIView, NSObject, but could not find out where this "view" property came from.
(also, any corrections on terminology would be appreciated since I am trying to learn all the correct terms - I'm a beginner iPhone programmer)
The view property is one of a UIViewController. The controller usually creates a view in its initialization, and is responsible for managing it. Any subclass of UIViewController will inherit this property. See this link for more details. Also, you may want to familiarize yourself with MVC(model view controller), as this might make it more clear why the controller has a view property. See this link for more details.

Arbitrary objects to handle actions?

My question may be a bit stupid, but why can't any object instantiated in IB handle, say, button click? I mean I'm able to add my own object to a xib, and link outlets to cotrols and control actions to object's method, but once I press the button everything just crashes (uknown selector).
Do you guys have a hint around that?
EDIT: The code, as requested:
#interface TextController {
IBOutlet UILabel * textLabel;
IBOutlet UITextField * textField;
}
-(IBAction)buttonClicked:(id)sender;
#end
#implementation TextController
-(IBAction)buttonClicked:(id)sender {
textLabel.text = #"Ololo";
}
#end
Connections in IB are ok, just believe me. It's really hard to get them wrong with all this drag'n'drop stuff :)
EDIT 2: TextController is not a file owner (in this case it works fine). However, I just want to understand why I can't wire up an action to some object (may be even not a subclass of UIViewController).
You can wire outlets and actions to any object in the nib-file. Drag an NSObject form the library palette onto your nib-file, in Interface Builder. Then go to the Identity tab of the information palette and set the Class of your object.
This way you can instantiate any object of any class from your nib. If the target you want to hook to is statically created from the nib-file. Make sure that the file's owner have at least one reference to your object, or else it will be deallocated as soon as it has been created. Targets are not retained by the sender.
If the object you want to hook up should not be statically created from your nib, then implement awakeFromNib in a class that is instantiated from the nib-file and hook up the targets in code.
Last option is if you do not have any sub-class of your own in the nib-file at all. Then implement initWithNibName:bundle: in your UIViewController subclass, and hook up your targets in code after calling the super implementation.
post code, this usually means you dont have your connections wired up correctly. Is file's owner TextController in IB?