Debugging Seemingly Random Exceptions in Xcode - ios

I have been at this for days and asked this question a few days ago. I thought it's probably better to rephrase the question more clearly.
I have a series of UICollectionViewControllers inside a UINavigationController. Each time the user makes a selection, a new collection view is pushed on the screen and this collection view is responsible for fetching its content from an API.
Sometimes there's a crash at this point. The exceptions are different each time. Usually, it's one of the following:
*** Collection <NSConcreteMapTable: 0x1922cf60> was mutated while being enumerated.
OR
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSSetM: 0x203f26b0> was mutated while being enumerated.'
Sometimes it doesn't even throw an exception but the program will pause in an "empty thread" saying error: address doesn't contain a section that points to a section in a object file. Finally, this error is more consistently reproducible when an item is selected, the new view is pushed, and then the back button is quickly pressed as soon as it appears. But it can also happen without the back button being pushed.
I have attached my own uncaught exception handler to print out the stack trace. In all cases, none of my own classes are in the trace.
I have 'break on exception' set but it never stops anywhere meaningful - usually some nondescript assembly code that just reads trap or in UIApplicationMain.
So my question is: Where do I even begin debugging this?
I can post an example of a stack trace if it helps.

First, set an exception breakpoint in Xcode. It will stop before the exception is thrown, so you know who caused it.
What seems to be happening is that you have code
for (id object in somearray) ...
and while that loop is running, someone modifies somearray. That is fatal. You probably have to think about how you are writing your code. For example, you can just write
for (id object in [somearray copy]) ...
and then you can modify somearray as much as you like. Maybe your code just isn't thread safe and another thread modifies somearray while one thread is iterating through it.

Related

Why isn't my WTArchitectView being released under Obj-C + ARC?

The second time I try to present a view controller with a WRArchitectView it fails with a large error stating that a second architect view is attempting to be allocated before the first has been deallocated. I've checked up an down, have ARC enabled, the view controller is completely deallocated. I even have a branch which is working with an identical view controller, so what could be retaining the WTArchitectView?
I was writing JSON in a Swift Utility class while the view controller was instantiated which wasn't being handled well. I was getting an error along the lines of *** WebKit discarded an uncaught exception. Somehow, parsing malformed JSON with NSJSONSerialization and not handling the exception halts some Wikitude internals, which means something internal was retaining the view. Fixing my JSON allowed Wikitude to dealloc properly.

strange error when reload tableView

