multiple actions to one event on Interface Builder? - iphone

in my iphone app one event (touch up inside UIButton) is connected to three actions in different classes. The first action creates a game object, the second pushes the a new view controller and the third triggers an method in the pushed view controller.
On interface builder I wired these actions to the event in the order mentioned above but the app crashes sometimes when I press the button.
Does some body know if the order in which I wired the action on IB will be maintained at runtime in my device and others?

I'd guess that the order in which actions are called is not guaranteed to be the same order in which you wire them up in IB. Consequently, your app might be trying to configure the view controller before it creates it. You can verify the calling order by putting an NSLog statement in each of your action methods.
Even if the actions are called in IB order, that's a code maintenance nightmare; imagine coming back later to insert a new action in your UIButton and needing to remember the order in which you originally wired them up.
Solution: To enforce order, create a single IBAction method that calls the other three methods in the desired order.

Related

IBAction or [UIButton addTarget:action: forControlEvents:] for UIButton created in .xib file? Which is the better approach?

What is the better approach if we are creating a UIButton in the .xib file using the Interface Builder, is it better to use IBAction method to define its Action Method and the required Control Event, or should we use
[UIButton addTarget:action: forControlEvents:]
method to define the Action Method?
Which approach is better and why?
Yes. You can use any way.
Both of these methods begin with your existing eventreporter program. You’ll add a simple
UIButton to it using Interface Builder. Place the button a top the label at the bottom of your page and use the attributes tag to label it Reset. With it in place and defined, it’s ready to be linked into your program by one of two different ways.
Using addTarget:action:forControlEvents: with a button
On the one hand, you may wish to add actions to your button programmatically. This could be the case if you created your button from within Xcode or if you created yourbutton in Interface Builder but want to change its behavior during runtime.Your first step is bringing your button into Xcode. If you created your button inInterface Builder, as we suggested earlier, you need to create an IBOutlet for the but-ton, which should be old hat by now. If you didn’t create your button in InterfaceBuilder, you can do so in Xcode. This probably means using the factory class method buttonWithType:, which lets you create either a rounded rectangle button or one of afew special buttons, like the info button. By either means, you should now have a but-ton object available in Xcode.
Using an IBAction with a button
The other way you can link up actions to methods is to do
everything
inside InterfaceBuilder. This is the preferred choice if you’ve created your object in Interface Builder(as we’ve suggested) and you’re not planning to change its behavior at runtime.When you use this procedure, you don’t need to make your button into an
IBOutlet. It’s effectively invisible from Xcode, which is fine, because all you careabout is what happens when the button is pushed. You also don’t use the somewhat complex addTarget:action:forControlEvents: method that we just ran through; instead, you connect things via intuitive Interface Builder means.
It depends upon user which one to use.
Use xib to make easier and lots of code can be avoid to write.
Although any of the two can be used. The only reason I see it should be IBAction is because you have used xib. In this way you know that everything you have created is from xib. But once again, both are fine.

iPhone: Indication when ABPeoplePickerNavigationViewController has finished loading

