Xcode 8 drag and connect #IBAction incorrectly adds "WithSender" on connection inspector IB - xcode8

Xcode 8 drag and connect #IBAction incorrectly adds "WithSender" on connection inspector IB
Therefore I have to rename the methods to something like
#IBAction func tappedConfirmButtonWithSender(sender: AnyObject) {}
Shouldn't it be?:
#IBAction func tappedConfirmButton(sender: AnyObject) {}
Is this my fault or is this a bug?

I've just hit this as well. It appears to be a bug with legacy Swift 2.3 code, due to a bit of Swift 3 leaking in. I found the key answers in the dev forums, plus some additional findings by me and my coworker.
Workaround: Change the argument (sender: AnyObject) to (_ sender: AnyObject). You'll get a warning on the modified line that you can safely ignore.
[UPDATED - another workaround: Apple responded to my bug report and suggested a different workaround: annotate the #IBAction method with #objc. I haven't yet confirmed that that works.]
What's going on: It looks like there's a bug in Xcode 8 storyboards. My interpretation is that it's mistakenly parsing Swift 2 #IBAction methods as if they were Swift 3, and then attempting to convert them back to Swift 2.
Let's get detailed! In Swift 3, unlike Swift 2, given a method declared as:
#IBAction func foo(sender: AnyObject)
the sender argument label is actually part of the method name and gets included in calls to that method. In Swift 2, of course, the first argument does not get a label by default. In Swift 2, you'd call foo(myButton); in Swift 3, you'd call foo(sender: myButton).
Xcode 8 is mistakenly reading this function the Swift 3 way. And the pattern for the Grand Renaming of the APIs is that Swift 2 method names of the form doSomethingWithParam(quuz) are rewritten for Swift 3 as doSomething(param: quuz). Xcode assumes that's what happened here, so in a misguided attempt to derive the original Swift 2 name, it adds WithSender back to the end of the method name. The underscore workaround works by making the Swift 3 method signature identical to the Swift 2 one. (I don't know why the #objc annotation also solves the problem, according to Apple.)
[Edited repeatedly with changes to workarounds.]

I have finally found topic with the problem I am having. I have started to doubt myself.
I will propose one more workaround for those who are interested.
Open your storyboard with right click -> Open as -> Source Code.
Find your method in xml file and delete WithSender addition to match your method name with the one in your class.
This way you can have your method name the way you want.
Thats it...

I had the same issue while working with Xcode 8. It may be bug.
Below is work around for this issue :
Delete the outlet connection from IB file
Create a new outlet by Ctrl and drag. This opens a pop-up as shown below.
Select Connection as Action and enter name of action. Then select Type.
Press Connect. This will create new IBAction in your Swift file.
Although the circle for IBAction may not be filled but it is connected.

You can try to change it as following:
#IBAction func tappedConfirmButton(_ sender: AnyObject)
{
}
Good luck!

Related

#objc requirement for Swift 3?

Any idea why i my Swift 3 iOS app, this
#objc(mapView:rendererForOverlay:) func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
triggers,
but if I replace above statement with this
func mapView(mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
does not trigger.
Even matt's answer is correct I want to explain the reason for the underscore.
Why do you need the underscore?
Short answer: Because this is the declaration of the method:
optional func mapView(_ mapView: MKMapView,
rendererFor overlay: MKOverlay) -> MKOverlayRenderer
https://developer.apple.com/reference/mapkit/mkmapviewdelegate/1452203-mapview
Long answer:
tl;dr: You need it to delete a leading parameter name for the first parameter in Swift 3.0.
To understand that you have to know the whole story:
Objective-C has akin of named arguments: The whole method declaration including the parts ahead of a parameter declaration is a part of the method identifier. Having the method …:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView
rendererForOverlay:(id<MKOverlay>)overlay;
… this means, that the identifier of the method (selector) is mapView:renderForOverlay:. This system was simple and in use for a long time. It was powerful, because it makes method overloading unnecessary.
According to Swift's design principle, to make working and simple things that complex that it is impossible to say, whether they are working, they did some tricky hacks:
Swift has akin of translation mechanism from Objective-C selectors to Swift function and parameter identifiers. They found a great solution in Swift 1.2(?), that makes things easier by far. Later they recognized, that the great and easy solution is confusing and they offered a new solution in Swift 2.0 which is greater and easier by far. Later they recognized, that the greater and easier solution is confusing and they offered a new-new solution in Swift 3.0, which is greater-greater by far-far.
While in Swift < 3.0 the first (external) parameter name defaults to nothing (because the first part of the selector becomes the function name) this rule does not apply anymore and you have to specify that. The underscore simply says, that there is no external name. So your method name is translated correctly to Objective-C's selector.
It takes the function name mapView adds no external name because of the _, so it is mapView:. And then it adds the next external parameter name renderFor, which leads to mapView:renderFor, then the parameter name overlay, capitalize it to Overlay, which leads to mapView:renderForOverlay: – the correct selector.
Quite easy, quite simple. Another feature that makes things in Swift great and easy. Much easier as in Objective-C
One obvious problem is that, in Swift 3, this is not the correct signature:
func mapView(mapView: MKMapView,
rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
The correct signature is:
func mapView(_ mapView: MKMapView,
rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
Notice the difference (the "underscore").
Another possible problem happens if your code is not inside a class or extension declaration that explicitly declares conformance to MKMapViewDelegate. Swift 3 is very choosy about this. (You did not show enough context for me to know if you're getting that part right.)
The #objc declaration works around both problems by explicitly bridging this function to Objective-C. But if you do it right on both counts, Swift will do the bridging for you and the #objc will not be needed.

Method names in Swift

In Objective-C we have method names like application:didFinishLaunchingWithOptions:, but in Swift the method for the same job looks different.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
Is the name of this method simply application since everything else are just parameters? Or is it called application didFinishLaunchingWithOptions with a space in the name?
I was looking for an official answer in the Apple Documentation but I could not find one.
The method is indeed called application, however didFinishLaunchingWithOptions is an external parameter name and:
If you provide an external parameter name for a parameter, that external name must always be used when you call the function.
Since there can be two functions called application with different external parameter names, we always have to specify the external parameters when referring to a function. So, the whole name of the function/method would be
application(_:didFinishLaunchingWithOptions:)
You are right there hasn't be any convention made yet for referring to Swift functions. The safest way to refer to a function now is to use the Obj-C convention.
application:didFinishLaunchingWithOptions:
Which is still used in all Apple documentation links.
This convention is used throughout Apple documentation.
The method is indeed “just” application.
Swift uses this more often, if you have a tableview for example almost all functions start with tableview
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {}
The parameters “define” the functions instead of the method.
What do you mean, its name in the documentation? it is application(_:didFinishLaunchingWithOptions:) I can’t imagine circumstances when you need to call it manually but just in case:
application(app, didFinishLaunchingWithOptions:aDictionary)
Naming is exactly the same in both languages.
If you want a good proof, try using any other naming in a selector.

Is there a shortcut for adding properties in Xcode 4?

In Visual Studio if I type prop and press tab then a property is created for me, I just have to fill in the details. Is there anything like this in Xcode 4?
I realise that a similar question has been asked here: Xcode script for generating/synthesizing properties but it seems to relate to Xcode 3 judging by the date.
Thanks, Gareth
In Xcode4 you can add a property, create an ivar, get release calls in dealloc and setting to nil in viewDidUnload all by simply dragging a UI component from within the XIB editor into your view controller's header file. All you have to do is name the property and Xcode4 does the rest for you. Nice!
Unfortunately if you just want to manually add a property, create an associated ivar and manage memory in an arbitrary class, there is no way to do that. At least none I have found so far! The smart code completion undeniably is an improvement but not the same as an intelligent operation to add all the boiler-plate for the addition of a property.
The code completion in Xcode 4 has been greatly improved. Just start typing #prop... and complete the in the header file. THen switch to your implementation file and start type #syn... and you are done.

NSCFString or UIViewController?

I am using UIViewController (a subclass of course) with a text field which sends an action when the contents changed (to the contentsChanged: selector of the ViewController). It is done by sending contentsChanged: to file's owner in IB.
But when I test it, it says : "-[NSCFString contentsChanged:] : unrecognised selector sent to instance " and the instance pointer in hex.
I am guessing that for some reason the view controller gets moved to another pointer and a string gets allocated there, but I cannot figure why.
Any ideas ?
Sounds like a classic case. Read up on NSZombieEnabled for how to track this sort of problem down.
I have the exact same problem with a subclass of UIViewController and this piece of innocuous code:
- (void)viewDidLoad
{
NSLog(#"%# %s %#", [self class], _cmd, answerButton);
[self.answerButton addTarget:self
action:#selector(getAnswerToQuestion:)
forControlEvents:UIControlEventTouchUpInside];
}
Yes, answerButton is connected (it's an IBOutlet), yes, - (IBAction)getAnswerToQuestion:(id)sender; is a proper method, but no joy. When I commented out the viewDidLoad and made the connection in IB, it showed in the crash report that the failure happens on [UIControl sendAction:to:forEvent:] resulting in
objc_msgSend() selector name: performSelector:withObject:withObject:
I can't prove it, but I suspect there's a bug somewhere in the UIKit that translates the bindings and addTarget to a call to performSelector. I'm planning to upgrade to iOS 4.01 first to see if that won't solve the problem.
UPDATE:
I'm not sure anymore that my problem really is similar to Alexandre Cassagne's but in the interest of sharing information I will not delete it just yet. I solved my problem, as so often, when I started to make an example project in order to file a bug report. Yes, clicking made answerButton call getAnswerToQuestion: like a good little object and all was fine.
The difference between the subclassed UIViewController of the example project and that of my real project was that the first also functioned as the xib's File's Owner while the second was just one of several view controller. When I moved getAnswerToQuestion: to the File's Owner in my real project, clicking answerButton worked as expected. So, my hunch that the problem lay somewhere in the translation from binding to performSelector wasn't that far off: the problem lies in the Responder Chain. I would think that establishing the Action-Target link either programmatically or in IB would bypass the Responder Chain, but apparently not.
The problem now, of course, is that Alexandre states in his question that his contentsChanged: method already is part of the File's Owner, which makes my answer irrelevant to the question.
without looking at the code, it looks like you are calling contentsChanged: on the text field's text, instead of the UIViewController subclass.
you should consider using the UITextFieldDelegate protocol to get called back when the text of a UITextField changes. I have not looked, but this is the thing I would do off the top of my head.

"unrecognized selector sent to instance" error in Objective-C

I created a button and added an action for it, but as soon as it invoked, I got this error:
-[NSCFDictionary numberButtonClick:]: unrecognized selector sent to instance
0x3d03ac0 2010-03-16 22:23:58.811
Money[8056:207] *** Terminating app
due to uncaught exception
'NSInvalidArgumentException', reason:'*** -[NSCFDictionary numberButtonClick:]: unrecognized selector sent to instance 0x3d03ac0'
This is my code:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
UIButton *numberButton = [UIButton buttonWithType:UIButtonTypeCustom];
numberButton.frame = CGRectMake(10, 435, 46, 38);
[numberButton setImage:[UIImage imageNamed:#"one.png"] forState:UIControlStateNormal];
[numberButton addTarget:self action:#selector(numberButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview: numberButton];
}
return self;
}
-(IBAction)numberButtonClick:(id)sender{
NSLog(#"---");
}
It looks like you're not memory managing the view controller properly and it is being deallocated at some point - which causes the numberButtonClicked: method to be sent to another object that is now occupying the memory that the view controller was previously occupying...
Make sure you're properly retaining/releasing your view controller.
For those getting here via Google like I did, which probably pertains more to Xcode 4.2+/iOS 5+ more, what with ARC. I had the same error "unrecognized selector sent to instance". In my case I had a UIButton's target action set up to pass itself as the sender parameter, but later realised I didn't need it and removed that in code. So, something like:
- (IBAction)buttonPressed:(UIButton *)sender {
Was changed to:
- (IBAction)buttonPressed {
Right clicking the UIButton in question showed that the Touch Up Inside event was associated with the view controllers buttonPressed: method. Removing this and reassigning it to the modified method worked a treat.
This was the top Google answer for this issue, but I had a different cause/result - I thought I'd add in my two cents in case others stumble across this problem.
I had a similar issue just this morning. I found that if you right click the UI item giving you the issue, you can see what connections have been created. In my case I had a button wired up to two actions. I deleted the actions from the right-click menu and rewired them up and my problem was fixed.
So make sure you actions are wired up right.
OK, I have to chip in here. The OP dynamically created the button. I had a similar issue and the answer (after hours of hunting) is so simple it made me sick.
When using:
action:#selector(xxxButtonClick:)
or (as in my case)
action:NSSelectorFromString([[NSString alloc] initWithFormat:#"%#BtnTui:", name.lowercaseString])
If you place a colon at the end of the string - it will pass the sender. If you do not place the colon at the end of the string it will not, and the receiver will get an error if it expects one. It is easy to miss the colon if you are dynamically creating the event name.
The receiver code options look like this:
- (void)doneBtnTui:(id)sender {
NSLog(#"Done Button - with sender");
}
or
- (void)doneBtnTui {
NSLog(#"Done Button - no sender");
}
As usual, it is always the obvious answer that gets missed.
In my case the function was not expecting an argument but the button was configured to send one causing the error. To fix this I had to rewire the event handler.
Here is my function:
Notice it contains no arguments.
Here is an image of my button configuration (right click on the button to view it):
Notice there are 3 event handlers.
To fix this I had to remove each of the event items since one of them was sending a reference to itself to the enterPressed function. To remove these items I clicked on the little x icon next to the name of each item until there were no items shown.
Next I had to reconnect the button to the event. To do this hold down the Control key and then drag a line from the button to the action. It should say "Connect Action". Note: I had to restart XCode for this to work for some reason; otherwise it only let me insert actions (aka create a new action) above or below the function.
You should now have a single event handler wired to the button event that passes no arguments:
This answer compliments the answer by #Leonard Challis which you should read as well.
This can also happen if you don't set the "Class" of the view in interface builder.
In my case, I was using NSNotificationCenter and was attempting to use a selector that took no arguments, but was adding a colon. Removing the colon fixed the problem.
When using a selector name, don't use a trailing colon if there are no arguments. If there's one argument, use one trailing colon. If there are more than one argument, you must name them along with a trailing colon for each argument.
See Adam Rosenfield's answer here: Selectors in Objective-C?
I had this problem with a Swift project where I'm creating the buttons dynamically. Problem code:
var trashBarButtonItem: UIBarButtonItem {
return UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "newButtonClicked")
}
func newButtonClicked(barButtonItem: UIBarButtonItem) {
NSLog("A bar button item on the default toolbar was clicked: \(barButtonItem).")
}
The solution was to add a full colon ':' after the action: e.g.
var trashBarButtonItem: UIBarButtonItem {
return UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "newButtonClicked:")
}
func newButtonClicked(barButtonItem: UIBarButtonItem) {
NSLog("A bar button item on the default toolbar was clicked: \(barButtonItem).")
}
Full example here: https://developer.apple.com/library/content/samplecode/UICatalog/Listings/Swift_UIKitCatalog_DefaultToolbarViewController_swift.html
The most obvious cause of this (included for completeness) is improperly casting a pointer and calling a method of the wrong class.
NSArray* array = [[NSArray alloc] init];
[(NSDictionary*)array objectForKey: key]; // array is not a dictionary, hence exception
I also had the same issue.
I deleted my uibutton in my storyboard and recreated it .. now everything works fine.
How to debug ‘unrecognized selector send to instance’
In most of the cases Xcode do not take us to the exact line where this issue happen. When app crash you won’t see the line of code that caused this, rather you will be taken to App delegate class, in which the error output may look like:
[UITableViewCellContentView image]: unrecognized selector sent to instance
or
[__NSDictionaryI objectAtIndex:] unrecognized selector sent to instance
or
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TestApp.MyViewController viewDidLoad:]: unrecognized selector sent to instance 0xDABCDD'
How to find line of code causing this:
Go to breakpoint navigator. Click ‘+’ option. click ‘Exception Breakpoint’. An new widget like following will apear.
Add following condition block:
-[NSObject(NSObject) doesNotRecognizeSelector:]
You can also put breakpoint for all exception.
Now run your code again. this time, breakpoint will trigger when this exception occurs.
WRITTEN BY: Prafulla Singh
Full explanition: https://prafullkumar77.medium.com/how-to-debug-unrecognized-selector-send-to-instance-402473bc23d
I had a similar problem, but for me the solution was slightly different. In my case, I used a Category to extend an existing class (UIImage for some resizing capabilities - see this howto in case you're interested) and forgot to add the *.m file to the build target. Stupid error, but not always obvious when it happens where to look. I thought it's worth sharing...
Another possible solution: Add '-ObjC' to your linker arguments.
Full explanation is here: Objective-C categories in static library
I think the gist is: if the category is defined in a library you are statically linking with, the linker isn't smart enough to link in category methods. The flag above makes the linker link in all objective C classes and categories, not just ones it thinks it needs to based on analyzing your source. (Please feel free to tune or correct that answer. I'm knew to linked languages, so I'm just parroting here).
This happened to my because accidentally erase the " #IBAction func... " inside my UIViewcontroller class code, so in the Storyboard was created the Reference Outlet, but at runtime there was any function to process it.
The solution was to delete the Outlet reference inside the property inspector and then recreate it dragging with command key to the class code.
Hope it helps!
I think you should use the void, instead of the IBAction in return type. because you defined a button programmatically.
I had the same error and I discovered the following:
When you use the code
[self.refreshControl addTarget:self action:#selector(yourRefreshMethod:) forControlEvents:UIControlEventValueChanged];
You may think it's looking for the selector:
- (void)yourRefreshMethod{
(your code here)
}
But it's actually looking for the selector:
- (void)yourRefreshMethod:(id)sender{
(your code here)
}
That selector doesn't exist, so you get the crash.
You can change the selector to receive (id)sender in order to solve the error.
But what if you have other functions that call the refresh function without providing a sender? You need one function that works for both. Easy solution is to add another function:
- (void)yourRefreshMethodWithSender:(id)sender{
[self yourRefreshMethod];
}
And then modify the refresh pulldown code to call that selector instead:
[self.refreshControl addTarget:self action:#selector(yourRefreshMethodWithSender:) forControlEvents:UIControlEventValueChanged];
I'm also doing the Stanford iOS course on an older Mac that can't be upgraded to the newest version of Mac OSX. So I'm still building for iOS 6.1, and this solved the problem for me.
On my case I solved the problem after 2 hours :
The sender (a tabBar item) wasn't having any Referencing Outlet. So it was pointing nowhere.
Juste create a referencing outlet corresponding to your function.
Hope this could help you guys.
I'm currently learning iOS development and going through the "Beginning iOS6 Development" book by aPress. I was getting the same error in Chapter 10:Storyboards.
It took me two days to figure it out but found out I accidentally set the TableView cell's tag to 1 when I shouldn't have. For anyone else doing this book and receive a similar error I hope this helps.
I really hope future errors in my code are easier to find! hahaha. The debug error did nothing to push me in the right direction to figuring it out (or at least I'm too new to understand the debugger, lol).
In my case I was using a UIWebView and I passed a NSString in the second parameter instead of a NSURL. So I suspect that wrong class types passed to a functions can cause this error.
..And now mine
I had the button linked to a method which accessed another button's parameter and that worked great BUT as soon I tried to do something with the button itself, I got a crash. While compiling, no error has been displayed.. Solution?
I failed to link the button to the file's owner. So if anyone here is as stupid as me, try this :)
Yet another slightly different solution/case.
I am using Xamarin and MvvmCross and I was trying to bind the UIButton to a ViewModel. I had the UIButton wired up to an Outlet and a TouchUpInside.
When Binding I only use the Outlet:
set.Bind (somethingOutlet).For ("TouchUpInside").To(vm => vm.Something);
All I had to do was remove the action (TouchUpInside) connection in XCode and that solved it.
P.S.
I guess this is in its base all related to the previous answers and to #Chris Kaminski in particular, but I hope this helps someone...
Cheers.
I had the same issue. The problem for me was that one button had two Action methods. What I did was create a first action method for my button and then deleted it in the view controller, but forgot to disconnect the connection in the main storyboard in the connection inspector. So when I added a second action method, there were now two action methods for one button, which caused the error.
For me, it was a leftover connection created in interfacebuilder bij ctrl-dragging. The name of the broken connection was in the error-log
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[NameOfYourApp.NameOfYourClass nameOfCorruptConnection:]:
unrecognized selector sent to instance 0x7f97a48bb000'
I had an action linked to a button. Pressing the button crashed the app because the Outlet no longer existed in my code.
Searching for the name in the log led me to it in the storyboard. Deleted it, and the crash was gone!
I'm replying to Leonard Challis, since I was also taking the Stanford iOS class C193P, as was user "oli206"
"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:"
The problem was that I had the "Enter" button on the calculator connected twice,and a friend pointed out that doing an inspection of the button in the Storyboard showed that 2 entries were on the "Touch Up Inside" attributes when I right clicked on the "Enter" button. Erasing one of the two "Touch Up Inside" "Sent Events" solved the problem.
This showed that the problem is triggered (for the C193P video class on the Calculator Walkthrough on Assignment 1) as 2 sent events, one of which was causing the exception.
It can happen when you do not assign the ViewController to the ViewControllerScene in
the InterfaceBuilder. So the ViewController.m is not connected to any scene.
Including my share. I got stuck on this for a while, until I realized I've created a project with ARC(Automatic counting reference) disabled. A quick set to YES on that option solved my issue.
Another really silly cause of this is having the selector defined in the interface(.h) but not in the implementation(.m) (p.e. typo)
Another reason/solution to add to the list. This one is caused by iOS6.0 (and/or bad programming). In older versions the selector would match if the parameter types matched, but in iOS 6.0 I got crashes in previously working code where the name of the parameter wasn't correct.
I was doing something like
[objectName methodName:#"somestring" lat:latValue lng:lngValue];
but in the definition (both .h and .m) I had
(viod) methodName:(NSString *) latitude:(double)latitude longitude:(double)longitude;
This worked fine on iOS5 but not on 6, even the exact same build deployed to different devices.
I don't get why the compiler coudn't tell me this, anyway - problem soled.
This also might happen when you want to set a property from a ControllerA to a public property inside a custom ControllerB class and you haven't set the "Custom Class" inside the identity inspector in storyboards yet.
My problem and solution was different and I thought I should post it here so that future readers can save their head from banging to the wall.
I was allocating different xib to same UIVIewController and even after searching everywhere I couldn't find how to correct it. Then I checked my AppDelegate where I was calling initWithNibName and can see that while copying the code, I changed the xib name, but forgot to change UIViewController class. So if none of the solution works for you, check your initWithNibName method.