Skip to content

Instantly share code, notes, and snippets.

@rinov
Last active August 2, 2023 09:18
Show Gist options
  • Save rinov/30e3851a6521e20c99f88c73d5dfeede to your computer and use it in GitHub Desktop.
Save rinov/30e3851a6521e20c99f88c73d5dfeede to your computer and use it in GitHub Desktop.
Guide on Swizzling Asynchronous URLSession Method
import SwiftUI
import Foundation
class CustomHTTPProtocol: URLProtocol {
private var dataTask: URLSessionDataTask?
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
print(#function)
return request
}
override class func requestIsCacheEquivalent(_ a: URLRequest, to b: URLRequest) -> Bool {
print(#function)
return super.requestIsCacheEquivalent(a, to: b)
}
override class func canInit(with request: URLRequest) -> Bool {
print(#function)
print("Request: \(request.url?.absoluteString ?? "Unknown")")
return true
}
override func startLoading() {
print(#function)
dataTask = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
self.client?.urlProtocol(self, didFailWithError: error)
} else {
if let data = data, let response = response {
print("Response: \(String(data: data, encoding: .utf8) ?? "")")
self.client?.urlProtocol(self, didLoad: data)
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
}
self.client?.urlProtocolDidFinishLoading(self)
}
}
dataTask?.resume()
}
override func stopLoading() {
print(#function)
dataTask?.cancel()
}
}
extension URLSessionConfiguration {
static func swizzleDefaultSessionConfiguration() {
let defaultSessionConfiguration = class_getClassMethod(URLSessionConfiguration.self, #selector(getter: URLSessionConfiguration.default))
let swizzledDefaultSessionConfiguration = class_getClassMethod(URLSessionConfiguration.self, #selector(URLSessionConfiguration.swizzledDefaultSessionConfiguration))
method_exchangeImplementations(defaultSessionConfiguration!, swizzledDefaultSessionConfiguration!)
}
@objc class func swizzledDefaultSessionConfiguration() -> URLSessionConfiguration {
let configuration = swizzledDefaultSessionConfiguration()
configuration.protocolClasses?.insert(CustomHTTPProtocol.self, at: 0)
return configuration
}
}
struct ContentView: View {
@State var responseData: String = ""
var body: some View {
VStack {
Text("Response Data:")
Text(responseData)
}
.task {
await fetchData()
}
}
func fetchData() async {
guard let url = URL(string: "https://github.com/rinov/") else {
return
}
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
do {
let (data, _) = try await session.data(from: url)
if let string = String(data: data, encoding: .utf8) {
responseData = string
}
} catch {
print("Error: \(error)")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
import SwiftUI
@main
struct TestAsyncURLSessionSwizzleApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
URLSessionConfiguration.swizzleDefaultSessionConfiguration()
return true
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment