Crash when using gesture recognizers in StoryBoard
Asked Answered
P

2

10

UPDATE

This is an old question for an old version of Xcode. It turned out that the issue was a bug in Xcode which has been fixed.

Original

I have a storyboard generated from making a new tab iphone application (with ARC)

In one of my tabs, if I drag a gesture recognizer (any, but let's say Pan) onto a control, and then set the selector to an action, it just crashes as soon as I go to the tab.

There is nothing in the Console -- it appears to be happening while the storyboard is being loaded (viewDidLoad is never called).

  1. I can't figure out how to get more information
  2. On a different tab, this works fine. Both tabs were generated automatically.

(it's possible I messed something up in the view, but I don't have a clue to figuring out what I did).

If I make gestures programmatically, they work fine, but it's nice to have it work in the storyboard, and I'm afraid that whatever is wrong will cause a crash some other way at some point.

MORE INFO

In the simulator I get

-[__NSCFString setView:]: unrecognized selector sent to instance 0x6d2db70

Again, need debugging techniques -- for example, is there a way to find out what object 0x6d2db70 is?

Which is exactly like this question (with no answer):

Gesture recognizer in Interface builder crashes my app

MORE INFO

This is trivial to reproduce

  1. New iPhone tabbed application, ARC and Storyboard on
  2. Drag tap gesture onto second tab's view (works on first one)
  3. Create an (IBAction)
  4. Connect the gesture's selector connection to the action from #3
  5. run, go to second tab

Crashes. Same thing with my app, default tab works, other tabs don't

Parik answered 27/1, 2012 at 15:35 Comment(10)
What kind of crash? SIGABRT? EXC_BAD_ACCESS? What's the stack trace?Atomy
That's the thing -- console has nothing. Stack trace is back at main in the release pool (so it feels like memory corruption). Need ideas for getting more info.Parik
I have done a LOT of iPhone debugging, but new to 4.2, ARC, etc. I would like ideas for new techniques (I know about zombies, debug malloc, etc -- but they don't seem appropriate).Parik
Also, is there a connection that I need to make besides selector? Does it connect to an IBAction with (id) sender? I can't seem to find any good docs on this.Parik
The action method signatures are documented here. The method can take a sender parameter or not.Atomy
A stack trace pointing at main usually indicates that an exception was thrown. Do you have an exception breakpoint set?Atomy
Besides setting the recognizer's target and action, it needs to be in at least one view's gestureRecognizers outlet collection. You do that by dropping the recognizer on a view. But it should be harmless if it's not in any gestureRecognizers collections.Atomy
Not near my computer right now -- will check all of this when I get to it -- thanks. @rob, add an answer -- I think you've given me enough to solve -- I will edit it with the results. Thanks.Parik
It's trivial to reproduce -- I think it's a bugParik
Check that the target of the Gesture Recognizer is not deallocatedIndustrial
A
9

The error message tells us that the program is sending the setView: message to an instance of __NSCFString (which is obviously the private implementation class of NSString).

Make sure you have tried running with zombies enabled. A zombie can easily cause an unrecognized selector error.

If it's not a zombie, put a breakpoint on -[NSObject doesNotRecognizeSelector:]. When the breakpoint is hit, you may be able to figure out the problem just from the stack trace. If not, you can print the debugDescription of the object (which is the same as the description for most classes).

On the simulator, you can ask the debugger to print the object's debugDescription like this:

(gdb) frame 0
#0  0x013bcbff in -[NSObject doesNotRecognizeSelector:] ()
(gdb) po ((int*)$ebp)[2]
this is my test string

On the device, you do this:

(gdb) frame 0
#0  0x344bca22 in -[NSObject doesNotRecognizeSelector:] ()
(gdb) po $r0
this is my test string

Update

Based on your steps to reproduce, this is a bug in UIKit. File a bug report. You can work around the bug by creating a strong outlet on SecondViewController and connecting it to the gesture recognizer. Make sure you set the outlet to nil in viewDidUnload.

Update

Do not ever set your outlet to nil -- part of the bug is that UIKit isn't retaining -- you need to keep your reference to make sure that the recognizers aren't released.

Atomy answered 28/1, 2012 at 19:4 Comment(12)
turning on zombies says the tap gesture is a zombie. -[UITapGestureRecognizer retain]: message sent to deallocated instance 0x6b5ba80Parik
I just noticed that UIImageView doesn't have a gestureRecognizers collection -- I have other UIImageView's where gestures work (also has the IB warning in the inspector).Parik
The gestureRecognizers property is part of UIView, so UIImageView inherits it. It is not tagged IBOutletCollection, so it only shows up in IB if you drop a recognizer on a view.Atomy
Do you have any unsafe_unretained outlets or variables?Atomy
Or any assign properties? Under ARC, assign is the same as unsafe_unretained.Atomy
It's trivial to reproduce -- I think it's a bug (see updated question)Parik
Everything is strong -- I have a trivial project that repros it. No outlets or any variablesParik
That's exactly what I did -- glad that you agree. I am using ARC -- do I need to set the outlet to nil?Parik
This was assigned Problem ID: 10771117 by Apple -- I will update this question if I hear that it was fixedParik
You need to set the outlet to nil in viewDidUnload. Otherwise it won't get released on a memory warning.Atomy
Unfortunately, you cannot release in viewDidUnload -- when the memory warning comes, the app will crash because UIKit isn't keeping a retain -- you have to hold yours (you can see this by setting to nil in viewDidUpload and simulating a memory warning -- you will crash when you change tabs with a zombie warning)Parik
Wow! I have been experiencing this issue as well, and it wasn't until I reviewed the Device Log in Organizer and found the doesNotRecognizeSelector was caused by the swipe that I managed to find this page. I have the same issue, and the fix above worked (just ctrl+drag the swipe gesture on to the header file of the backing view controller and make it a Strong Outlet - problem solved). Thanks!Mcclenaghan
M
2

In my case, when auto-creating the IBOutlet for the gesture recognizer by drag-n-dropping in the code, Xcode correctly created the property with a "strong" attribute, but it also added the "set to nil" in viewDidUnload. Removing the "set to nil" solved the issue for me.

Microspore answered 21/6, 2012 at 12:2 Comment(1)
That makes sense -- I ran into the same thing after I manually added in the IBOutlet in the standard way.Parik

© 2022 - 2024 — McMap. All rights reserved.