Open hcl416029105 opened 6 years ago
@hcl416029105 我先看看,晚上给你答复。
如果不用AFHTTPSessionManager,直接用原生的NSURLSession,没有问题: NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
NSURLSessionTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://hcz-static.pingan.com.cn/fuelCard/fuelCard.zip"]];
[task resume];
这种可以正常调用。
好的,非常感谢你的解答
@hcl416029105 多谢提供的信息,我这边看了下,用 AFNetworking 出问题的原因是在 CFNetwork -[__NSCFURLLocalSessionConnection initWithTask:delegate:delegateQueue:]
方法中会调用 __NSURLSessionLocal
的 can_delegate_task_willSendRequestForEstablishedConnection
方法,而这个方法中会执行下列方法:
[delegate respondsToSelector:@selector(URLSession:task:_willSendRequestForEstablishedConnection:completionHandler:)]
delegate
此时已经是你的 NSURLDelegateProxy
对象,他无法响应 respondsToSelector
,所以会走消息转发的流程中,也就会走到 NSURLDelegateProxy
对象 的 methodSignatureForSelector
。
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
NSMethodSignature *methodSignature = nil;
if ( [self.proxyTarget respondsToSelector:sel]) {
methodSignature = [self.proxyTarget methodSignatureForSelector:sel];
}
return methodSignature;
}
但是因为你的 proxyTarget
在 initWithTarget
被赋值为 AFHTTPSessionManager
对象,而且这个属性为弱引用,而执行到 methodSignatureForSelector
时,AFHTTPSessionManager
对象已经被释放,所以这里 return 的 methodSignature
实际为 nil,导致消息转发流程失败,也就有了下面的输出:
*** NSForwarding: warning: object %p of class '%s' does not implement doesNotRecognizeSelector: -- abort
将属性改为 strong,发现问题已经没有了。
@property(nonatomic, strong) id proxyTarget;
当然你可能会问为什么直接使用 NSURLSession
的 API 无此问题。
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
NSURLSessionTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://hcz-static.pingan.com.cn/fuelCard/fuelCard.zip"]];
[task resume];
事实上使用 NSURLSession
的 API 和 AF 在 CFNetwork 层都会走上面的那段逻辑,但是由于sessionWithConfiguration:delegate:delegateQueue
方法的入参 delegate 恰好是一个强引用的对象,比如我这里可能是一个 ViewController
,所以即使 proxy 那边是弱引用,执行到 methodSignatureForSelector
能够正常返回方法签名对象,消息转发的流程得以正常执行,所以这种场景无此问题。
具体你可以在自己项目中调试来验证,建议在 NSURLDelegateProxy
的 methodSignatureForSelector
方法下断点来验证。
@hcl416029105 另外关于网络监控这块可以看下我的另外一篇文章揭秘 APM iOS SDK 的核心技术,文章对听云的网络监控实现进行了一些探索,希望能对你有所帮助。
网络监控搞复杂了,不用各种swizze,各种hook,直接取getifaddrs获取的数据
@hcl416029105 getifaddrs()
函数拿到的 ifaddrs
struct 最多也是本地地址的信息吧,类似 Local IP 这些,网络监控要获取到的远远不止这个。
如果强引用的话 会不会引起对象释放不了的问题吗
如果强引用的话 会不会引起对象释放不了的问题吗
同问
我在使用NSProxy替换NSURLSession原来的的delegate的时候,再使用AFNetwork的AFHTTPSessionManager的GET方法的时候崩溃了,不知道是什么原因,具体代码如下:
static void swizzleClassMethod(Class theClass, SEL originalSelector, SEL swizzledSelector) { Method origMethod = class_getClassMethod(theClass, originalSelector); Method newMethod = class_getClassMethod(theClass, swizzledSelector);
}
@interface NSURLSession()
@property(nonatomic, strong) NSURLDelegateProxy *delegateProxy;
@end;
@implementation NSURLSession (DelegateMonitor)
(void)load {
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ swizzleClassMethod([self class], @selector(sessionWithConfiguration:delegate:delegateQueue:), @selector(hcz_sessionWithConfiguration:delegate:delegateQueue:)); });
}
(NSURLSession )hcz_sessionWithConfiguration:(NSURLSessionConfiguration )configuration delegate:(nullable id)delegate delegateQueue:(nullable NSOperationQueue )queue
{
if (delegate) {
NSURLDelegateProxy proxy = [[NSURLDelegateProxy alloc] initWithTarget:delegate];
NSURLSession *session = [NSURLSession hcz_sessionWithConfiguration:configuration delegate:proxy delegateQueue:queue];
}
return [self hcz_sessionWithConfiguration:configuration delegate:delegate delegateQueue:queue]; }
@end
@interface NSURLDelegateProxy() @property(nonatomic, weak) id proxyTarget;
@end
@implementation NSURLDelegateProxy
(instancetype)initWithTarget:(id)target { self.proxyTarget = target; return self; }
(void)forwardInvocation:(NSInvocation *)invocation { SEL sel = [invocation selector]; if ( [self.proxyTarget respondsToSelector:sel]) { [invocation invokeWithTarget:self.proxyTarget]; }
}
(nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
NSMethodSignature *methodSignature = nil;
if ( [self.proxyTarget respondsToSelector:sel]) { methodSignature = [self.proxyTarget methodSignatureForSelector:sel]; }
return methodSignature; }
都是很简单的调用,AFHTTPSessionManager的调用方法如下:
错误提示: 2017-12-08 18:08:44.923871+0800 AFNetworkingDemo[82876:14788953] *** NSForwarding: warning: object 0x608000036560 of class '__NSMessageBuilder' does not implement doesNotRecognizeSelector: -- abort