📜 ⬆️ ⬇️

Using NSURLProtocol in Swift

NSURLProtocol is a kind of magic key to a URL. It allows you to override the URL loading system, Apple defines custom URL schemes and overrides existing URL schemes.

Does this seem magical? It should be so. Because if you look for them, you will find that the URL, almost like love, is around us. What do UIWebView or WKWebView use? They use the URL. What is used to broadcast video from MPMoviePlayer? To do this, use the URL. How do you send someone to your application on iTunes , launch FaceTime or Skype, launch another application in the system or even insert an image in an HTML file ? Using URL. Take a look at the NSFileManager and note how many file handling methods URLs are needed for.

In this article about NSURLProtocol, you will learn how to define a protocol handler that modifies the URL of a scheme. It will add raw and ready-made transparent caching layer, saving extracted resources to Core Data. By launching it into operation, the regular UIWebView can then take on the role of a browser, caching the loaded pages so that you can later view them in offline mode.
')


Before you plunge into this with your head, you will need to learn basic network concepts and become familiar with how NSURLConnection works. If you are not currently familiar with NSURLConnection , then I suggest you read this tutorial and / or document from Apple .

Well, are you ready now to study what the NSURLProtocol is for? Well, go make yourself a cup of tea and get ready for a meaningful, mind-developing discussion and step-by-step application.

Start

In the context of the design of this tutorial, you will create an elementary mobile web browser that you could possibly add to your next application. It will have a basic user interface that allows the user to enter and open a URL. A characteristic feature is that your browser successfully caches the results. In this way, the user can load the previously visited pages in the blink of an eye, because the page will be loaded not from the network request, but from the local application cache.

You already know that if pages load quickly, users are happy, that is, this is a good example of how the NSURLProtocol can improve the performance of your application.

You need to complete the following steps:


If you are not familiar with the Core Data database, you can take a look at our tutorial . However, the code in this tutorial should be sufficient to understand the capabilities of the NSURLProtocol. Using the Core Data database is an easy way to put the local cache into effect, so it’s not so important to learn something useful here.

Start Project Overview

You can download the start project here . Once the download is complete, unzip and open the project file.

When you open the project, you will find two main files. The first is the Main.storyboard file. It contains the UIViewController required to implement it. Note the UITextField (for entering the URL), the UIButton (for launching web requests) and the UIWebView.

Open the BrowserViewController.swift file. Here you will see the main mode of operation configured for the UI components. This UIViewController supports the UITextFieldDelegate protocol, and you can run a query when the user presses the enter key. The IBAction for the button is set to work in the same way as the enter key. Finally, the sendRequest () method simply takes the text from the text field, creates an NSURLRequest object, and calls the loadRequest method (_ :) for the UIWebView to load it.

Once you are familiar with the application, compile and run it! When the application starts, enter “http://raywenderlich.com” and click “Go”. UIWebView will load the response and display the result in the application. Pretty simple to start with. Now it's your turn to pull your fingers. Next ... coding!

Interception of network requests

A number of classes, known as the URL Download System , process URL requests on iOS. At the heart of the URL Loading System is the NSURL class. For network requests, this class shows which host is trying to reach your application, and also shows the path to the resource in this host. In addition, the NSURLRequest object adds information such as HTTP headers, the bulk of your message, etc. The loading system provides several different classes that you can use to process a request, the most common being NSURLConnection and NSURLSession.

Now it's time to start intercepting all NSURL requests launched by the application. To do this, you will need to create your own implementation of the NSURL protocol.

Click File \ New \ File .... Select iOS \ Source \ Cocoa Touch Class and press the Next key. In the Class field, enter MyURLProtocol and in the Subclass of field, enter NSURLProtocol. Check that the language is Swift. Finally, click Next and then Create when the dialog appears.

Open the file MyURLProtocol.swift and replace its contents with the following:

import UIKit var requestCount = 0 class MyURLProtocol: NSURLProtocol { override class func canInitWithRequest(request: NSURLRequest) -> Bool { println("Request #\(requestCount++): URL = \(request.URL.absoluteString)") return false } } 


Each time the Download System URL receives a request to load a URL, it searches for a registered protocol handler to process the request. Each handler notifies the system if it can process this request with its own method canInitWithRequest (_ :).

The parameter to this method is a query about whether the protocol can process it. If the method returns true, the load system will rely on this subclass of the NSURL protocol to process the request and ignore all other handlers.

