How To: Instrument A Swift iOS App With New Relic Mobile

By Jonathan Karon Posted in Tech Topics 12 June 2014
I make iOS apps. I care about how stable and performant they are, so I’m excited by Apple’s announcement of its latest programming language, Swift. People have been asking me what it means for New Relic Mobile.
swift1We’ve been experimenting with Swift. Of course we’re curious about how Swift code interacts with the Objective-C runtime and what app execution looks. Read on to learn what makes Swift apps tick and how we wired up the New Relic SDK to get a preview of what the future holds.
In this blog post I will:
  1. Explain how Swift interacts with Objective-C,
  2. Show you how to get New Relic running in a Swift app, and
  3. Share some simple Swift code that demonstrates the power of code-level tracing.

Is it possible to instrument Swift apps?

Swift apps use Cocoa frameworks like Foundation and UIKit, just like Objective-C apps. Your Swift code runs side-by-side with system frameworks, C libraries, and other Objective-C code. New Relic already automatically instruments many of those libraries. So with a few minutes of work you will get the same visibility into networking, image loading, JSON parsing, and CoreData that you get in traditional iOS apps.
Your Swift code itself is compiled down to machine code and is not visible to the current New Relic SDK. However, we can make use of the Swift/Objective-C bridge to capture performance data of your Swift classes and see how it interacts with the underlying Cocoa APIs that we already instrument.

Running New Relic in a Swift app

Deploying New Relic’s iOS SDK into a Swift app is almost exactly like an Objective-C app. The one difference is that you’ll have to set up your app to be a “mixed target” and configure the bridging code that allows Swift and Objective-C to talk to each other. This is covered in step 3 below.
1. Create a new iOS swift app in XCode
If you’re an experienced developer, this one should need no explanation. I’ve created an app called Vaux’s Swift.
2. Add the New Relic framework
Drag NewRelicAgent.framework into your project just like you’ve always done.
swift11
3. Set up a Bridging Header
Swift provides a mechanism, called Bridging, that allows Swift and Objective-C code to interact within the app. This bridging behavior has to be enabled for each project.
How to enable bridging: If you don’t have a “[Project Name]-Bridging-Header.h” file in your project, the simplest way to set it up is to create an Objective-C file, name it Placeholder.m. XCode will prompt you to setup the Bridging Header.
swift3
How to bridge the New Relic SDK: Now open the Bridging-Header and #import the New Relic header.
1
2
3
4
5
6
//  vaux_s_swift-Bridging-Header.h
//
//  Use this file to import your target's public headers
//    that you would like to expose to Swift.
//
#import "NewRelicAgent/NewRelic.h"
Once you’ve done this, it’s safe to delete the Placeholder.m file.
4. Initialize the agent in your AppDelegate.swift
1
2
3
4
5
6
7
8
9
10
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
var window: UIWindow?
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
// Swift exposes the NewRelic class
NewRelic.startWithApplicationToken("YOUR_APP_TOKEN_HERE")
return true
}

5. Add the required frameworks and libraries to your build settings
Select your project in the navigator, then the application target, and the General properties tab. Scroll down to “Linked Frameworks” and ensure NewRelicAgent, CoreTelephony, SystemConfiguration, and libz.dylib are shown.
swifttttt
6. Fire it up!
When you run your app, it will initialize the SDK and report performance data to New Relic.
swift31
Because Swift builds upon the Cocoa frameworks we already instrument, you’ll see network analytics, UIImage and JSON loading, etc.

Better Interaction tracing

