我創建了一個NSURLConnection
和NSURLSession
類別,以便在調試時攔截呼叫並收集網絡信息。 一切在大多數情況下,除了當我使用的NSURLConnection
Swizzle NSURLConnection sendAsynchronous:request:queue:completionHandler and sendSynchronousRequest:returningResponse:error:not working
sendAsynchronousRequest:queue:completionHandler:
sendSynchronousRequest:returningResponse:error:
這兩個靜態方法靜態類方法的偉大工程,只是,雖然調試我看到這個方法的實現交換正在發生的事情不要在我混寫服從正如其他方法,我swizzle。 這裏是我的代碼,類似於我對其他方法似乎工作得很好。
typedef void (^SendAsynchronousCompletionHandlerBlock)(NSURLResponse*, NSData*, NSError*);
static void (*OriginalNSURLConnectionSendAsynchronousRequestQueueCompletionHandler)(id, SEL, NSURLRequest*, NSOperationQueue*, SendAsynchronousCompletionHandlerBlock);
static NSData* (*OriginalNSURLConnectionSendSynchronousRequestReturningResponseError)(id, SEL, NSURLRequest*, NSURLResponse**, NSError**);
static void MyNSURLConnectionSendAsynchronousRequestQueueCompletionHandler(id self, SEL _cmd, NSURLRequest* request, NSOperationQueue* queue, SendAsynchronousCompletionHandlerBlock completionHandler)
{
NSLog(@"Implementation Intercept in %s", __PRETTY_FUNCTION__);
OriginalNSURLConnectionSendAsynchronousRequestQueueCompletionHandler(self, _cmd, request, queue, completionHandler);
}
static NSData* MyNSURLConnectionSendSynchronousRequestReturningResponseError(id self, SEL _cmd, NSURLRequest* request, NSURLResponse** response, NSError** error)
{
NSLog(@"Implementation Intercept in %s", __PRETTY_FUNCTION__);
NSData* data = OriginalNSURLConnectionSendSynchronousRequestReturningResponseError(self, _cmd, request, response, error);
return data;
}
@implementation NSURLConnection (MyNSURLConnection)
+ (void) load
{
// Create onceToken
static dispatch_once_t onceToken;
// Use dispatch_once to make sure this runs only once in the lifecycle
dispatch_once(&onceToken,
^{
NSLog(@"Injecting code to NSURLConnection");
[self injectImplementationToNSURLConnectionSendAsynchronousRequestQueueCompletionHandler];
[self injectImplementationToNSURLConnectionSendSynchronousRequestReturningResponseError];
// Some other methods I intercept, just as reference, they work as tested to init an NSURLConnection object
// I will skip their implementation which is similar to what I show here
[self injectImplementationToNSURLConnectionConnectionWithRequestDelegate];
[self injectImplementationToNSURLConnectionInitWithRequestDelegateStartImmediately];
[self injectImplementationToNSURLConnectionInitWithRequestDelegate];
[self injectImplementationToNSURLConnectionStart];
});
}
+ (void) injectImplementationToNSURLConnectionSendAsynchronousRequestQueueCompletionHandler
{
// Replace the method on the same class that's used
// in the calling code
Class class = [NSURLConnection class];
// The Original +sendAsynchronousRequest:queue:completionHandler:
SEL originalSelector = @selector(sendAsynchronousRequest:queue:completionHandler:);
// The Replacement method implementation
IMP replacement = (IMP)MyNSURLConnectionSendAsynchronousRequestQueueCompletionHandler;
// This will eventually hold the original sendAsynchronousRequest:queue:completionHandler:
IMP* store = (IMP*)&OriginalNSURLConnectionSendAsynchronousRequestQueueCompletionHandler;
IMP originalImp = NULL;
Method method = class_getClassMethod(class, originalSelector);
if (method)
{
const char* type = method_getTypeEncoding(method);
// Replace the original method with the MyNSURLConnectionSendAsynchronousRequestQueueCompletionHandler
originalImp = class_replaceMethod(class, originalSelector, replacement, type);
if (!originalImp)
{
originalImp = method_getImplementation(method);
}
}
// Put the original method IMP into the pointer
if (originalImp && store)
{
*store = originalImp;
}
}
+ (void) injectImplementationToNSURLConnectionSendSynchronousRequestReturningResponseError
{
// Replace the method on the same class that's used
// in the calling code
Class class = [NSURLConnection class];
// The Original +sendSynchronousRequest:returningResponse:error: selector
SEL originalSelector = @selector(sendSynchronousRequest:returningResponse:error:);
// The Replacement method implementation
IMP replacement = (IMP)MyNSURLConnectionSendSynchronousRequestReturningResponseError;
// This will eventually hold the original sendSynchronousRequest:returningResponse:error:
IMP* store = (IMP*)&OriginalNSURLConnectionSendSynchronousRequestReturningResponseError;
IMP originalImp = NULL;
Method method = class_getClassMethod(class, originalSelector);
if (method)
{
const char* type = method_getTypeEncoding(method);
// Replace the original method with the MyNSURLConnectionSendSynchronousRequestReturningResponseError
originalImp = class_replaceMethod(class, originalSelector, replacement, type);
if (!originalImp)
{
originalImp = method_getImplementation(method);
}
}
// Put the original method IMP into the pointer
if (originalImp && store)
{
*store = originalImp;
}
}
那麼是什麼讓不同的這些方法,我不能有我的代碼調配成原來的執行,並沒有出現在任何方式錯誤。
這裏是我測試的代碼:
- (IBAction) executeURLRequest: (UIButton*)sender
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://My.URL/file.json"]];
[request setValue:@"API_KEY" forHTTPHeaderField:@"X-My-Auth-Token"];
NSURLResponse* response;
NSError* error;
// Doesn't work, my swizzle method is not invoked
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// Doesn't work, my swizzle method is not invoked
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error)
{
if (error) NSLog(@"NSURLConnection failed: %@", [error debugDescription]);
NSLog(@"Made the NSURLRequest to My");
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
^{
// It works, I get to see my message of the method invoked to the output console
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:nil startImmediately:YES];
});
}
我不知道,它看起來相當好,我...你有什麼感想?
是的,這個實現工作,我可以看到你的代碼和我的區別是,你得到原始的實現與gOrigNSURLConnection_sendAsynchronousRequestQueueCompletionHandler =(void *)method_getImplementation(origMethod);我爲同步版本做了同樣的工作,它也可以工作。因爲現在所有其他部分按預期工作,所以我現在將繼續執行其餘的實施。如果可能的話,請爲我的知識庫解釋。 –