If none of the registered persistent handlers can process the request, the URL loading system will process it itself using the default mode.

If you want to execute a new protocol, such as foo: //, it is here that you need to check that the URL scheme request is foo. But in the example above, you get a false response, which indicates that your application cannot process the request. Wait a little, you will soon begin to process them!

Note: NSURLProtocol must be an abstract class. You create a subclass in the individual mode for the NSURLProtocol, but you should never handle the NSURLProtocol directly.

Open AppDelegate.swift and replace the method.

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool { NSURLProtocol.registerClass(MyURLProtocol) return true } 


Now that your application is running, it will register the protocol in the URL Download System. This means that it will be able to process every request received by the download system URL. This includes coding that directly requests the download system, as well as many system components that are based on the URL loading structure, such as UIWebView.

Compile the project and run it. Insert the line " raywenderlich .com" as a website line, press the Go key and check the Xcode console. Now for each request that the application must fulfill, the Download System URL will ask your class if it can process it.

In the console, you should see something like this:

 Request #0: URL = http://raywenderlich.com/ Request #1: URL = http://raywenderlich.com/ Request #2: URL = http://raywenderlich.com/ Request #3: URL = http://raywenderlich.com/ Request #4: URL = http://raywenderlich.com/ Request #5: URL = http://raywenderlich.com/ Request #6: URL = http://www.raywenderlich.com/ Request #7: URL = http://www.raywenderlich.com/ Request #8: URL = http://www.raywenderlich.com/ Request #9: URL = http://www.raywenderlich.com/ Request #10: URL = http://www.raywenderlich.com/ Request #11: URL = http://www.raywenderlich.com/ Request #12: URL = http://raywenderlich.com/ Request #13: URL = http://cdn3.raywenderlich.com/wp-content/themes/raywenderlich/style.min.css?ver=1402962842 Request #14: URL = http://cdn3.raywenderlich.com/wp-content/plugins/swiftype-search/assets/autocomplete.css?ver=3.9.1 Request #15: URL = http://cdn4.raywenderlich.com/wp-content/plugins/videojs-html5-video-player-for-wordpress/plugin-styles.css?ver=3.9.1 Request #16: URL = http://vjs.zencdn.net/4.5/video-js.css?ver=3.9.1 Request #17: URL = http://cdn3.raywenderlich.com/wp-content/themes/raywenderlich/style.min.css?ver=1402962842 ... 

At this point, your class simply registers the request URL sequentially and returns false, which means that your custom class cannot process the request. But if you view the registration records, you will see all the requests sent from UIWebView. These include the main website (.html) and all assets, such as JPEGs and CSS files. Each time a UIWebView needs to launch a request, it is registered in the console before it starts. The total should show you a mountain of requests, probably more than five hundred, because of all the assets on the web page.

So, this is what you need to do: Your custom class receives a notification about each URL request, and then you can do something with each request!

How do you get the data?

“I like it when pages load for ages,” you’ll never hear from anyone. That is, you now have to make sure that your application can process requests. As soon as you get a true answer in canInitWithRequest (_ :), your class is simply obliged to fully process this request. This means that you must receive the requested data and send it back to the URL Download System.

How do you get the data?