Now that you’re up and running, you’ll notice that all of your Interactions show up in New Relic named UIViewController. Swift implements view controllers by subclassing the Objective-C UIViewController class. New Relic doesn’t yet automatically detect these subclasses.
We can make your data much more interesting by starting Interaction traces at the right point in your Swift code. Simply add a call to NewRelic.startInteractionFromMethodName() in each Swift ViewController to improve the data New Relic reports.
1
2
3
4
5
6
7
 class ViewController: UIViewController {
     override func viewDidLoad() {
      // Manually start tracing the Interaction here,
// rather than in the UIViewController parent class 
        NewRelic.startInteractionFromMethodName("viewDidLoad", object: self)
        super.viewDidLoad()
     }
Rebuild and run the app. After a couple of minutes, you will see an Interaction named after the generated name of each Swift ViewController class.

Using the New Relic SDK to instrument your Swift native code

Let’s look at instrumenting some of our Swift application code using New Relic’s SDK.
As I mentioned earlier, at present the New Relic SDK does not automatically instrument compiled Swift code. First, I will create a helper class to make interacting with the SDK a bit easier. Then I’ll create a simple image downloader and add custom instrumentation using the helper class.
1. Implementing an SDK helper
Create a new NRHelpers.swift file.
1
2
3
4
5
6
7
8
9
10
11
12
13
import Foundation
 class NRMethodTimer {
     var timer: NRTimer
     init(methodName name:String, forObject context:AnyObject,
 ofCategory category:NRTraceType) {
         timer = NRTimer()
         NewRelic.startTracingMethod(Selector(name), object: context, 
  timer: timer, category: category)
     }
     func exit() {
         NewRelic.endTracingMethodWithTimer(timer)
     }
 }
Note: In Swift, instances of classes and structures are technically referred to as instances, not objects. As the New Relic SDK operates specifically on objects, we have chosen to use the object naming convention in this code.
2. Implement an ImageFetcher helper class
ImageFetcher takes care of downloading an image from a URL and loading it into a UIImageView.
After initializing an instance, you call run() to initiate the asynchronous retrieve and display functionality. Once the network request completes, the finish() method creates a UIImage and displays it in the stored UIImageView.
You’ll notice I am using the NRMethodTimer to instrument the methods I care about.
3. Adding a UIImageView and loading an image
I’ve added a new method, ViewController.loadImage(), that takes care of creating and starting a new ImageFetcher. In ViewController.viewDidLoad(), I create a UIImageView and call loadImage() to populate it asynchronously.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ViewController: UIViewController {
    func loadImage(source imageSource:String, forView imageView:UIImageView) {
        let timer = NRMethodTimer(methodName: "loadImage", forObject: self,
ofCategory: NRTraceTypeViewLoading)
 let loader = ImageFetcher(source: imageSource, forView: imageView)
        loader.run()
  timer.exit()
    }
    override func viewDidLoad() {
        NewRelic.startInteractionFromMethodName("viewDidLoad", object: self)
        super.viewDidLoad()
        // an image to retrieve
        let sourceUrl = 
"https://farm4.staticflickr.com/3843/14356460721_3a1bdf3b40_b.jpg"
        // a view to display it
        let iView = UIImageView(frame: CGRectMake(10, 10, 340, 340))
        self.view.addSubview(iView)
        self.loadImage(source: sourceUrl, forView: iView)
    }
// other ViewController methods
}
4. Enjoying the results
Now in the Interaction breakdown you see execution data for all of your instrumented methods alongside the Cocoa APIs New Relic automatically instruments.
swift32
Digging deeper into Interaction traces, you’ll see the Swift methods that make use of NRMethodTimer. Here’s a snapshot showing ImageFetcher.finish(), which creates a UIImage from the downloaded data and then assigns it to the saved UIImageView.
swiftfinal
At New Relic, we’ll continue to explore performance monitoring of apps built using Swift, and keep you updated on any interesting outcomes. In the meanwhile, if you want to try this out for one of your own Swift apps, download New Relic Mobile. Until next time, happy app building!
You can download the source for this demo app, including NRMethodTimer and ImageHelper,  from GitHub here: https://github.com/newrelic/vauxs-swift
**Swift image via Flickr/Kat+Sam.

1 comment: