Segmented control addTarget() crashing app below iOS 9.0 - swift

My app has been released recently but it supports iOS 8.2.
Unfortunately, below iOS 9.0 tapping a segmented control which has been added programmatically crashes the app with no error message in the console.
I believe that the line where the target is added may cause the issue:
The following line is placed inside the init() of my custom cell, the segmented control is an instance var and calls a method in its parent view controller
segmentedControl.addTarget(ListViewController(), action: #selector(ListViewController.segmentedControlToggled(segmentedControl:)), for: .valueChanged)
Again, this works as expected down to iOS 9.0.
The setup works fine, it only crashes once the segmented control is tapped.
Should there be another syntax for the selector?
Thanks for any suggestions!

Per the documentation of addTarget:
The control does not retain the object in the target parameter. It is your responsibility to maintain a strong reference to the target object while it is attached to a control.
Which means that you need to store the value of the target parameter somewhere, thing you fail to achieve:
segmentedControl.addTarget(ListViewController(),...)
The ListViewController will get deallocated as soon as there will be no other references to it, the important thing to remember here is that you can't know in advance when the deallocation will happen, as you don't know how may other objects will refer your object.
To make sure the target doesn't get deallocated, store the ListViewController instance into a property.
The crash is not particular to the iOS version, it might be that on some iOS version the ListViewController gets deallocated sooner.

Related

Works on iOS Simulator but not on iPhone

The line of code works fine on the iOS Simulator 6.0, but is crashing when I try to run it on my iPhone, also running iOS6.
[menuView addSubview:mvc.view];
Why is this happening, and how can I fix it?
This is the more complete version of the code:
SDMenuViewController *mvc = [[SDMenuViewController alloc] init];
[menuView addSubview:mvc.view];
And this is what it is crashing with:
2012-10-08 21:32:32.423 CrunchCalculator1-2[21019:907] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </var/mobile/Applications/EDD23933-CE20-4AFD-A2B1-CDD56AD658E8/CrunchCalculator1-2.app> (loaded)' with name 'SDNestedTableView''
*** First throw call stack:
(0x39cd03e7 0x35ece963 0x39cd0307 0x39ee0fd1 0x39ee05ff 0x39dd9031 0x39e0786d 0x39d63419 0xb20d9 0x39d63541 0x39da3d29 0x39d9fac5 0x39de1199 0xb17c5 0x39da4a71 0x39da45f5 0x39d9c803 0x39d44ce7 0x39d44775 0x39d441b7 0x31e145f7 0x31e14227 0x39ca53e7 0x39ca538b 0x39ca420f 0x39c1723d 0x39c170c9 0x39d9b43d 0x39d98289 0xb1523 0x3792fb20)
libc++abi.dylib: terminate called throwing an exception
Thanks!
I'm not quite sure how it worked on your simulator (when I tried it on mine, I got the crash you list in your original question). Anyway, you can fix it by looking at the following items:
The main problem is that the NIB was not included in the bundle. Add it to the project target's "Copy Bundle Resources", e.g.:
While you're looking at your "Copy Bundle Resources", you'll also want to include SDSubCell.xib, SDGroupCell.xib, and add all of those PNG files, too.
As an aside, while it doesn't apparently cause the crash, the "File Owner" base class in SDNestedTableView NIB refers to a class that doesn't exist anywhere in this project. That can't be good. Anyway, you probably want to change that to SDMenuViewController or SDNestedTableViewController;
It's a little unrelated to your crash, but as I look at the project, I see a worrying construct:
SDMenuViewController *mvc = [[SDMenuViewController alloc] initWithNibName:#"SDNestedTableView" bundle:nil];
[menuView addSubview:mvc.view];
You're creating a controller, grabbing its view, and either letting the view controller fall out of scope and be released (if you were using ARC) or leaking it (if not ARC).
I wasn't entirely sure from the original question whether you were doing addSubview as a way of transitioning to a new view (which is really bad practice) or whether you were doing view controller containment. As I look at the code, it appears you're doing the latter, though you're missing a few calls in your code. You might want to read up on view controller containment. And also check out that WWDC 2011 session 102.
Anyway, those two lines of code above with the view controller alloc/init and the subsequent addSubview will leak in your non-ARC project (and would crash it if you ever went to ARC) and your view hierarchy is out of sync with your view controller hierarchy. I'd suggest you might want:
SDMenuViewController *mvc = [[[SDMenuViewController alloc] initWithNibName:#"SDNestedTableView" bundle:nil] autorelease];
[self addChildViewController:mvc];
[mvc didMoveToParentViewController:self];
[menuView addSubview:mvc.view];
Note the autorelease on that first line.
View controller containment can be powerful, but you want to make sure you do some of this basic housekeeping.
One final update:
I notice that there are some bugs that are in this code. First, your use of currentSection in item:setSubItem:forRowAtIndexPath won't work. You're setting that based upon the last expandingItem. So, if you click on one of the main items before expanding either one, the program will crash. Probably best is to eliminate the currentSection variable altogether and in item:setSubItem:forRowAtIndexPath, use item.cellIndexPath.row rather than your variable currentSection.
Unfortunately, this fix leads to a more serious problem, there appears to be an iOS 6 bug in the SDNestedTable class, itself. If you run this on iOS 6 and you expand your all of your items, scroll to the bottom and then scroll back to the top, the program will crash because the cellIndexPath property of the SDGroupItem *item returned by item:setSubItem:forRowAtIndexPath can be deallocated! If you turn on zombies in iOS 6, you'll see cellIndexPath has been released. I went and downloaded the original version and see the same problem there. The problem appears to be that cellIndexPath in SDGroupCell is defined as an assign property (which means that if iOS determines it no longer needed the indexPath it created for its own purposes, it will be released even though SDGroupCell maintains an assign reference to this released object). Just change the cellIndexPath property of SDGroupCell from assign to retain, and this iOS 6 bug goes away. I've informed the developer of SDNestedTable of this issue, but this change to retain will fix the problem of the code crashing in iOS 6.
[Edit: The author of SDNestedTable agreed with my assessment of the issue, and he reports that this issue has been fixed the latest version. - Rob]
Best wishes.
You should probably use initWithNibName: insead of just init in the first line. Not sure regarding your specific issue, but certainly something to try.
It looks like you're trying to instantiate a nib called SDNestedTableView.nib and it isn't present. Is the nib included as a project member?

Xcode application running on Iphone but crashing on Ipad

I made a universal application that contains NIB files for both ipad and iphone UI's. In my view controllers initWithNibName method I call UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM() to detect whether the controller is running on iphone or ipad.
I then launch their respective nib files. When I run the app on iphone, it works fine, but when I run it on ipad it eventually crashes with a EXC_BAD_ACCESS error. This error occurs when I use a view controller to launch another view controller, which then launches another one in the navigation stack. This error occurs as soon as I click the view that belongs to the third controller of the stack.
I cannot distinguish a difference between the NIB files that would cause a crash. I have been working tirelessly to figure out why this is happening but I cannot fix this error. Does anyone have any insight into what might be going on?
Any advice on how to approach fixing this problem would be very appreciated.
The first thing you should do is enable the "All Exceptions" break point. This will often accurately tell you the line of code where the EXC_BAD_ACCESS is happening.
Next, I would turn on zombies and see where the over-release is happening. To do so, in Xcode, while holding the option key, click Product | Run.... In the ensuing window, add NSZombieEnabled to the environment variables list.
Then run. Do the normal things you do to cause the crash and see where the debugger lands. With any luck, it will stop where the problem is actually occurring.
When you get a EXC_BAD_ACCESS it means you're trying to access/release something that's already been released. If you're in a non-ARC situation, it normally means you've inadvertently released something when you didn't mean to, so just check for alloc/init and release balance. If, however, you're in an ARC situation, I would bet it has to do with not niling a delegate when a view controller gets released.
For example, if you have a MKMapView and have set its delegate to your view controller, you should nil its delegate when your view gets unloaded or dealloc'd. Otherwise, messages will continue to get set to it. Or, another possibility is that you've added your view controller as an NSNotificationCenter observer and didn't remove it as an observer when the view controller was unloaded or dealloc'd.
Another possibility is that you're re-using view controllers between the two versions of your universal app. If you are accessing anything by an identifier that doesn't exist in the nib for the iPad, that would cause a crash--though if you're using nibs as opposed to storyboards, that may not be an issue.
That's about all I can think of for now. Try to zero in on where it's happening and post code here if you still can't figure it out.
Best regards.

Crash when using gesture recognizers in StoryBoard

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).
I can't figure out how to get more information
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
New iPhone tabbed application, ARC and Storyboard on
Drag tap gesture onto second tab's view (works on first one)
Create an (IBAction)
Connect the gesture's selector connection to the action from #3
run, go to second tab
Crashes. Same thing with my app, default tab works, other tabs don't
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.
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.

Do the viewcontrollers in a UIPageViewController set-up need releasing?

I am using the Apple UIPageViewController template from Xcode to create interactive photobooks. Everything works fine except that whenever I turn a page (create a new viewcontroller) the memory allocation goes up and up and up until the app crashes. It looks to me that the viewcontrollers never get 'released' (am I still allowed to use that word in an ARC environment?). It does not seem to be anything to do with the content of the pages because when I comment out all the content creation stuff in the ...DataViewController the memory still keeps going up and up every time I turn a page, not as spectacular as when a large image has been included but it still keeps creeping up.
There's been exactly the same question here: PageViewController: How to release ViewControllers added to it? but this one deals with a pre arc & storyboard situation. Adding autorelease is not permitted and it certainly seems that the compiler is NOT taking care of it. :-(
Any suggestions?
The problem turned out to be the never enough damned "UIImage imagedNamed" construct. It probably is all my own fault for not checking after I read somewhere that this had been fixed in a recent xcode release. So I assumed images were no longer being cached whereas the opposite was true. Once I changed all to the "UIImage imageWithContentsOfFile" the app started working smooth as a babies bottom.
I had the same problem building a picture book with very large images. I went to other question you provided a link for and that solved it for me. Adding "autorelease" frees up the memory.
In the UIPageviewcontroller delegate method "viewControllerAtIndex". I changed from:
// Create a new view controller and pass suitable data.
ContentViewController *contentViewController = [[ContentViewController alloc] initWithNibName:#"ContentViewController" bundle:nil];
and added autorelease
// Create a new view controller and pass suitable data.
ContentViewController *contentViewController = [[[ContentViewController alloc] initWithNibName:#"ContentViewController" bundle:nil] autorelease] ;
This wasn't included in the apple example but I'm also using xib for each page. I've been debugging this using instruments and saw memory reclaimed right away and dealloc being called when it wasn't previously.
found answer here....
https://stackoverflow.com/a/7934392/1212585

Weird XIB file issue

Experiencing a weird problem in a modified program written by me. In my first iteration, the view controller had an IBAction by the title userSpecifyingInput and had all my buttons wired up to this IBAction.
To make the design more sophisticated, I introduced userSpecifyingDigit and userSpecifyingLetter and accordingly had some buttons wiring up to the first IBAction (userSpecifyingDigit) and the next button wiring up to the second IBAction (userSpecifyingLetter).
Upon running my program, it gave me this error:
terminating app: NSInvalidArgumentException
Unrecognized selector sent to instance
And these selectors were alternating between userSpecifyingInput and userSpecifyingDigit which did not make sense as userSpecifyingInput was completely removed from my ViewControllers interface and implementations.
Now I am not sure why userSpecifyingInput still existed, but after dabbling with sent events, I noticed that the buttons were wired upto the new selectors as well as the old selector.
I had to manually remove the old selector from the touchupinside events for all the buttons.
Naturally this does not seem to be a very convenient way to go about proceedings and if the view controller selectors are modified then the touch events ought to be automatically removed.
Am I missing something here? This is a pretty open ended question with different answers
Eliminating an IBAction from your implementation will not remove any previous links to it in IB. I haven't heard of any XCode/IB preferences to shortcut this issue.
Sounds like the xib still thinks one of it's objects is hooked up to the UIViewController, but the function on the UIViewController is no longer there. To check and fix this...
Click on the xib file in the project navigator
Select the File's Owner
Click on the Connections Inspector
Verify that none of these connections are invalid
I would also look in the UIViewController to make sure no automagically created references exist here as well.