Crash Analysis with HP AppPulse Mobile on iOS
Written by Eddie Freeman   
Monday, 11 April 2016
Article Index
Crash Analysis with HP AppPulse Mobile on iOS
Debugging in AppPulse Mobile

Accessing the Name

Setting up your environment from a previously saved state without hitting a server is a pretty common desire. However, if something goes wrong you won't necessarily get much context. We'll demonstrate this when trying to grab the username set from a previous state.

Debugging in AppPulse Mobile

You launch the app on a new device and suddenly there's a crash. Diving into the crash, it seems like there's a scenario in which launch crashes on app load can happen:

 

appulse2

 

The timeline shows that one of the major events I flagged earlier is causing the problem:

 

appulse3

 

Buggy Block - After checking, I found that I was accessing the wrong key from NSUserDefaults:

 

func getName() -> String {
 HPAppPulse.addBreadcrumb(
          "Setting userName to user saved")
 userName = defaults.objectForKey("user_Name")
                                      as! String
 return userName
}

 

Fixed Block - I realized that I'm calling NSUserDefaults too often in the previous snippet and not checking for nil from a forced unwrap.
To fix this, I move the NSUserDefaults code to the GoodFeelsClient init() with this:

 

if let name = defaults.objectForKey("userName") {
 userName = name as! String
 HPAppPulse.addBreadcrumb(
             "Setting userName to user saved")
} else {
 userName = ""
 HPAppPulse.addBreadcrumb("Setting userName to empty")
}

In A Threaded Task

A stack trace can get muddled when a threaded task completes or causes a crash later in a program than when it was started. We'll attempt to demonstrate this while collecting the contacts list.

Debugging in AppPulse Mobile

In this case having intelligently placed breadcrumbs saved me time as I got accurate feedback to focus on where the issue arose. I found the problem during change notification dispatch:

 

appulse4

 

Buggy Block - This led me to find the issue in this block:

func contentChangedNotification(
      notification: NSNotification!) {
 contacts = GoodFeelsClient.sharedInstance.contacts
 contactsTableView?.reloadData()
 AlertController.showWithTitle(
  "\(GoodFeelsClient.sharedInstance.contacts.count)  Contacts", message: "Last Contact: \(GoodFeelsClient.
    sharedInstance.contacts.first?.
        phoneticFamilyName)", actionTitle: "OK")
}

 

Fixed Block - By protecting the contact object and formatting it properly I am able to resolve the issue:

func contentChangedNotification(
          notification: NSNotification!) {
 contacts = GoodFeelsClient.sharedInstance.contacts
 contactsTableView?.reloadData()
 if let contact =
   GoodFeelsClient.sharedInstance.contacts.last {
  AlertController.showWithTitle(
  "\(GoodFeelsClient.sharedInstance.contacts.count)  
  Contacts", message: "Last Contact: \  
   (CNContactFormatter.stringFromContact(
    contact, style: .FullName)!)",
     actionTitle: "OK")
 }
}

 

A Segfault in Transit

Trying to access or write to an illegal memory location can happen to the best of us. We'll demonstrate this when preparing to send the text message.

Debugging in AppPulse Mobile

The section in AppPulse Mobile makes where this crash happens pretty obvious:

 

appulse5

 

Then I drill down into the timeline to see more:

appulse6

(click to enlarge)

Buggy Block - Looking closely it seems like I wasn't checking to make sure the device could actually send a text message:

@IBAction func sendText(sender: UIButton) {
 if !selectedContacts.isEmpty {
                // the culprit conditional

  HPAppPulse.addBreadcrumb(
     "Sending Text via Composed Message")
  let controller = GoodFeelsClient.sharedInstance.
          configuredMessageComposeViewController(
 
     Array(selectedContacts.keys),

     textBody:GoodFeelsClient.
          sharedInstance.selectedMessage)
 
 self.presentViewController(controller,
             animated: true, completion: nil)
 }
}

Fixed Block - Simply adding that check to the conditional resolves the issue:

@IBAction func sendText(sender: UIButton) {
 
if !selectedContacts.isEmpty &&
  GoodFeelsClient.sharedInstance.canSendText() {
   // adds functionality to check
   // for txting capability

  HPAppPulse.addBreadcrumb(
      "Sending Text via Composed Message")
  let controller = GoodFeelsClient.sharedInstance.
     configuredMessageComposeViewController(

      Array(selectedContacts.keys),

      textBody: GoodFeelsClient.
             sharedInstance.selectedMessage)

      self.presentViewController(controller,
         animated: true, completion: nil)
 } else {
  print("This device cannot send SMS messages.")
 }
}

Conclusions

In the debugging of each scenario, we demonstrated how usage of breadcrumbs became integral to determine the user behavior that led up to a crash and the originating thread.

Even without the breadcrumbs, the organization of crashes by users impacted and by actions causing the crash let me understand at a glance where I needed to focus my attention.

 AppPulse2

 
 

 

  • Eddie Freeman is an iOS developer at Ticketfly, a technology company reimagining live events for everyone by using powerful ticketing, digital marketing, and analytics software. Eddie is also an independent contractor providing consultations in mobile, product, and/or community strategies, building mobile apps and writing about technology. 

 

 

More Information

HP App Pulse Mobile

Related Articles

Using HP AppPulse With iOS

Animated iOS User Interfaces

Analytics As A Service 

Monitor Mobile 

Deep Monitor Your Site 

 

Banner

 

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, FacebookGoogle+ or Linkedin



Last Updated ( Tuesday, 12 April 2016 )