I didn't believe this line will fix my crash, but guess what - It did.
let bugfix = ""

seen from Malaysia
seen from Japan
seen from Germany

seen from Sweden

seen from Malaysia

seen from Malaysia

seen from United Kingdom
seen from China
seen from China
seen from Malaysia
seen from United Kingdom
seen from Ecuador
seen from T1
seen from United Kingdom
seen from Malaysia
seen from Bangladesh
seen from United Kingdom
seen from Brazil

seen from Poland
seen from South Korea
I didn't believe this line will fix my crash, but guess what - It did.
let bugfix = ""
EXC_BAD_ACCESS when using CoreImage
I'm working on an iOS app, in Swift. In general, I love Swift. Xcode is still learning some things about it, but in general, it's simply fantastic.
Which is why it can be so frustrating when Swift, or Xcode when compiling it, gives you an annoying, useless error message, like EXC_BAD_ACCESS, and gives you no more information about it.
(tldr; Swift extensions to UIImage can be wonky.)
Yesterday, I was working on adding a new controller to a UINavigationController stack. The stack is nothing exceptional:
UITableView, listing all of a certain kind of model
A detail view controller, which extends UIViewController, which has details about the model instance, including a UICollectionView, which includes zero to many images that you can page through
A map (MKMapView) in a UIViewController
It was that third controller I was adding yesterday, when I started getting really annoying errors. In the second controller.
After a while, I discovered steps to reproduce the crash:
Select any cell in the table view to go into the detail
Tap the button to push the map view controller
Go back to the detail
Go back to the table, and select either the same or a different model
Crash! EXC_BAD_ACCESS.
Xcode was pointing at this line, which was used to make a reflected image of the currently viewed photo in the detail view controller (controller 2, above):
let cgImage = CI_CONTEXT.createCGImage(outputImage, fromRect: rect)
I tried everything to get more information from Xcode about what, exactly, was failing. I broke the line that was getting the error into six or so, to see which variable or method call was causing the issue. No dice.
Here's the whole snippet, which takes a UIImage and returns a UIImage? filtered by a gaussian blur:
let CI_CONTEXT = CIContext(options: nil) import CoreImage extension UIImage { func getBlurryCopy() -> UIImage? { let gaussianFilter: CIFilter = CIFilter(name: "CIGaussianBlur") let ciImage = CoreImage.CIImage(image: self) gaussianFilter.setValue(25, forKey: "inputRadius") gaussianFilter.setValue(ciImage, forKey: kCIInputImageKey) let outputImage = gaussianFilter.outputImage let rect = ciImage.extent() let cgImage = CI_CONTEXT.createCGImage(outputImage, fromRect: rect) //EXC_BAD_ACCESS return UIImage(CGImage: cgImage)? } }
It worked perfectly until I started pushing that third controller onto the stack.
Hmm. I figured it was a memory problem, so I did a bunch of research about CoreImage's memory handling. Everything, including Apple's documentation, says clearly to not try and handle memory allocation or release because Swift does that for you. Nonetheless, I checked all of my controllers' didReceiveMemoryWarning(), and still nothing.
I read up on CIContext, which is immutable and thus can (and should) be declared once and reused for multiple images. (CIFilter is mutable, and should be used once.) But I was already doing that. (Except I was also reusing my CIFilter instance. Fixing that didn't help though.)
Then I remembered seeing a Stack Overflow thread, in which someone was complaining about Swift extensions not working very well. So I decided to move that block above and make it into a class method in a generic helper class:
let CI_CONTEXT = CIContext(options: nil) import CoreImage class ImageHelper { class func getBlurryCopy(image: UIImage) -> UIImage? { let gaussianFilter: CIFilter = CIFilter(name: "CIGaussianBlur") let ciImage = CoreImage.CIImage(image: image) gaussianFilter.setValue(25, forKey: "inputRadius") gaussianFilter.setValue(ciImage, forKey: kCIInputImageKey) let outputImage = gaussianFilter.outputImage let rect = ciImage.extent() let cgImage = CI_CONTEXT.createCGImage(outputImage, fromRect: rect) return UIImage(CGImage: cgImage)? } }
And that fixed it.
It's not a mind blowing solution by any means, but considering the amount of time I banged my head against the wall, trying again and again to squeeze more juice out of Xcode or logging, I'm posting it for all to see.
The Mystery of a EXC_BAD_ACCESS Thread Lock Crash
After making some additions to the app I am working on I went to testing it on the simulator and I was greeted with a brand new crash. When I went to check the console I was greeted with a weird error message:
bool _WebTryThreadLock(bool), 0xa15c170: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
Program received signal: “EXC_BAD_ACCESS”.
When first looking at this error you will probably be confused why it happend in the first place. Your given some mumbo jumbo about secondary thread and main threads, so I hit Google to get a better understand of whats going on and how to fix it.
The most likely your problem will be because you were trying to alter a UI element in a background thread, kinda like the error already says. Now in order to remedy this problem what you will have to do is find the code that is making the change to a UI object and execute on the main thread from inside your spawned thread. This is actually very simple to do, its just one method call.
The method you will need to use is the following:
[self performSelectorOnMainThread:@selector(YOUR_METHOD:) withObject:ARGUMENT waitUntilDone:YES];
Now just like when you want to run some code in a secondary thread, you will have to place the code you found that was causing your problem in its own method and call on the using the above call to execute a method on the main thread.