NSURLProtocol Tutorial

NSURLProtocol is the lesser known heart of the URL handling system in iOS. In this NSURLProtocol tutorial you will learn how to tame it. By Rocir Santiago.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 5 of this article. Click here to view the first page.

Getting Started

Now it’s time to get your hands dirty! Next, you’ll develop a simple project so you have somewhere to get to know NSURLProtocol. After completing this exercise you’ll know how to customize how an app loads URL data.

You’ll build an elementary mobile web browser, such as one that you might add to your next app. It will have a basic user interface that lets the user enter and go to a URL. The twist is that your browser will cache successfully retrieved results. This way the user can load pages he’s already visited in the twinkle of an eye, because the page won’t load from a network request, but from the app’s local cache.

You already know that fast page loads = happy users, so this is a good example of how NSURLProtocol can improve your app’s performance.

These are the steps you’re going to go through:

  • Use a UIWebView for displaying the websites
  • Use Core Data, for caching the results.

If you’re not familiar with Core Data, you can take a look into our tutorial. However, the code in this tutorial should be enough to understand the possibilities of NSURLProtocol. Using Core Data is just a simple way to implement the local cache, so it’s not essential to learn something useful here.

Starter project overview

You can download the starter project here. As soon as the download is finished, unzip it and open the project file. It will look like this:

Screen Shot 2013-12-15 at 7.30.51 PM

When you open the project, there are two main files. The first one is the Main.storyboard file. It has the UIViewController set up the way you need for implementation. Notice the UITextField (for URL input), UIButton (for firing the web requests) and UIWebView.

Open BrowserViewController.m. Here you’ll see the basic behavior set up for the UI components. This UIViewController implements the UITextViewDelegate, so you can fire the request when the user taps the return key. The IBAction for the button is pre-set to behave the same way as the return key. Last, the sendRequest method just takes the text from the textfield, creates a NSURLRequest object and sends calls the loadRequest: method from UIWebView to load it.

Once you’re familiarized with the app, build and run! When the app opens, enter “http://raywenderlich.com” and press the “Go” button. The UIWebView will load the response and display the results in the app. Pretty simple for a starting point. Now it’s time for you to stretch those finger muscles. Up next….coding!

Custom NSURLProtocol loading

Intercepting network requests

Now it’s time to start intercepting all NSURLRequest’s fired by the app. For that, you’ll need to create your own NSURLProtocol implementation.

Click File\New\File…. Select Objective-C class and hit the Next button. In the Class field, enter MyURLProtocol and in Subclass of field, enter NSURLProtocol. Finally press Next and then Create when the dialog appears.

Open MyURLProtocol.m and add this method to the class implementation:

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    static NSUInteger requestCount = 0;
    NSLog(@"Request #%u: URL = %@", requestCount++, request.URL.absoluteString);
    return NO;
}

Every time the URL Loading System receives a request to load a URL, it searches for a registered protocol handler to handle the request. Each handler tells the system whether it can handle a given request via its +canInitWithRequest: method.

The parameter to this method is the request that the protocol is being asked if it can handle. If the method returns YES, then the loading system will rely on this NSURLProtocol subclass to handle the request, and ignore all other handlers.

If none of the custom registered handlers can handle the request, then the URL Loading System will handle it by itself, using the system’s default behavior.

If you want to implement a new protocol, like foo://, then this is where you should check to see if the request’s URL scheme was foo. But in the example above, you’re simply returning NO, which tells you your app cannot handle the request. Just hold on a minute, we’ll start handling them soon!

Now, register this protocol with the loading system. Open AppDelegate.m. Then add an import for MyURLProtocol.h at the top and insert the following code within the -application:didFinishLaunchingWithOptions: method:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [NSURLProtocol registerClass:[MyURLProtocol class]];
    return YES;
}

Now that you’ve registered the class with the URL Loading System, it will have the opportunity to handle every request delivered to the URL Loading system. This includes code which calls the loading system directly, as well as many system components that rely on the URL loading framework, such as UIWebView.