If you run the network protocol of a new application from scratch (for example, add the foo: // protocol), then here you will know the joys of implementing the network protocol of the application. But since your task is to just insert a custom caching layer, you can simply retrieve the data using NSURLConnection.

Your custom NSURLProtocol subclass returns data through an object that implements the NSURLProtocolClient protocol. In order not to get confused in the names, remember: NSURLProtocol is a class, and NSURLProtocolClient is a protocol!

Through the client, you notify the URL Download System of the postback of changes in operation, responses and data.

In essence, you simply intercept the request and then transfer it back to the standard URL Download System using NSURLConnection.

Open the file MyURLProtocol.swift and add the following characteristic at the top of the definition of the class MyURLProtocol:

 var connection: NSURLConnection! 


Then, find canInitWithRequest (_ :). Enter true in the answer field:

 return true 


Now add four more methods:

 override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest { return request } override class func requestIsCacheEquivalent(aRequest: NSURLRequest, toRequest bRequest: NSURLRequest) -> Bool { return super.requestIsCacheEquivalent(aRequest, toRequest:bRequest) } override func startLoading() { self.connection = NSURLConnection(request: self.request, delegate: self) } override func stopLoading() { if self.connection != nil { self.connection.cancel() } self.connection = nil } 


Your protocol itself defines what “canonical request” means, but at a minimum it must answer an incoming request with the same canonical request. Thus, if two semantically equal queries are entered (that is, not necessarily = = =) for this method, then outgoing queries must also be semantically equal. For example, if the case of letters for your custom URL scheme is irrelevant, then all canonical URLs are lowercase.

To comply with the minimum standard, simply return the request itself. As a rule, this is a reliable competent decision, since you usually should not change the request. In the end, you trust the developer, right? What you could do here, for example, modify the query by adding a header and return a new query.

The requestIsCacheEquivalent (_: toRequest :) is where you should not rush to determine when two different requests for a custom URL scheme (i.e., foo: //) are equal in terms of cache capabilities. If the two queries are equal, then they must use the same cached data. This concerns your own, built-in URL Loading System caching system, which you should ignore for this tutorial. So for this exercise, simply rely on the default superclass implementation.

The boot system uses startLoading () and stopLoading () to send a signal to your NSURLProtocol to start and stop processing the request. Your start of the implementation puts the NSURLConnection sample to download the data. There is also a stop method so that URL loading can be canceled. In the above example, it was allowed to cancel the current connection and get rid of it.

Hooray! You have installed an interface that needs a valid NSURLProtocol example. If you want to read more, see the official documentation describing the methods that a valid subclass of NSURLProtocol can perform.

But your coding is not done yet! You have yet to process the request that you carry out using the transmitted callbacks from NSURLConnection that you have created.

Open the MyURLProtocol.swift file and add the following methods:

 func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!) { self.client!.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .NotAllowed) } func connection(connection: NSURLConnection!, didReceiveData data: NSData!) { self.client!.URLProtocol(self, didLoadData: data) } func connectionDidFinishLoading(connection: NSURLConnection!) { self.client!.URLProtocolDidFinishLoading(self) } func connection(connection: NSURLConnection!, didFailWithError error: NSError!) { self.client!.URLProtocol(self, didFailWithError: error) } 


These are all methods of the NSURLConnection delegate. They are used when the NSURLConnection sample you use to load data responds when it has data, when the download is complete and when a failure occurs. In each of these cases, you must pass this information to the client.

Thus, summing up, your handler MyURLProtocol creates its own NSURLConnection and asks it to process the request. In the NSURLConnection callback methods listed above, the protocol handler sends messages from the network back to the Download System URL. These messages notify you of the download progress, process completion, or errors.

Take a look and you will see a very close similarity in the message signatures for NSURLConnectionDelegate and NSURLProtocolClient, they both are APIs for asynchronous data loading. Also note how MyURLProtocol uses its client characteristic to send messages back to the URL loading system.

Compile the project and run it. When the application starts, enter the same URL and press the Go key.

Oh oh oh! Your browser does not download anything anymore! If you look at Troubleshooting Navigator while it works, you will see that memory usage is getting out of control. The console should display a racing list of innumerable requests for the same URL. What could be wrong?

In the console, you should see that the lines are always registered like this:

 Request #0: URL = http://raywenderlich.com/ Request #1: URL = http://raywenderlich.com/ Request #2: URL = http://raywenderlich.com/ Request #3: URL = http://raywenderlich.com/ Request #4: URL = http://raywenderlich.com/ Request #5: URL = http://raywenderlich.com/ Request #6: URL = http://raywenderlich.com/ Request #7: URL = http://raywenderlich.com/ Request #8: URL = http://raywenderlich.com/ Request #9: URL = http://raywenderlich.com/ Request #10: URL = http://raywenderlich.com/ ... Request #1000: URL = http://raywenderlich.com/ Request #1001: URL = http://raywenderlich.com/ 


You need to go back to Xcode and stop the application before trying to fix the problem.

Suppression of an infinite loop with tags

Think again about the URL Loading System and protocol registration, and maybe you will understand why this is happening. When UIWebView wants to load a URL, the Download System URL asks MyURLProtocol if it can process this particular request. If your class returns true, then it can process it.

Thus, the URL Download System will create a sample of your protocol and call startLoading. Then the implementation begins and its NSURLConnection is launched. But it also calls the URL Loading System. And what do you think? Since you always get a true response in the canInitWithRequest (_ :) method, it creates another copy of MyURLProtocol.

