iOS 中的 NSURLConnection 调配
NSURLConnection swizzling in iOS
我已经为 sendSynchronousRequest 创建了 NSURLConnection 方法 swizzling,但是它没有工作下面是我的代码。每当我试图从主函数调用它时,它就会崩溃。
let originalRequestSyncSelector = #selector(self.sendSynchronousRequest(_:returning:))
let swizzledRequestSyncSelector = #selector(self.swizzSendSynchronousRequest(_:returning:error:))
let originalSyncRequestMethod = class_getClassMethod(self, originalRequestSyncSelector)
let swizzledSyncRequestMethod = class_getInstanceMethod(self, swizzledRequestSyncSelector)
if originalSyncRequestMethod == nil || swizzledSyncRequestMethod == nil {
return
}
method_exchangeImplementations(originalSyncRequestMethod!, swizzledSyncRequestMethod!)
@objc func swizzSendSynchronousRequest(_ request: NSURLRequest?, returning response: URLResponse?, error: Error?) -> Data? {
var tempData: Data?
print("Inside Sync Swizzled Method")
print("------------\(String(describing: request))")
return tempData
}
有几件事可能会导致问题:
- 方法签名不同。原始实现没有
error
参数,而是一个抛出函数。此外,与您的 swizzled 方法不同,sendSynchronousRequest
采用 URLRequest
而不是 NSURLRequest
.
- 您正在调配一个实例和一个 class 方法。我不确定如何(或是否)使它起作用。
sendSynchronousRequest
作为抛出函数暴露给 Swift。如果您的 swizzled 函数未标记 throws
,它会起作用,但抛出函数不能暴露给 ObjC,并且在被 swizzled 时可能会导致问题。
这里有一些 playground 的工作代码:
import Foundation
import ObjectiveC
extension NSURLConnection {
@objc static func swizzSendSynchronousRequest(_ request: URLRequest?, returning response: URLResponse?) -> Data? {
print("Inside Sync Swizzled Method")
print("------------\(String(describing: request))")
return Data()
}
}
let originalRequestSyncSelector = #selector(NSURLConnection.sendSynchronousRequest(_:returning:))
let swizzledRequestSyncSelector = #selector(NSURLConnection.swizzSendSynchronousRequest(_:returning:))
let originalSyncRequestMethod = class_getClassMethod(NSURLConnection.self, originalRequestSyncSelector)
let swizzledSyncRequestMethod = class_getClassMethod(NSURLConnection.self, swizzledRequestSyncSelector)
method_exchangeImplementations(originalSyncRequestMethod!, swizzledSyncRequestMethod!)
let request = URLRequest(url: URL(string: "https://example.com")!)
do {
let data = try NSURLConnection.sendSynchronousRequest(request, returning: nil)
print(data)
} catch {
print(error)
}
无论如何,我认为在 Objective-C 中执行混合会是一个更好的主意。
much better documentation 介绍了如何做到这一点,您可以在 Swift <-> Objective-C 桥接魔法中避免陷阱。
我已经为 sendSynchronousRequest 创建了 NSURLConnection 方法 swizzling,但是它没有工作下面是我的代码。每当我试图从主函数调用它时,它就会崩溃。
let originalRequestSyncSelector = #selector(self.sendSynchronousRequest(_:returning:))
let swizzledRequestSyncSelector = #selector(self.swizzSendSynchronousRequest(_:returning:error:))
let originalSyncRequestMethod = class_getClassMethod(self, originalRequestSyncSelector)
let swizzledSyncRequestMethod = class_getInstanceMethod(self, swizzledRequestSyncSelector)
if originalSyncRequestMethod == nil || swizzledSyncRequestMethod == nil {
return
}
method_exchangeImplementations(originalSyncRequestMethod!, swizzledSyncRequestMethod!)
@objc func swizzSendSynchronousRequest(_ request: NSURLRequest?, returning response: URLResponse?, error: Error?) -> Data? {
var tempData: Data?
print("Inside Sync Swizzled Method")
print("------------\(String(describing: request))")
return tempData
}
有几件事可能会导致问题:
- 方法签名不同。原始实现没有
error
参数,而是一个抛出函数。此外,与您的 swizzled 方法不同,sendSynchronousRequest
采用URLRequest
而不是NSURLRequest
. - 您正在调配一个实例和一个 class 方法。我不确定如何(或是否)使它起作用。
sendSynchronousRequest
作为抛出函数暴露给 Swift。如果您的 swizzled 函数未标记throws
,它会起作用,但抛出函数不能暴露给 ObjC,并且在被 swizzled 时可能会导致问题。
这里有一些 playground 的工作代码:
import Foundation
import ObjectiveC
extension NSURLConnection {
@objc static func swizzSendSynchronousRequest(_ request: URLRequest?, returning response: URLResponse?) -> Data? {
print("Inside Sync Swizzled Method")
print("------------\(String(describing: request))")
return Data()
}
}
let originalRequestSyncSelector = #selector(NSURLConnection.sendSynchronousRequest(_:returning:))
let swizzledRequestSyncSelector = #selector(NSURLConnection.swizzSendSynchronousRequest(_:returning:))
let originalSyncRequestMethod = class_getClassMethod(NSURLConnection.self, originalRequestSyncSelector)
let swizzledSyncRequestMethod = class_getClassMethod(NSURLConnection.self, swizzledRequestSyncSelector)
method_exchangeImplementations(originalSyncRequestMethod!, swizzledSyncRequestMethod!)
let request = URLRequest(url: URL(string: "https://example.com")!)
do {
let data = try NSURLConnection.sendSynchronousRequest(request, returning: nil)
print(data)
} catch {
print(error)
}
无论如何,我认为在 Objective-C 中执行混合会是一个更好的主意。 much better documentation 介绍了如何做到这一点,您可以在 Swift <-> Objective-C 桥接魔法中避免陷阱。