SlideShare a Scribd company logo
URLProtocol
2017/11/24
Introduction
•
• API
• API
•
#if DEBUG
DispatchQueue.global().async {
//
let user = User.mockData()
//
}
#else
let request = URLRequest(url: URL(string: "https://api.test.com/
users/foo")!)
let task = URLSession.shared.dataTask(with: request) { (data,
response, error) in
//
}
task.resume()
#endif
Demo
"NS" URLProtocol
Swift3 `Foundation` API "NS"
"NS"
URL Loading System
URL Loading System
The URL loading system is a set of classes and
protocols that allow your app to access content
referenced by a URL. At the heart of this
technology is the NSURL class, which lets your
app manipulate URLs and the resources they
refer to.
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/
URLLoadingSystem/URLLoadingSystem.html
URL loading system
• ftp://
• http://
• https://
• file:///
• data:
Foundation
• URL
•
•
•
•
•
URLProtocol
URLProtocol
URLProtocol
URLProtocol
An NSURLProtocol object handles the loading
of protocol-specific URL data. The
NSURLProtocol class itself is an abstract class
that provides the infrastructure for processing
URLs with a specific URL scheme. You create
subclasses for any custom protocols or URL
schemes that your app supports.
https://developer.apple.com/documentation/foundation/urlprotocol
•
•
•
•
•
https://www.raywenderlich.com/76735/using-nsurlprotocol-swift
URLProtocol
• URLProtocol
• URLProtocol
registerClass(_:)
• class func canInit(with request: URLRequest) -
> Bool
• class func canonicalRequest(for request:
URLRequest) -> URLRequest
• func startLoading()
• func stopLoading()
URLProtocol
•
•
•
•
•
https://www.raywenderlich.com/76735/using-nsurlprotocol-swift
URLProtocol
• `true`
•
• `false` URLProtocol
override class func canInit(with request: URLRequest) -> Bool {
return true
}
• 'canonical'
• 'canonical'
•
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
override func startLoading() {
// Bundle JSON
guard
let path = Bundle.main.path(forResource: "user", ofType: "json"),
let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else
{
//
}
let client = self.client
let response = HTTPURLResponse(url: request.url!, statusCode: 200,
httpVersion: "HTTP/1.1", headerFields: ["Content-Type" : "application/
json;"])
//
client?.urlProtocol(self, didReceive: response!,
cacheStoragePolicy: .notAllowed)
//
client?.urlProtocol(self, didLoad: data)
//
client?.urlProtocolDidFinishLoading(self)
}
override func startLoading() {
...
//
let client = self.client
let response = HTTPURLResponse(url: request.url!, statusCode: 500,
httpVersion: "HTTP/1.1", headerFields: ["Content-Type" : "application/
json;"])
//
client?.urlProtocol(self, didReceive: response!,
cacheStoragePolicy: .notAllowed)
//
let error = NSError(domain: "CustomURLProtocolError", code: 10001,
userInfo: nil)
client?.urlProtocol(self, didFailWithError: error)
return
....
}
URLProtocolClient
• URLProtocol "URL Loading
System"
• func urlProtocol(URLProtocol, didReceive: URLResponse, cacheStoragePolicy: URLCache.StoragePolicy)
• func urlProtocol(URLProtocol, didLoad: Data)
• func urlProtocolDidFinishLoading(URLProtocol)
• func urlProtocol(URLProtocol, didFailWithError: Error)
• func urlProtocol(URLProtocol, didReceive: URLAuthenticationChallenge)
• func urlProtocol(URLProtocol, didCancel: URLAuthenticationChallenge)
• func urlProtocol(URLProtocol, wasRedirectedTo: URLRequest, redirectResponse: URLResponse)
• func urlProtocol(URLProtocol, cachedResponseIsValid: CachedURLResponse)
URLProtocolClient
• URLProtocol "URL Loading
System"
• func urlProtocol(URLProtocol, didReceive: URLResponse, cacheStoragePolicy: URLCache.StoragePolicy)
• func urlProtocol(URLProtocol, didLoad: Data)
• func urlProtocolDidFinishLoading(URLProtocol)
• func urlProtocol(URLProtocol, didFailWithError: Error)
• func urlProtocol(URLProtocol, didReceive: URLAuthenticationChallenge)
• func urlProtocol(URLProtocol, didCancel: URLAuthenticationChallenge)
• func urlProtocol(URLProtocol, wasRedirectedTo: URLRequest, redirectResponse: URLResponse)
• func urlProtocol(URLProtocol, cachedResponseIsValid: CachedURLResponse)
URLProtocolClient
• URLProtocol "URL Loading
System"
• func urlProtocol(URLProtocol, didReceive: URLResponse, cacheStoragePolicy: URLCache.StoragePolicy)
• func urlProtocol(URLProtocol, didLoad: Data)
• func urlProtocolDidFinishLoading(URLProtocol)
• func urlProtocol(URLProtocol, didFailWithError: Error)
• func urlProtocol(URLProtocol, didReceive: URLAuthenticationChallenge)
• func urlProtocol(URLProtocol, didCancel: URLAuthenticationChallenge)
• func urlProtocol(URLProtocol, wasRedirectedTo: URLRequest, redirectResponse: URLResponse)
• func urlProtocol(URLProtocol, cachedResponseIsValid: CachedURLResponse)
•
• URLSession
GCD
override func stopLoading() {
}
URLProtocol
• `application(_:
didFinishLaunchingWithOptions:)`
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//
URLProtocol.registerClass(CustomURLProtocol.self)
return true
}
URL Loading System
•
•
let request = URLRequest(url: URL(string: "https://api.test.com/users/
foo")!)
let task = URLSession.shared.dataTask(with: request) { (data, response,
error) in
//
}
task.resume()
• Flags
#if DEBUG
let path = Bundle.main.path(forResource: "user", ofType: "json")!
let data = try! Data(contentsOf: URL(fileURLWithPath: path))
DispatchQueue.global().async {
//
}
#else
let request = URLRequest(url: URL(string: "https://api.test.com/users/foo")!)
let task = URLSession.shared.dataTask(with: request) { (data, response, error)
in
//
}
task.resume()
#endif
URLSession.shared
URLProtocol
•
•
• Flags
let request = URLRequest(url: URL(string: "https://api.test.com/users/
foo")!)
let task = URLSession.shared.dataTask(with: request) { (data, response,
error) in
//
}
task.resume()
• `application(_:
didFinishLaunchingWithOptions:)`
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//
URLProtocol.registerClass(CustomURLProtocol.self)
return true
}
URL Loading System
URLSession.shared
• The shared session uses the shared NSURLCache,
NSHTTPCookieStorage, and NSURLCredentialStorage
objects, uses a shared custom networking protocol list
(configured with registerClass(_:) and unregisterClass(_:)),
and is based on a default configuration.
• In other words, if you’re doing anything with caches,
cookies, authentication, or custom networking protocols,
you should probably be using a default session instead of
the shared session.
https://developer.apple.com/documentation/foundation/urlsession/1409000-shared
• URLSession.shared
URLSessionConfiguration
•
URLSessionConfiguration.default URLSession
• URLProtocol.registerClass
URLProtocol.registerClass(CustomURLProtocol.self)
• URLSessionConfiguration
var protocolClasses: [AnyClass]?
let config = URLSessionConfiguration.default
config.protocolClasses = [CustomURLProtocol.self]
let session = URLSession(configuration: config)
let task = session.dataTask(with: urlRequest) { (data, response, error) in
...
}
• URLProtocol URLSessionConfiguration
SessionManager
• ( ) SessionManager
let config = URLSessionConfiguration.default
config.protocolClasses = [CustomURLProtocol.self]
self.manager = SessionManager(configuration: config) //
manager.request(url).response { response in
...
}
Alamofire
• URLProtocol URLSessionConfiguration
URLSessionAdapter Session
let config = URLSessionConfiguration.default
config.protocolClasses = [CustomURLProtocol.self]
let adapter = URLSessionAdapter(configuration: config)
let session = Session(adapter: adapter)
session.send(request) { (result) in
...
}
APIKit
URLProtocol
•
• API
• Qiita API
API
URLProtocol
• https://github.com/Alamofire/Alamofire/
blob/master/Tests/URLProtocolTests.swift
• https://github.com/ishkawa/APIKit/blob/
master/Tests/APIKitTests/TestComponents/
HTTPStub.swift
• https://github.com/AliSoftware/
OHHTTPStubs
Appendix
• [URL Loading System]: https://developer.apple.com/library/content/
documentation/Cocoa/Conceptual/URLLoadingSystem/
URLLoadingSystem.html
• [URLProtocol]: https://developer.apple.com/documentation/foundation/
urlprotocol
• [Using NSURLProtocol with Swift]: https://www.raywenderlich.com/76735/
using-nsurlprotocol-swift
• [iOS Advent Calendar 2011 5 / NSURLProtocol ]: http://
faultier.blog.jp/archives/1762587.html
• [Using NSURLProtocol for Testing]: https://yahooeng.tumblr.com/post/
141143817861/using-nsurlprotocol-for-testing

More Related Content

URLProtocol

  • 4. #if DEBUG DispatchQueue.global().async { // let user = User.mockData() // } #else let request = URLRequest(url: URL(string: "https://api.test.com/ users/foo")!) let task = URLSession.shared.dataTask(with: request) { (data, response, error) in // } task.resume() #endif
  • 8. URL Loading System The URL loading system is a set of classes and protocols that allow your app to access content referenced by a URL. At the heart of this technology is the NSURL class, which lets your app manipulate URLs and the resources they refer to. https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ URLLoadingSystem/URLLoadingSystem.html
  • 9. URL loading system • ftp:// • http:// • https:// • file:/// • data:
  • 14. URLProtocol An NSURLProtocol object handles the loading of protocol-specific URL data. The NSURLProtocol class itself is an abstract class that provides the infrastructure for processing URLs with a specific URL scheme. You create subclasses for any custom protocols or URL schemes that your app supports. https://developer.apple.com/documentation/foundation/urlprotocol
  • 18. • class func canInit(with request: URLRequest) - > Bool • class func canonicalRequest(for request: URLRequest) -> URLRequest • func startLoading() • func stopLoading()
  • 22. • `true` • • `false` URLProtocol override class func canInit(with request: URLRequest) -> Bool { return true }
  • 23. • 'canonical' • 'canonical' • override class func canonicalRequest(for request: URLRequest) -> URLRequest { return request }
  • 24. override func startLoading() { // Bundle JSON guard let path = Bundle.main.path(forResource: "user", ofType: "json"), let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { // } let client = self.client let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: ["Content-Type" : "application/ json;"]) // client?.urlProtocol(self, didReceive: response!, cacheStoragePolicy: .notAllowed) // client?.urlProtocol(self, didLoad: data) // client?.urlProtocolDidFinishLoading(self) }
  • 25. override func startLoading() { ... // let client = self.client let response = HTTPURLResponse(url: request.url!, statusCode: 500, httpVersion: "HTTP/1.1", headerFields: ["Content-Type" : "application/ json;"]) // client?.urlProtocol(self, didReceive: response!, cacheStoragePolicy: .notAllowed) // let error = NSError(domain: "CustomURLProtocolError", code: 10001, userInfo: nil) client?.urlProtocol(self, didFailWithError: error) return .... }
  • 26. URLProtocolClient • URLProtocol "URL Loading System" • func urlProtocol(URLProtocol, didReceive: URLResponse, cacheStoragePolicy: URLCache.StoragePolicy) • func urlProtocol(URLProtocol, didLoad: Data) • func urlProtocolDidFinishLoading(URLProtocol) • func urlProtocol(URLProtocol, didFailWithError: Error) • func urlProtocol(URLProtocol, didReceive: URLAuthenticationChallenge) • func urlProtocol(URLProtocol, didCancel: URLAuthenticationChallenge) • func urlProtocol(URLProtocol, wasRedirectedTo: URLRequest, redirectResponse: URLResponse) • func urlProtocol(URLProtocol, cachedResponseIsValid: CachedURLResponse)
  • 27. URLProtocolClient • URLProtocol "URL Loading System" • func urlProtocol(URLProtocol, didReceive: URLResponse, cacheStoragePolicy: URLCache.StoragePolicy) • func urlProtocol(URLProtocol, didLoad: Data) • func urlProtocolDidFinishLoading(URLProtocol) • func urlProtocol(URLProtocol, didFailWithError: Error) • func urlProtocol(URLProtocol, didReceive: URLAuthenticationChallenge) • func urlProtocol(URLProtocol, didCancel: URLAuthenticationChallenge) • func urlProtocol(URLProtocol, wasRedirectedTo: URLRequest, redirectResponse: URLResponse) • func urlProtocol(URLProtocol, cachedResponseIsValid: CachedURLResponse)
  • 28. URLProtocolClient • URLProtocol "URL Loading System" • func urlProtocol(URLProtocol, didReceive: URLResponse, cacheStoragePolicy: URLCache.StoragePolicy) • func urlProtocol(URLProtocol, didLoad: Data) • func urlProtocolDidFinishLoading(URLProtocol) • func urlProtocol(URLProtocol, didFailWithError: Error) • func urlProtocol(URLProtocol, didReceive: URLAuthenticationChallenge) • func urlProtocol(URLProtocol, didCancel: URLAuthenticationChallenge) • func urlProtocol(URLProtocol, wasRedirectedTo: URLRequest, redirectResponse: URLResponse) • func urlProtocol(URLProtocol, cachedResponseIsValid: CachedURLResponse)
  • 31. • `application(_: didFinishLaunchingWithOptions:)` func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // URLProtocol.registerClass(CustomURLProtocol.self) return true } URL Loading System
  • 32. • • let request = URLRequest(url: URL(string: "https://api.test.com/users/ foo")!) let task = URLSession.shared.dataTask(with: request) { (data, response, error) in // } task.resume()
  • 33. • Flags #if DEBUG let path = Bundle.main.path(forResource: "user", ofType: "json")! let data = try! Data(contentsOf: URL(fileURLWithPath: path)) DispatchQueue.global().async { // } #else let request = URLRequest(url: URL(string: "https://api.test.com/users/foo")!) let task = URLSession.shared.dataTask(with: request) { (data, response, error) in // } task.resume() #endif
  • 36. • • • Flags let request = URLRequest(url: URL(string: "https://api.test.com/users/ foo")!) let task = URLSession.shared.dataTask(with: request) { (data, response, error) in // } task.resume()
  • 37. • `application(_: didFinishLaunchingWithOptions:)` func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // URLProtocol.registerClass(CustomURLProtocol.self) return true } URL Loading System
  • 38. URLSession.shared • The shared session uses the shared NSURLCache, NSHTTPCookieStorage, and NSURLCredentialStorage objects, uses a shared custom networking protocol list (configured with registerClass(_:) and unregisterClass(_:)), and is based on a default configuration. • In other words, if you’re doing anything with caches, cookies, authentication, or custom networking protocols, you should probably be using a default session instead of the shared session. https://developer.apple.com/documentation/foundation/urlsession/1409000-shared
  • 39. • URLSession.shared URLSessionConfiguration • URLSessionConfiguration.default URLSession • URLProtocol.registerClass URLProtocol.registerClass(CustomURLProtocol.self)
  • 40. • URLSessionConfiguration var protocolClasses: [AnyClass]? let config = URLSessionConfiguration.default config.protocolClasses = [CustomURLProtocol.self] let session = URLSession(configuration: config) let task = session.dataTask(with: urlRequest) { (data, response, error) in ... }
  • 41. • URLProtocol URLSessionConfiguration SessionManager • ( ) SessionManager let config = URLSessionConfiguration.default config.protocolClasses = [CustomURLProtocol.self] self.manager = SessionManager(configuration: config) // manager.request(url).response { response in ... } Alamofire
  • 42. • URLProtocol URLSessionConfiguration URLSessionAdapter Session let config = URLSessionConfiguration.default config.protocolClasses = [CustomURLProtocol.self] let adapter = URLSessionAdapter(configuration: config) let session = Session(adapter: adapter) session.send(request) { (result) in ... } APIKit
  • 46. Appendix • [URL Loading System]: https://developer.apple.com/library/content/ documentation/Cocoa/Conceptual/URLLoadingSystem/ URLLoadingSystem.html • [URLProtocol]: https://developer.apple.com/documentation/foundation/ urlprotocol • [Using NSURLProtocol with Swift]: https://www.raywenderlich.com/76735/ using-nsurlprotocol-swift • [iOS Advent Calendar 2011 5 / NSURLProtocol ]: http:// faultier.blog.jp/archives/1762587.html • [Using NSURLProtocol for Testing]: https://yahooeng.tumblr.com/post/ 141143817861/using-nsurlprotocol-for-testing