I have a very general table view.
when it is refreshed, it will go to fetch list of objects from Parse. Analyze these data in a dispatch_async queue, then refresh table view. Most time, it has no problem, but some time reloadData() crash
Is it crashes because the tableView is reloading data when I call it? (when the tableview is init, reloadData may be called automatically) How to avoid this error? ( there is no error message in console )
EDIT:
I tries to put ?, but does not work
This happens when your tableView (or whatever object you're sending the message to) is nil. So sometime before your async call dispatched this on the main queue, your tableView got dealloacted.
Check this link out for some info:
http://www.touch-code-magazine.com/how-to-debug-exc_bad_access/
You will get EXC_BAD_ACCESS error mostly in the following scenarios:
You are trying to access an object that is not initialized.
You are trying to access an object that no longer exists. Either it’s being released or it’s nil. In ARC mode, make sure you take ownership of the object that you want to use.
You are passing an message to an object that the object doesn’t understand.
It can also happen for bad typecast. Like the lines below where I am trying to access an int with %# in stead of %d.
int myAwesomeInt = 9;
NSLog(#"%#", myAwesomeInt);
How to debug:
Identify what you did that caused the crash. Did it crash while view of a particular view controller didLoad or in a delegate method or on a particular action. That will often help to find the object that is casuing the error.
(In your case look at what specifically happens when you are reloading the table. Do a stack trace line by line and see what your code is doing during a reload)
Most of the time “NSZombies” can help to identify the dead object. You can enable NSZombies by editing your scheme Product -> Edit Scheme -> Diagnostics.
If you still don’t find the root cause then always go backwards from child view controller to parent view controller to see what object needs to be retained or what message needs to be passed properly.
Look into Static Analyzer and Instruments for advanced debugging.
Credit:
The Basic Troubleshooting guide
Hope this helps. Good Luck

[__NSCFString count]: unrecognized selector sent to instance 0x75bc230'

My code is:
SCDownloadManagerView *downLoadMnger = [[SCDownloadManagerView alloc]init]
[self.vw_ownVw addSubview:downLoadMnger.view]
[self.vw_ownVw bringSubviewToFront:downLoadMnger.view]
I am getting this error on second line [self.vw_ownVw addSubview:downLoadMnger.view]
Please help me.
In my experience, what usually causes this error is when memory has been released prematurely. In this case, it is possible that your program is trying to use an array, but because it was not properly retained, the array was deallocated, and an NSString was allocated in the same spot. When your program tries to access the array, it sends the count message to where it thinks the array is, but because a string has been allocated there instead, the string gets the count message and this causes an error because strings don't respond to count.
The code you posted is not the cause of the problem, it is only the point at which this bug is manifesting. In order to find the cause, you need to review your memory management. Try running "Build & Analyze", the static analyser is very good at picking up obvious mistakes in memory management. Review parts of your code that deal with arrays, but keep in mind that the array in question could also be managed by another object outside of your code (such as a view or view controller) that you have released too early, etc.

'NSInvalidArgumentException', reason: '-[__NSCFString _isDecompressing]: unrecognized selector

I have this error going on in Xcode:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString _isDecompressing]: unrecognized selector sent to instance 0x71863b0'
I have quite a bit of code and classes so I don't know what would need to be posted to start looking at this issue. If someone could give me some direction on how to start fixing this, it would be much appreciated. p.s. if there is anything else that needs to be posted tell me and I'll edit.
When you have unrecognized selector send to instance error, you have to check if you declared and implemented the method that is pointed out by the error, in your case _isDecompressing. If everything is ok on your class (the method is declared and implemented) then have a look at the class type that is calling the method, in your case NSString most of the time the class is wrong.
So in order to point out your problem, you are trying to call a method _isDecompressing on NSString which doesn't exist. So make sure every object that calls this method is of your desired type and not NSString
A good way to find the line that is causing the crash is to enable exceptions breackpoints.
The most likely cause of this crash is that you are sending a message to a deallocated instance of an object - try running your app with NSZomie's enabled - see e.g. How do I set up NSZombieEnabled in Xcode 4?
What is going on is that the memory used by your object gets marked as unused when deallocated and some other object gets allocated in that place. This object, however, is of a different class, hence the does not recognize selector message.
As noted in the comments, the way sending messages to deallocated instances manifests itself varies:
The object is allocated somewhere in memory - on a page, which is split into parts by an allocator - e.g. malloc. If the underlying allocator already returned the page where the object was to the kernel, then the app will crash with no log (EXC_BAD_ACCESS).
If the object was released and the retain count reached 0 it was deallocated, meaning just marking the memory on the page as free for future use. If you hence try to send another message to that object, the runtime will notice that the object has no retain count, hence was deallocated and will case the message sent to deallocated instance exception.
If, however, the memory that your initial object occupied was taken by another object in between, there's no way for the runtime to know that there was once an object you intend to call a method on, hence the unrecognized selector exception, since the class which the object belongs to is part of the object structure - the isa pointer. Nothing else is (or can be) checked by the run-time. For the runtime, it's a valid request to send a message to an object, however, there's no such method on the new object.
This can be potentially dangerous if the new object responds to the same message which does something lethal in one class, since the method is actually called on the object if it is a valid method name!
Of course, there are other scenarios, e.g. the object will overwritten by other data, hence the isa pointer points to a non-existant class and a crash will occur just as in the first place, since the OS will try to dereference an address that is not valid in the context of your process.
In the debugger console, use 'bt' to get a backtrace, then disassemble the first address in the backtrace the is noticeably smaller than the other values... the small valued addresses are your code.
This is easy to hit if you pull an image name out of, say, a JSON dictionary and pass it straight into something that expects a UIImage; since the values aren't type checked, the compiler will miss the error and you'll get a runtime crash.
(Ask me how I know!)

Find __NSFastEnumerationMutationHandler caller

I have an app which is periodically triggering a "Collection was mutated while being enumerated." exception. The frequency of the exception seems to vary across devices.
I have a breakpoint set on all exceptions thrown, but at the time the exception is thrown, the only stack I get is __NSFastEnumerationMutationHandler and the assembly code it calls. I get the memory address for the __NSArrayM that's being modified, but I can't figure out how to reverse-engineer this into the name or contents of the array. Typing image lookup --address 0x20087d10 (the address the exception prints) in lldb gives me no output. $r0 gives me the exception object, but both po [$r0 callStackSymbols] and po [$r0 callStackReturnAddresses] return nil.
I also can't figure out how to determine which section of code is triggering it; the contents of the application threads at the time the exception breakpoint is hit vary from incident to incident and do not include any obvious accesses to collection objects.
How do I figure out which collection is being mutated and triggering this exception?
It turns out I was overcomplicating things - one can reference memory addresses directly at the lldb command line, so po 0x20087d10 is sufficient to print the description of the object at 0x20087d10.
(Murphy's law of StackOverflow... when you finally give up and post it on StackOverflow, you finally figure it out yourself.)

Resources