I'm working on an app which allows users to send messages to people which can be selected from a variety of sections. One of these sections happens to be the contacts stored on the phone book (other contacts are selected from an online DB).
As such, I have a 'master list' of recipients. If the user, for example, chooses to select a contact from their online account, this will push a new view that will allow the user to select which contacts to add to the recipient list. When they go back to the master list, they should see the chosen participants selected there. If they were to return to add another person, the selected contacts should all be checked (each contact is displayed as a UITableViewCell).
This is working fine for all the online contacts however I'm having some issue implementing this functionality for local contacts using the ABPeoplePickerNavigationViewController. To check the selected contacts when the user returns to this screen, I need to have some way to now when the view has loaded.
Are any of the view delegates (i.e. ViewDidAppear) guaranteed to be called after the table has been loaded (I'm pretty doubtful on this one)?
If not, I had thought of counting the total number of rows in the datasource (using numberOfRowsInSection:) in a timer. If half a second or so has passed without the count incrementing, it should be a safe bet that all the records have been loaded. Somehow, however, I'm not so sure if this is going to work. It might be that all the records will be loaded in a single hit.
Any ideas on how to achieve this? Are my suggested methods workable? Is there a different workaround?
If you make view transition by standard methods, like presentModelView: or pushViewController:, then the methods about viewWillAppear:, viewDidAppear, viewWillDisappear:, and viewDidDisappear will be called. But if you make view transition by UIView's instance methods, like +transitionFromView:toView:duration:options:completion etc, then you have to call those viewWillAppears methods manually.
All UI related method will run in main thread, and ABPeoplePickerNavigationController is a sub-class of UIViewController. When it's view has been loaded, it will call -viewDidLoad. At this moment, it means the view has been loaded, maybe this view doesn't appear. So, the -viewWillAppear: should be executed after -viewDidLoad. But, the -viewDidLoad maybe executed before return from -init in practice. In my experiment, I set view's backgroundColor inside the -init, then when I use self.view.backgroundColor = [UIColor black], at this moment the view has been loaded. It means the -viewDidLoad will be executed when I set background color of view.

How to communicate between objects

Still having trouble with this language.
Ok, let's say I have two objects. The first is my application delegate, the second is a custom view containing the various buttons that make up the main menu. When a button is clicked, it is the menu that responds. However, I need to make use of certain instance variables in the application delegate (such as the Window) in order to implement the appropriate changes. In this case, I want the main menu to be removed and replaced with a new view. In other words, the main menu needs to trigger a method held in the application delegate.
So, how should I go about this?
I did a blog post on my web site a ways back that distills the process down into the simplest way I could come up with to describe setting up a delegate.
http://www.dosomethinghere.com/2009/07/18/setting-up-a-delegate-in-the-iphone-sdk/
The preferred way is to create a delegate protocol for your view controller. Your application delegate can then implement this protocol and act on behalf of your view controller.
Check out the part about Delegation in the Cocoa Fundamentals Guide. Also read through the docs about Modal View Controllers, as this is quite similar to what you're trying to do. There are some code examples there as well.

Actionscript style events in Objective-C?

I'm a newbie doing Objective-C, coming from Flex/Actionscript development.
I have an iPhone app with an UIApplicationDelegate conforming delegate called MyAppDelegate - it has a UIWindow.
Instead of adding buttons, labels and whatnot directly to the window, I guess I'm supposed to make a child class of UIViewController for every screen I wanna make. When that screen should be displayed, I add the respective controller's view to the window as a subview. When another screen should be displayed, I should pop off any other view from the window and add the new view. Hope I got everything correct so far...
My intent is to make each view controller only know about its own things, so let's say I wanna call view A from view B, in ActionScript I'd add a button in A firing off an event which would be caught in view A's owning object (could be the application), which could take proper action (remove view A, instantiate view B and display it).
How do I do this in Objective-C?
A UIControl, such as UIButton, can have any number of event listeners registered with:
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
The target would be the view controller you want to receive the method, and the action is the method you want called. For a button, events is usually just UIControlEventTouchUpInside. If the target is nil, the event will pass up the responder chain until a responder implements the action. If you pass #selector(buttonClicked:) then the target should have this method:
-(IBAction) buttonClicked:(id)sender;
The sender will be the button that was clicked. IBAction is equivalent to a void return type. You can bind the action in Interface Builder if you prefer that to doing it programmatically.
When another screen should be
displayed, I should pop off any other
view from the window and add the new
view.
This is basically correct, but usually you use a meta view controller like UINavigationController to manage view controllers. Even if you do not use the UI that a meta controller might present, it is convenient to have view switching managed for you.
If you're coming from Actionscript you may be interested in looking at the PureMVC framwork for objective C. Using PureMVC you'll create a combination of Mediators, Commands, and Models for application interaction.
With PureMVC you register notification with the facade, and you define listeners in your mediators to respond to these. This is pretty close to the event model you're used to in Actionscript. (At my last job we added some categories to the UIResponder to remove some of the cruft in doing this). If you're creating a considerably sized application, then I would recommend you give it a look; it certainly helped us keep everything manageable.
If you don't want to pull in a third party library then you should define your view manipulation code in your MyAppDelegate and use the [UIApplication sharedApplication] class method to access the globally shared instance.

How to send actions to targets other than File's Owner?

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.