什么是RunLoop
運(yùn)行循環(huán)
一個(gè)線程對(duì)應(yīng)一個(gè)RunLoop咙边,主線程的RunLoop默認(rèn)已經(jīng)啟動(dòng)精刷,子線程的RunLoop得手動(dòng)啟動(dòng)(調(diào)用run方法)
RunLoop只能選擇一個(gè)Mode啟動(dòng)剪决,如果當(dāng)前Mode中沒有任何Source(Sources0灵汪、Sources1)、Timer柑潦,那么就直接退出RunLoop
RunLoop作用
保持程序的持續(xù)運(yùn)行
處理App中的各種事件(比如觸摸事件享言、定時(shí)器事件、Selector事件)
節(jié)省CPU資源渗鬼,提高程序性能:該做事時(shí)做事览露,該休息時(shí)休息......
模擬RunLoop內(nèi)部實(shí)現(xiàn)
其實(shí)它內(nèi)部就是do-while循環(huán),在這個(gè)循環(huán)內(nèi)部不斷地處理各種任務(wù)(比如Source譬胎、Timer差牛、Observer)
void message(int num)
{
printf("執(zhí)行第%i個(gè)任務(wù)", num);
}
int main(int argc, const char * argv[]) {
do {
printf("有事做嗎? 沒事做我休眠了");
int number;
scanf("%i", &number);
message(number);
} while (1);
return 0;
}
獲得RunLoop對(duì)象
RunLoop對(duì)象
NSRunLoop
CFRunLoopRef
Foundation[NSRunLoop currentRunLoop];
// 獲得當(dāng)前線程的RunLoop對(duì)象[NSRunLoop mainRunLoop];
// 獲得主線程的RunLoop對(duì)象
Core FoundationCFRunLoopGetCurrent();
// 獲得當(dāng)前線程的RunLoop對(duì)象CFRunLoopGetMain();
// 獲得主線程的RunLoop對(duì)象
RunLoop結(jié)構(gòu)
CFRunLoopRef對(duì)應(yīng)RunLoop對(duì)象
CFRunLoopModeRef代表RunLoop的運(yùn)行模式, 系統(tǒng)默認(rèn)注冊(cè)了5個(gè)Mode
NSDefaultRunLoopMode:App的默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行
UITrackingRunLoopMode:界面跟蹤 Mode堰乔,用于 ScrollView 追蹤觸摸滑動(dòng)偏化,保證界面滑動(dòng)時(shí)不受其他 Mode 影響
NSRunLoopCommonModes: 這是一個(gè)占位用的Mode,不是一種真正的Mode
CFRunLoopTimerRef是基于時(shí)間的觸發(fā)器
CFRunLoopTimerRef基本上說的就是NSTimer镐侯,它受RunLoop的Mode影響
CFRunLoopSourceRef是事件源(輸入源)
CFRunLoopObserverRef是觀察者侦讨,能夠監(jiān)聽RunLoop的狀態(tài)改變
// 1.創(chuàng)建Observer
// 第一個(gè)參數(shù):用于分配該observer對(duì)象的內(nèi)存
// 第二個(gè)參數(shù):用以設(shè)置該observer所要關(guān)注的的事件
// 第三個(gè)參數(shù):用于標(biāo)識(shí)該observer是在第一次進(jìn)入run loop時(shí)執(zhí)行, 還是每次進(jìn)入run loop處理時(shí)均執(zhí)行
// 第四個(gè)參數(shù):用于設(shè)置該observer的優(yōu)先級(jí)
// 第五個(gè)參數(shù): observer監(jiān)聽到事件時(shí)的回調(diào)block
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
switch(activity)
{
case kCFRunLoopEntry:
NSLog(@"即將進(jìn)入loop");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"即將處理timers");
break;
case kCFRunLoopBeforeSources:
NSLog(@"即將處理sources");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"即將進(jìn)入休眠");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"剛從休眠中喚醒");
break;
case kCFRunLoopExit:
NSLog(@"即將退出loop");
break;
default:
break;
}
});
// 2.添加監(jiān)聽
/*
第一個(gè)參數(shù): 給哪個(gè)RunLoop添加監(jiān)聽
第二個(gè)參數(shù): 需要添加的Observer對(duì)象
第三個(gè)參數(shù): 在哪種模式下監(jiān)聽
*/
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopDefaultMode);
// 3,釋放observer
CFRelease(observer);
RunLoopRunLoop處理邏輯(略)
RunLoopRunLoop應(yīng)用
NSTimer
只能在指定的model下運(yùn)行
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
ImageView顯示
只能在指定的model下設(shè)置圖片
PerformSelector
只能在指定的model下調(diào)用
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:[UIImage imageNamed:@"lnj"] waitUntilDone:YES modes:@[NSDefaultRunLoopMode]];
常駐線程
必須調(diào)用run才會(huì)執(zhí)行死循環(huán)
NSRunLoop的model中必須有source/timer,死循環(huán)才不會(huì)退出
NSRunLoop *runloop = [NSRunLoop currentRunLoop];[runloop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runloop run]
自動(dòng)釋放池activities = 0x1 = 11:
即將進(jìn)入RunLoop :
創(chuàng)建一個(gè)自動(dòng)釋放池activities = 0xa0 = 160 = 128 + 3232:即將休眠 :
釋放上一次的自動(dòng)釋放池, 創(chuàng)建一個(gè)新的自動(dòng)釋放池128:即將退出RunLoop :
釋放自動(dòng)釋放池
NSURLRequest
用于保存請(qǐng)求地址/請(qǐng)求頭/請(qǐng)求體
默認(rèn)情況下NSURLRequest會(huì)自動(dòng)給我們?cè)O(shè)置好請(qǐng)求頭
request默認(rèn)情況下就是GET請(qǐng)求
同步請(qǐng)求
如果是調(diào)用NSURLConnection的同步方法, 會(huì)阻塞當(dāng)前線程
// 1.創(chuàng)建一個(gè)URL
NSURL *url = [NSURL URLWithString:@"[http://129.168.1.1:31812/login2?username=cyx&pwd=123&type=JSON](http://129.168.1.1:31812/login2?username=cyx&pwd=123&type=JSON)"];
// 2.根據(jù)URL創(chuàng)建NSURLRequest對(duì)象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.利用NSURLConnection對(duì)象發(fā)送請(qǐng)求
/*
第一個(gè)參數(shù): 需要請(qǐng)求的對(duì)象
第二個(gè)參數(shù): 服務(wù)返回給我們的響應(yīng)頭信息
第三個(gè)參數(shù): 錯(cuò)誤信息
返回值: 服務(wù)器返回給我們的響應(yīng)體
*/
NSHTTPURLResponse *response = nil; // 真實(shí)類型
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
NSLog(@"response = %@", response.allHeaderFields);
異步請(qǐng)求
// 1.創(chuàng)建一個(gè)URL
NSURL *url = [NSURL URLWithString:@"[http://129.168.1.1:31812/login2?username=cyx&pwd=123&type=JSON](http://129.168.1.1:31812/login2?username=cyx&pwd=123&type=JSON)"];
// 2.根據(jù)URL創(chuàng)建NSURLRequest對(duì)象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.利用NSURLConnection對(duì)象發(fā)送請(qǐng)求
/*
第一個(gè)參數(shù): 需要請(qǐng)求的對(duì)象
第二個(gè)參數(shù): 回調(diào)block的隊(duì)列, 決定了block在哪個(gè)線程中執(zhí)行
第三個(gè)參數(shù): 回調(diào)block
*/
// 注意點(diǎn): 如果是調(diào)用NSURLConnection的同步方法, 會(huì)阻塞當(dāng)前線程
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
POST方法
// 1.創(chuàng)建一個(gè)URL
NSURL *url = [NSURL URLWithString:@"[http://129.168.1.1:31812/login](http://129.168.1.1:31812/login)"];
// 2.根據(jù)URL創(chuàng)建NSURLRequest對(duì)象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 2.1設(shè)置請(qǐng)求方式
// 注意: POST一定要大寫
request.HTTPMethod = @"POST";
// 2.2設(shè)置請(qǐng)求體
// 注意: 如果是給POST請(qǐng)求傳遞參數(shù): 那么不需要寫?號(hào)
request.HTTPBody = [@"username=cyx&pwd=123&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
// 3.利用NSURLConnection對(duì)象發(fā)送請(qǐng)求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
請(qǐng)求服務(wù)器響應(yīng)
// 1.創(chuàng)建URL
NSURL *url = [NSURL URLWithString:@"[http://xxx.jpg](http://xxx.jpg)"];
// 2.根據(jù)URL創(chuàng)建NSURLRequest
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.利用NSURLConnection發(fā)送請(qǐng)求
/*
// 只要調(diào)用alloc/initWithRequest, 系統(tǒng)會(huì)自動(dòng)發(fā)送請(qǐng)求
[[NSURLConnection alloc] initWithRequest:request delegate:self];
*/
/*
// startImmediately: 如果傳遞YES, 系統(tǒng)會(huì)自動(dòng)發(fā)送請(qǐng)求; 如果傳遞NO, 系統(tǒng)不會(huì)自動(dòng)發(fā)送請(qǐng)求
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[conn start];
*/
[NSURLConnection connectionWithRequest:request delegate:self];
- 代理方法
#pragma mark - NSURLConnectionDataDelegate
/*
只要接收到服務(wù)器的響應(yīng)就會(huì)調(diào)用
response:響應(yīng)頭
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(@"%s", __func__);
}
/*
接收到服務(wù)器返回的數(shù)據(jù)時(shí)調(diào)用(該方法可能調(diào)用一次或多次)
data: 服務(wù)器返回的數(shù)據(jù)(當(dāng)前這一次傳遞給我們的, 并不是總數(shù))
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"%s", __func__);
}
/*
接收結(jié)束時(shí)調(diào)用
*/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"%s", __func__);
}
/*
請(qǐng)求錯(cuò)誤時(shí)調(diào)用(請(qǐng)求超時(shí))
*/
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"%s", __func__);
}
中文問題
// 1.創(chuàng)建URL
NSString *urlStr = @"[http://129.168.1.1:31812/login2?username=cyx&pwd=123&type=JSON](http://129.168.1.1:31812/login2?username=cyx&pwd=123&type=JSON)";
NSLog(@"轉(zhuǎn)換前:%@", urlStr);
// 2.對(duì)URL進(jìn)行轉(zhuǎn)碼
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];