知识点:
NSURLConnection 设置代理的方式来发送网络请求所遇到的一些问题:
1. 使用NSURLConnection设置代理的方式来发送网络请求,代理方法默认是在主线程中执行的.
我们可以 使用 setDelegateQueue: 方法来设置代理方法在子线程中执行.
[connect setDelegateQueue:[[NSOperationQueue alloc] init]];
注意: 不可以
[connect setDelegateQueue:[NSOperationQueue mainQueue]] 这样设置,否则代理方法不会被执行.
2. 设置代理的方式 本身是异步执行的.
3. 给NSURLConnection设置代理后.理论上当connect变量出了大括号就被释放了.为什么还会调用代理方法\
因为 the calling thread’s run loop must be operating in the default run loop mode.这个方法内部其实\
会将connect对象当做source添加到runloop中,并设置运行模式为默认模式.当所有代理方法都执行完/接收完服务器返回的数据后,\
才会释放.(必须是默认模式)
4.当使用 initWithRequest: delegate :startImmediately 来发送请求时:
// startImmediately: YES 创建网络链接后会立刻发送网络请求 NO 不会发送网络请求. 除非调用 [connect start]方法
[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
5. 当发送网络请求的步骤也放入到子线程中去执行.此时代理方法不会被调用( startImmediately = YES ).
原因: connect 对象 当作sourse添加到runloop中了. 此时的connect再子线程中.子线程的runloop并没有自动开启, 需要我们自己来开启子线程的runloop.
6. 前提:网络请求在子线程中执行: 当startImmediately 为NO的时候, 调用 [connect start] 方法, 直接就可以调用代理方法.这是为什么呢?
第5条,startImmediately = YES, 就需要手动开启子线程runloop.
注意: 这里是因为 [connect start] 的start方法, start方法会将默认的 connect对象添加到runloop中并设置运行模式为默认, 如果当前的runloop
没有开启,那么start方法内部会自动获取当前线程的runloop对象并开启.
代码如下:
// Created by 朝阳 on 2017/12/12.
// Copyright © 2017年 sunny. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self delegate2];
}
// 异步的
- (void)delegate1
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8080/MJServer/login?username=123&pwd=123&method=get&type=JSON"]];
// 设置代理
// 代理方法: 默认是在主线程中调用的
// 给NSURLConnection 设置代理后. 理论上当connect变量出了 大括号就被释放了.为什么还会调用代理方法\
因为 the calling thread’s run loop must be operating in the default run loop mode. 这个方法内部其实\
会将connect对象 当做 source添加到runloop中,并设置运行模式 为 默认模式. 当所有代理方法都执行完/接收完服务器返回的数据后,\
才会释放
NSURLConnection *connect = [NSURLConnection connectionWithRequest:request delegate:self];
// 设置代理方法在哪个线程中调用
// [NSOperationQueue alloc] init] 如果是非主队列,就开 子线程
// [NSOperationQueue mainQueue] 不能这样设置.没有任何反应
// [connect setDelegateQueue:[NSOperationQueue mainQueue]];
[connect setDelegateQueue:[[NSOperationQueue alloc] init]];
// 先打印zy---- 证明 是异步执行的
NSLog(@"zy-----");
}
- (void)delegate2
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8080/MJServer/login?username=123&pwd=123&method=get&type=JSON"]];
// 设置代理
// 代理方法: 默认是在主线程中调用的
// startImmediately: YES 创建网络链接后会立刻发送网络请求 NO 不会发送网络请求. 除非调用 [connect start]方法
NSURLConnection *connect = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
// 设置代理方法在哪个线程中调用
[connect setDelegateQueue:[[NSOperationQueue alloc] init]];
// 开始发送请求
[connect start];
// 先打印zy---- 证明 是异步执行的
NSLog(@"zy-----");
}
- (void)newThreadDelegate1
{
// 开子线程来发送网络请求
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8080/MJServer/login?username=123&pwd=123&method=get&type=JSON"]];
// 设置代理
// 代理方法: 默认是在主线程中调用的
NSURLConnection *connect = [NSURLConnection connectionWithRequest:request delegate:self];
// 设置代理方法在哪个线程中调用
[connect setDelegateQueue:[[NSOperationQueue alloc] init]];
NSLog(@"---%@---",[NSThread currentThread]);
// 开启子线程的runloop(子线程的runloop默认是不开启的)
[[NSRunLoop currentRunLoop] run];
// 必须是默认模式
// [[NSRunLoop currentRunLoop] runMode:UITrackingRunLoopMode beforeDate:[NSDate date]];
});
}
- (void)newThreadDelegate2
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8080/MJServer/login?username=123&pwd=123&method=get&type=JSON"]];
// 设置代理
// 代理方法: 默认是在主线程中调用的
// startImmediately: YES 创建网络链接后会立刻发送网络请求 NO 不会发送网络请求. 除非调用 [connect start]方法
NSURLConnection *connect = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
// 设置代理方法在哪个线程中调用
[connect setDelegateQueue:[[NSOperationQueue alloc] init]];
// 开始发送请求
// If you don’t schedule the connection in a run loop or an operation queue before calling this method, the connection is scheduled in the current run loop in the default mode.\
start 方法 会默认将 connect对象添加到runloop中并设置运行模式为默认.
// 注意: 如果当前runloop没有开启,那么该方法内部会自动获取当前线程的runloop对象并开启
[connect start];
NSLog(@"---%@---",[NSThread currentThread]);
});
}
#pragma -mark NSURLConnectionDataDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(@"didReceiveResponse---%@",[NSThread currentThread]);
}
@end