This new copy will create another one, and then another, and then an infinite number of copies. That is why your application does not download anything! It just continues to allocate more memory and shows only one URL in the console. Poor browser gets stuck in an endless loop! Your users may be so desperate that they can even cause damage to their devices.

Obviously, you cannot always get a true response in the canInitWithRequest (_ :) method. You must have some sort of control to let the Download System URL handle the request only once. The solution is in the NSURLProtocol interface. Look for a class method called setProperty (_: forKey: inRequest :) that allows you to add custom properties to a given URL request. This way, you can 'tag' it by attaching a property to it, and the browser will know if it has already seen it before.

Thus, you display the browser from an infinite loop. Open the file MyURLProtocol.swift. and replace the startLoading () and canInitWithRequest (_ :) methods with the following:

 override class func canInitWithRequest(request: NSURLRequest!) -> Bool { println("Request #\(requestCount++): URL = \(request.URL.absoluteString)") if NSURLProtocol.propertyForKey("MyURLProtocolHandledKey", inRequest: request) != nil { return false } return true } override func startLoading() { var newRequest = self.request.copy() as NSMutableURLRequest NSURLProtocol.setProperty(true, forKey: "MyURLProtocolHandledKey", inRequest: newRequest) self.connection = NSURLConnection(request: newRequest, delegate: self) } 


Now in the startLoading () method, it sets the property associated with the key “MyURLProtocolHandledKey” and assigns it true for this request. This means that the next time canInitWithRequest (_ :) is called for a given NSURLRequest object, the protocol may ask if the same property is installed.

If it is set, it returns true, it means that you do not need to process this request anymore. System Download URL will download data from the network. Since your copy of MyURLProtocol is sent for that request, it will receive callbacks from NSURLConnectionDelegate.

Compile and run the application. The application will successfully display web pages in your webview. Sweet victory! The console should now look something like this:

 Request #0: URL = http://raywenderlich.com/ Request #1: URL = http://raywenderlich.com/ Request #2: URL = http://raywenderlich.com/ Request #3: URL = http://raywenderlich.com/ Request #4: URL = http://raywenderlich.com/ Request #5: URL = http://raywenderlich.com/ Request #6: URL = http://raywenderlich.com/ Request #7: URL = http://raywenderlich.com/ Request #8: URL = http://raywenderlich.com/ Request #9: URL = http://www.raywenderlich.com/ Request #10: URL = http://www.raywenderlich.com/ Request #11: URL = http://www.raywenderlich.com/ Request #12: URL = http://raywenderlich.com/ Request #13: URL = http://cdn3.raywenderlich.com/wp-content/themes/raywenderlich/style.min.css?ver=1402962842 Request #14: URL = http://cdn3.raywenderlich.com/wp-content/plugins/swiftype-search/assets/autocomplete.css?ver=3.9.1 Request #15: URL = http://cdn4.raywenderlich.com/wp-content/pluginRse/qvidueeosjts -#h1t6m:l URL = ht5t-pv:i/d/ecodn3.raywenderlich.com/-wppl-acyoenrtent/themes/raywenderlich/-sftoyrl-ew.omridnp.css?vreers=s1/4p0l2u9g6i2n8-4s2t yles.css?ver=3.9.1 Request #17: URL = http://cdn3.raywenderlich.com/wp-content/themes/raywenderlich/style.min.css?ver=1402962842 Request #18: URL = http://vjs.zencdn.net/4.5/video-js.css?ver=3.9.1 Request #19: URL = http://www.raywenderlich.com/wp-content/plugins/wp-polls/polls-css.css?ver=2.63 Request #20: URL = http://cdn3.raywenderlich.com/wp-content/plugins/swiftype-search/assets/autocomplete.css?ver=3.9.1 Request #21: URL = http://cdn3.raywenderlich.com/wp-content/plugins/swiftype-search/assets/autocomplete.css?ver=3.9.1 Request #22: URL = http://cdn4.raywenderlich.com/wp-content/plugins/powerpress/player.min.js?ver=3.9.1 Request #23: URL = http://cdn4.raywenderlich.com/wp-content/plugins/videojs-html5-video-player-for-wordpress/plugin-styles.css?ver=3.9.1 Request #24: URL = http://cdn4.raywenderlich.com/wp-content/plugins/videojs-html5-video-player-for-wordpress/plugin-styles.css?ver=3.9.1 Request #25: URL = http://cdn3.raywenderlich.com/wp-content/themes/raywenderlich/style.min.css?ver=1402962842 Request #26: URL = http://cdn3.raywenderlich.com/wp-content/plugins/swiftype-search/assets/autocomplete.css?ver=3.9.1 ... 