Now, build and run. Insert “http://raywenderlich.com” as the website, click on “Go” and check the Xcode console. Now, for every request the app needs to perform, the URL Loading System asks your class if it can handle it.

In the console you should see something like this:

2014-01-19 06:56:02.671 NSURLProtocolExample[903:70b] Request #0: URL = http://www.raywenderlich.com/
2014-01-19 06:56:02.672 NSURLProtocolExample[903:70b] Request #1: URL = http://www.raywenderlich.com/
2014-01-19 06:56:02.672 NSURLProtocolExample[903:70b] Request #2: URL = http://www.raywenderlich.com/
2014-01-19 06:56:02.672 NSURLProtocolExample[903:70b] Request #3: URL = http://www.raywenderlich.com/
2014-01-19 06:56:02.680 NSURLProtocolExample[903:70b] Request #4: URL = http://www.raywenderlich.com/
2014-01-19 06:56:02.684 NSURLProtocolExample[903:1303] Request #5: URL = http://www.raywenderlich.com/
2014-01-19 06:56:02.828 NSURLProtocolExample[903:330b] Request #6: URL = http://www.raywenderlich.com/
2014-01-19 06:56:02.829 NSURLProtocolExample[903:330b] Request #7: URL = http://www.raywenderlich.com/
2014-01-19 06:56:02.829 NSURLProtocolExample[903:330b] Request #8: URL = http://www.raywenderlich.com/
2014-01-19 06:56:02.830 NSURLProtocolExample[903:330b] Request #9: URL = http://cdn2.raywenderlich.com/wp-content/themes/raywenderlich/style.min.css?ver=1389898954
2014-01-19 06:56:02.830 NSURLProtocolExample[903:1303] Request #10: URL = http://cdn2.raywenderlich.com/wp-content/themes/raywenderlich/style.min.css?ver=1389898954
2014-01-19 06:56:02.830 NSURLProtocolExample[903:330b] Request #11: URL = http://cdn3.raywenderlich.com/wp-content/plugins/swiftype-search/assets/autocomplete.css?ver=3.8
2014-01-19 06:56:02.831 NSURLProtocolExample[903:1303] Request #12: URL = http://cdn3.raywenderlich.com/wp-content/plugins/swiftype-search/assets/autocomplete.css?ver=3.8
2014-01-19 06:56:02.831 NSURLProtocolExample[903:330b] Request #13: URL = http://www.raywenderlich.com/wp-content/plugins/wp-polls/polls-css.css?ver=2.63
2014-01-19 06:56:02.839 NSURLProtocolExample[903:1303] Request #14: URL = http://www.raywenderlich.com/wp-content/plugins/wp-polls/polls-css.css?ver=2.63
2014-01-19 06:56:02.840 NSURLProtocolExample[903:330b] Request #15: URL = http://cdn1.raywenderlich.com/wp-content/plugins/powerpress/player.js?ver=3.8
2014-01-19 06:56:02.840 NSURLProtocolExample[903:1303] Request #16: URL = http://cdn1.raywenderlich.com/wp-content/plugins/powerpress/player.js?ver=3.8
2014-01-19 06:56:02.843 NSURLProtocolExample[903:330b] Request #17: URL = http://cdn5.raywenderlich.com/wp-content/plugins/swiftype-search/assets/install_swiftype.min.js?ver=3.8

For now, you’re just logging the string representation of the request’s URL and returning NO, which means your custom class cannot handle the request. But if you look into the logs, you’ll see all the requests made from the UIWebView. It includes the main website (.html) and all the assets, such as JPEGs and CSS files. Every time the UIWebView needs to fire a request, it’s logged to the console before it’s actually fired. The count should show you a mountain of requests — likely over five hundred — because of all the assets on the Ray Wenderlich page.

Rocir Santiago

Contributors

Rocir Santiago

Author

Over 300 content creators. Join our team.