I have some toolbar buttons in an Interface Builder .xib file, but clicking them does not call their corresponding IBAction methods in my view controller.
I know the view controller is connected to the nib, because test code like this in the view controller has the expected result:
self.saveButton.title = #"foo";
When I click the button, it shows the selected state, but then nothing happens when I release it. The method definition looks like this...
- (IBAction)save:(UIButton *)sender;
...and I see the connection in the Connections Inspector in Interface Builder. I have other buttons that work fine, and I don't see what's different about this one.
I had the wrong type for the sender argument in the IBAction method. I somehow had this:
- (IBAction)save:(UIButton *)sender;
But since a bar button item is calling this, it should be:
- (IBAction)save:(UIBarButtonItem *)sender;
After updating the code, I had to unlink and relink the button in Interface Builder. Then it worked!
I've been using this code for years on iOS with no problem, but apparently the Mac Catalyst platform is less permissive for an error like this.
I haven't seen many Mac Catalyst issues posted yet, so hopefully this will help someone in the same situation.
Related
I know the second button here shows the Assistant editor:
And I know how to make an Outlet and Action by Control dragging from an object in the Interface Builder to the View Controller code. Ideally it should be as easy as the documentation makes it look:
But this is usually what Xcode actually looks like for me when I press the "Assistant" editor:
A mess. I have to minimize lots of things, try to get the storyboard object in view, and then go find the right View Controller. All this before I can do the Control-drag.
Is there a way to make the connection without using the Assistant editor? (And preferably without having to type a lot of code in myself.)
Don't press the assistant editor button. Sometimes it opens a random file instead of the one you want.
When you are in Storyboard, Option click on the .h file that you want to open in the Project Navigator. This will open the proper .h file to add the outlets or actions.
When you're done, close the Assistant editor right pane (which is displaying the .h file) and you will be back in Storyboard.
Yes, you can do it without the Assistant editor and without writing lots of code. It requires learning to do two things:
Use code snippets
Use the Connections inspector
Create code snippets for the IBOutlet and IBAction
Normally when you create an IBOutlet and IBAction with the Assistant editor it automatically adds code like this to your View Controller:
#IBOutlet weak var myOutletName: UIButton!
#IBAction func myActionName(sender: AnyObject) {
}
You could type this all yourself and then add the connection in the Connection inspector, but why do all that typing? Just make a code snippet that will autocomplete. Drag the code to the Code Snippets library in the Utility panel.
Give it a title and most importantly, a Completion Shortcut. I called mine "ibaction" for the #IBAction code.
Now all I have to do is start typing "ibaction" and I can autocomplete the code snippet. I only have to edit the name of the action. It is a similar process for the Outlet.
Read more about creating code snippets:
Xcode Snippets
Creating a Custom Code Snippet
Now all you have to do is connect the IB object to the code.
Make the connection with the Connections inspector
First, click the object in the storyboard that you want to connect. For me, I am using a Button.
Then select the Connections inspector. It is on the far right.
Alternatively, you can right click or control click the object to get a menu.
Then click the New Referencing Outlet to connect it to your Outlet or the Touch Up Inside under Sent Events to connect it to your Action.
For whatever reason I find that sometimes I need to drag just a little bit after clicking the "+" button to get the menu of available connections to show up.
I have a number of view controllers, each with their own menu button (a UIBarButton, added in the storyboard). Now I want to link all these up to a single #IBAction function in their superclass (the superclass is the same for all the view controllers with that menubutton).
Now I have linked up #IBOutlets to a superclass before, but it doesn't seem to work with #IBActions, even though the function isn't private, and it definitely is part of the superclass (I am refactoring, previously it was an #IBAction in each class, which only did menuButtonTap() (calling the method in the superclass).
Any ideas?
I have solved the problem by manually creating an #IBAction on the superclass, and giving them the same name as the ones I create in the subclasses. Then I deleted the ones in the subclasses. This leaves a 'dangling reference' from the storyboard, according to Xcode, but I know it's there.
Although this still does not work as of Xcode 9.4 for general purpose UIViewController (but your workaround still does work 👍🏻), please note that it works as expected for UITableViewCell templates in storyboard.
If some of your template cells in storyboard share the same base class containing #IBOutlet properties, you will be able to link them to every template cell instance as you usually do:
Then Xcode will show a popup for telling in which prototype cell the link is "backed":
I'm not sure why this second step is necessary though, since you designate a specific component from within a given prototype cell
You can do it like you do when adding an action to a UITabbar button from subview class.
Assuming btn is a UIBarButtonItem,
[btn setTarget:self.superview];
[btn setAction:#selector(menuButtonTap:)]
Are you using __unused keyword by any chance? If you do the IBAction won't show up in storyboard(I am using Xcode 6.3.2)
- (IBAction)actionBack:(__unused id)sender;
vs
- (IBAction)actionBack:(id)sender;
To make it show up and selectable removed the __unsused keyword.
I tried to run this method of code
- (IBAction)signInButton:(id)sender {
NSLog(#"Run Action %#", #"Here");
}
The result of this code log the "Run Action Here" twice in the console.
I initially loaded all my project import file (.m and .h) in one header file "Loader.h", I taught this was the cause, but I still experience the same issue even after I dissembled the header file.
Same Issue happens on other view controller.
What am I doing wrong ?
Thanks in advance.
It sounds like you've connected the action to your button or other UI element for two different events. For example, if you connect it to both the touch down and touch up events, a single tap of the button will trigger the action twice.
One thing you can do to diagnose the problem is to control-click on the view controller containing the action in your nib or storyboard and look at the Received Actions section near the bottom of the resulting popup. You'll likely see your action connected twice.
Another option is to set a breakpoint in the action and take a look at the sender parameter each time you hit the breakpoint. This will show you what object is triggering the action each time.
This seems to be some problem with the logging. It indeed logs twice from IBAction handlers. I put NSAlert, to make sure it's called twice, but it was called once, nevertheless the log was printed twice in the console.
I'm trying to add a Modal ViewController to the existing application. To init and open it I use the following code
AddedViewController *addedOne = [[AddedViewController alloc] init];
[self.parent presentModalViewController:addedOne animated:YES];
If AddedViewController.xib with a View inside of course is just empty it opens nicely,
but
This throws SIGTRAP signal ((lldb) in log) at loading if AddedViewController.xib is not empty (i.e.) even if I add just a UILabel with static text there.
How can I handle this to have fully-operational ViewController (with labels, buttons, textfields, etc.. open properly?
========
UPD.
Problem easily resolved, see my answer below. =)
Assuming you are trying to present this inside the current view, you should not use self.parent and just use self.
The answer was in Use Autolayout checkbox for the ViewController settings, now everything works fine TWIMC. =))
I'm still quite the beginner at iOS and so I've been doing lots of tutorials, lately.
Let's say I was making an app such as a calculator, with let's say 24 buttons. I've seen example code where the button's label gets used to figure out what button it is, but that seems really kludgey, especially when trying to translate the app.
So is it better to just bite the bullet and have one IBOutlet for each and every button instead? why or why not?
If not, what would be the most elegant way to go about doing this, while staying in the MVC paradigm?
Ok I just was looking back at my code and now i feel more like a noob than before... I really was talking about IBActions, not so much IBOutlets... Should I have a whole bunch of IBActions for the different buttons? here's what it looks like right now in the viewController.h file:
- (IBAction)digitPressed:(UIButton *)sender;
- (IBAction)operationPressed:(UIButton *)sender;
- (IBAction)dotPressed:(UIButton *)sender;
- (IBAction)button_mClear_Pressed:(UIButton *) sender;
- (IBAction)button_mPlus_Pressed:(UIButton *) sender;
- (IBAction)button_mMinus_Pressed:(UIButton *) sender;
- (IBAction)button_mRecall_Pressed:(UIButton *) sender;
- (IBAction)button_AC_Pressed:(UIButton *) sender;
- (IBAction)button_PlusMinus_Pressed:(UIButton *) sender;
why does that just feel repetitive and inelegant to me?
Typically, you'd have similar buttons all trigger the same action, the idea being that similar button actions should have some common code between them. You then use the tag property to identify which button was clicked. E.g., number buttons trigger a specific action, operator buttons trigger another action, and so on.
- (void)didClickOperatorButton:(id)button
{
switch ([button tag])
{
case kAdditionOperation:
// Do the addition operation ...
// etc..
You can set the tag property on any control in Interface Builder.
If you use IBOutlets and wire them up in Interface Builder/Xcode 4 is more a matter of taste, than a programming decision. And doing so or not does not necessarily affect the mvc paradigm.
It is your choice, if you keep 24 IBOutlets in your viewcontroller and load the buttons from a nib, as it is maybe easier to arrage them in your interface, or to have an array full of buttons, and add them to your view programmatically and set them up with the right actions.
You can also have the buttons in different nibs for different viewcontroller — lets say for the number pad, the simple commands and the higher commands and functions. each of the viewcontrollers would have a delegate of a certain protocol, which all would be implemented by on 'BrainController'.This setup might be a bit overkill for a simple calculator, but would allow you to use nibs, without a viewcontoller overcrowded with IBOutlets. And you could re-use oarts of it in other project, i.e. the numberpad in an app with a remote control interface.
If you use XIB's and a lot of objects, then yes. If you plan on making the object do something special like disable the button during some method call later in code, then YES, hook up an IBOutlet. If you are only connecting the buttons to IBActions, then NO, just connect any button (without IBOutlet) to your IBAction, this will save you on connecting a bunch of objects.