You may wonder why you did all this just to make the application work exactly as it did when you started. Well, because you have to prepare for the fun part! Now you have all control over the data from the URL of your application, and you can do whatever you want with it. It's time to start caching the received data of your application.

Local cache injection

Remember the basic requirement for this application: for this request, data from the network must be downloaded only once, and then they need to be cached. If the same request is launched again in the future, your protocol will return a cached response without loading it from the network.

Note: the starting project already includes the core Core Data model and stack. You do not need to know the details of Core Data, you can think of it as a dark data warehouse; If you're interested, check out Apple's Core Data Guide.

It's time to save the answers your application receives from the network and retrieve them when the corresponding cached data appears. Open the MyURLProtocol.swift file and add the following import at the top of the file:

 import CoreData 


Then add two variables in the class definition:

 var mutableData: NSMutableData! var response: NSURLResponse! 


The response variable will store a link to the metadata you need when saving the response from the server. The mutableData variable will be used to store data that it receives in the delegate method of connection (_: didReceiveData :). When the answer comes, you can cache the data and metadata.

Then add the following method to the class:

 func saveCachedResponse () { println("Saving cached response") // 1 let delegate = UIApplication.sharedApplication().delegate as AppDelegate let context = delegate.managedObjectContext! // 2 let cachedResponse = NSEntityDescription.insertNewObjectForEntityForName("CachedURLResponse", inManagedObjectContext: context) as NSManagedObject cachedResponse.setValue(self.mutableData, forKey: "data") cachedResponse.setValue(self.request.URL.absoluteString, forKey: "url") cachedResponse.setValue(NSDate(), forKey: "timestamp") cachedResponse.setValue(self.response.MIMEType, forKey: "mimeType") cachedResponse.setValue(self.response.textEncodingName, forKey: "encoding") // 3 var error: NSError? let success = context.save(&error) if !success { println("Could not cache the response") } } 


Here is what this method does:
  1. Get Core Data NSManagedObjectContext from an AppDelegate instance. The context of the object being manipulated is your interface to Core Data.
  2. Create an instance of the NSManagedObject class to match the data model, as in the .xcdatamodeld file. Set its properties based on the references to the NSURLResponse and NSMutableData that you saved.
  3. Save the context of a Core Data managed object.


Now that you have a way to store data, you need to call this method from somewhere. All in the same MyURLProtocol.swift, change the delegate methods of the NSURLConnection to the following:

 func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!) { self.client!.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .NotAllowed) self.response = response self.mutableData = NSMutableData() } func connection(connection: NSURLConnection!, didReceiveData data: NSData!) { self.client!.URLProtocol(self, didLoadData: data) self.mutableData.appendData(data) } func connectionDidFinishLoading(connection: NSURLConnection!) { self.client!.URLProtocolDidFinishLoading(self) self.saveCachedResponse() } 


Instead of being directly transferred to the client, the response actions and data are now saved by your custom protocol class.

Compile and run the application. Nothing has changed in the application, but remember that the now successfully obtained data from the web server is stored in the local database of your application.

Getting a cached response

