I am having trouble understanding the UIKit crash reports that I am receiving:
Is there a way of finding out what line of code caused this:
Crashed: com.apple.main-thread
0 UIKit 0x195694264 __56-[UIPresentationController runTransitionForCurrentState]_block_invoke + 444
1 UIKit 0x1955d0950 _runAfterCACommitDeferredBlocks + 292
2 UIKit 0x1955c29ec _cleanUpAfterCAFlushAndRunDeferredBlocks + 528
3 UIKit 0x195336648 _afterCACommitHandler + 132
4 CoreFoundation 0x18f1c09a8 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
5 CoreFoundation 0x18f1be630 __CFRunLoopDoObservers + 372
6 CoreFoundation 0x18f1bea7c __CFRunLoopRun + 956
7 CoreFoundation 0x18f0eeda4 CFRunLoopRunSpecific + 424
8 GraphicsServices 0x190b58074 GSEventRunModal + 100
9 UIKit 0x1953a9058 UIApplicationMain + 208
10 FlexConnect 0x1001b48c8 main (AppDelegate.swift:20)
11 libdyld.dylib 0x18e0fd59c start + 4
The error itself is:
Crashed: com.apple.main-thread
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000010
EDIT:
Based of the answer below, I'm wondering if it is advisable to use:
func topMostController() -> UIViewController {
var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
while (topController.presentedViewController != nil) {
topController = topController.presentedViewController!
}
return topController
}
and always call
let topVC = topMostController().dismiss(animated: true, completion: nil)
everywhere in my app where I currently have self.dismiss(animated: true, completion: nil)?
Is this a necessary check or how can I pin down where self.dismiss is having an issue?
Some sample dismissals:
@IBAction func returnToDash(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
let pending = UIAlertController(title: "\n\n\n\(title)", message: nil, preferredStyle: .alert)
displayActivityAlertWithCompletion2(ViewController: self, pending: pending){_ in
Helper_StatusCheck.doSync(_cleanSync: false){
Prefs.is_Syncing = false
DispatchQueue.main.async {
pending.dismiss(animated: true){
Toast(text: "Upload sync completed").show()
self.dismiss(animated: true, completion: nil)
}
}
}
}
where displayActivityAlertWithCompletion2 looks like:
public func displayActivityAlertWithCompletion2(ViewController: UIViewController, pending: UIAlertController, completionHandler: @escaping ()->())
{
//let pending = UIAlertController(title: "\n\n\n"+title, message: nil, preferredStyle: .alert)
//create an activity indicator
let indicator = UIActivityIndicatorView(frame: pending.view.bounds)
indicator.autoresizingMask = [.flexibleWidth, .flexibleHeight]
indicator.color = UIColor(rgba: Palette.loadingColour)
//add the activity indicator as a subview of the alert controller's view
pending.view.addSubview(indicator)
indicator.isUserInteractionEnabled = false
// required otherwise if there buttons in the UIAlertController you will not be able to press them
indicator.startAnimating()
ViewController.present(pending, animated: true, completion: completionHandler)
}
EDIT 2 :
Some sample popover methods in my app:
@IBAction func search(_ sender: UIButton) {
if let popView = UIStoryboard(name: "AssetCommon", bundle: nil).instantiateViewController(withIdentifier: "searchPop") as? searchPopVC {
popView.delegate = self
popView.modalPresentationStyle = .popover;
popView.popoverPresentationController?.delegate = self
popView.popoverPresentationController?.barButtonItem = searchButton
popView.popoverPresentationController?.permittedArrowDirections = .any
popView.preferredContentSize = CGSize(width: 300, height: 70)
self.present(popView, animated: true, completion: nil)
}
}
and search pop:
class searchPopVC: UIViewController
{
@IBOutlet weak var searchBar: UISearchBar!
weak var delegate: SearchPopDelegate?
override func viewDidLoad()
{
super.viewDidLoad()
searchBar.delegate = self;
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
@IBAction func performSearch(_ sender: UIButton)
{
let term = searchBar.text ?? "";
delegate?.performSearch(with: term)
self.dismiss(animated: true, completion: nil);
}
}
extension searchPopVC: UISearchBarDelegate
{
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
let term = searchBar.text ?? "";
delegate?.performSearch(with: term);
self.dismiss(animated: true, completion: nil)
}
}
You won't be able to find the line of code from this crash. However, this crash happens when the view controller you use to call dismiss(animated:completion:)
is removed from the view hierarchy prior to the animation completing.
Depending on how your code is setup, you can try to request a view controller higher up to call the dismissal. Another solution could be to retain the view controller in a property until your for sure done with it.
Edit: 1/5/18
In response to the comments, here is an example of how a function can be made for view controllers that logs an event and dismisses.
extension UIViewController {
func dismissAndLog(animated: Bool, completion: (() -> ())? = nil) {
// Here are two examples of how your view controller can be identified.
// let id = title
let id = String(describing: type(of: self))
CLSLogv("Dismissed View Controller: %@", getVaList([id]))
dismiss(animated: animated, completion: completion)
}
}
I'm not entirely familiar with Crashlytics or their API, so if this logging is giving you issues, you can check out these links.
Also I don't know how they provide the data to you, so I can't explain to you the best way to parse it. However certainly the timestamps can be successfully used as a final solution. You can also try emailing their support asking for the best way to map these logs to the crash.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With