Finally, now is the time to get the cached data and send it to the client on the NSURLProtocol. Open the file MyURLProtocol.swift. and add the following method:

 func cachedResponseForCurrentRequest() -> NSManagedObject? { // 1 let delegate = UIApplication.sharedApplication().delegate as AppDelegate let context = delegate.managedObjectContext! // 2 let fetchRequest = NSFetchRequest() let entity = NSEntityDescription.entityForName("CachedURLResponse", inManagedObjectContext: context) fetchRequest.entity = entity // 3 let predicate = NSPredicate(format:"url == %@", self.request.URL.absoluteString!) fetchRequest.predicate = predicate // 4 var error: NSError? let possibleResult = context.executeFetchRequest(fetchRequest, error: &error) as Array<NSManagedObject>? // 5 if let result = possibleResult { if !result.isEmpty { return result[0] } } return nil } 


Here is what he does:
  1. Takes the context of a Core Data managed object, just like in saveCachedResponse ().
  2. Creates an NSFetchRequest and indicates that you want to find an element called CachedURLResponse. This is the element in the managed object model that needs to be extracted.
  3. The predicate for a sample query needs to get a CachedURLResponse object that corresponds to the URL you upload. This code sets it up.
  4. Fulfills a sample query.
  5. If there are any results, opens the first result.


startLoading (). , , URL. startLoading :

 override func startLoading() { // 1 let possibleCachedResponse = self.cachedResponseForCurrentRequest() if let cachedResponse = possibleCachedResponse { println("Serving response from cache") // 2 let data = cachedResponse.valueForKey("data") as NSData! let mimeType = cachedResponse.valueForKey("mimeType") as String! let encoding = cachedResponse.valueForKey("encoding") as String! // 3 let response = NSURLResponse(URL: self.request.URL, MIMEType: mimeType, expectedContentLength: data.length, textEncodingName: encoding) // 4 self.client!.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .NotAllowed) self.client!.URLProtocol(self, didLoadData: data) self.client!.URLProtocolDidFinishLoading(self) } else { // 5 println("Serving response from NSURLConnection") var newRequest = self.request.copy() as NSMutableURLRequest NSURLProtocol.setProperty(true, forKey: "MyURLProtocolHandledKey", inRequest: newRequest) self.connection = NSURLConnection(request: newRequest, delegate: self) } } 


This is what happens:

  1. -, .
  2. , .
  3. NSURLResponse .
  4. . NotAllowed, , , . URLProtocolDidFinishLoading, , . , !
  5. If no cached data was found, then load the data as usual.


Compile and run your project. Browse multiple websites and then exit the application. Or switch the device to airplane mode (or, using the iOS simulator, turn off Wi-Fi on your computer / unplug the Ethernet cable) Try to download any website you just downloaded. Pages should load from cached data. Hooray!Rejoice! You did it !!!

You will see many entries in the console that look like this:

 Request #22: URL = http://vjs.zencdn.net/4.5/video-js.css?ver=3.9.1 Serving response from cache 


This entry indicates that data is being returned from your cache!

And it's all. -. !

NSURLProtocol?

NSURLProtocol, , , ? Here are some examples:

Provide your Network Requests with Custom Notifications:

It doesn't matter if you send a request using UIWebView, NSURLConnection or even using a third-party library (such as AFNetworking, MKNetworkKit, your own, etc., as they are all built on NSURLConnection). You can provide custom notification for both metadata and data. You could also use it if you, for example, want to “redeem” the request notification for testing purposes.

Skip the Web Workflow and Provide Local Data:

Sometimes you may feel that there is no need to run a network request in order to provide the application with the data it needs. NSURLProtocol can configure your application to find data in a local storage or local database.

Forward your network requests:

Have you ever wanted to redirect requests to a proxy server, trusting the user to follow the specific instructions for installing iOS? Can you do it! NSURLProtocol gives you what you want - control over requests. You can configure your application to intercept and redirect them to another server or proxy, or wherever you want. This is about control !!!

Modify the user agent of your requests:

, , . , -. , -. , , .

:

(, - UDP). .

, . ( ) , NSURLProtocol . , NSURLRequest, , NSURLResponse. NSURLResponse. , .

NSURLProtocol , , . , , . , NSURLProtocol, .

What's next?

Here here you can download the completed project for this training manual.

This example demonstrated the simple use of the NSURLProtocol, but do not confuse it with an absolute caching solution. Implementing a high-quality browser caching requires much more. In fact, the loading system has built-in caching configurations that you should be familiar with. The goal of this tutorial is to simply show you the possibilities. Since the NSURLProtocol has access to data coming in and out of a large number of components, this is very powerful! There are almost no limits to what you can do when implementing the startLoading method.

While RFC 3986 IETF can modestly define a URL as “... a compact sequence of characters that defines an abstract or physical resource ...” the fact is that a URL is its own mini-language. It is designated domain domain (DSL) for designation and location of things. This is probably the most common domain domain in the world, given that URLs have gone off the screen and are now broadcast on radio and television advertisements, printed in magazines and drawn on store signs all over the world.

NSURLProtocol is a language that can be used in many different ways. When Twitter wanted to implement SPDY on iOS , HTTP 1.1, NSURLProtocol. , , . NSURLProtocol , .

Source: https://habr.com/ru/post/237367/


All Articles