網絡總結

網絡

基本概念

  • 客戶端:client
  • 服務器:server
  • 請求:request
  • 響應:response
  • 過程html5

    • 客戶端 -> 發送請求 -> 服務器(鏈接數據庫)
    • 服務器 -> 發送響應 -> 客戶端
  • 客戶端(移動端)ios

    • 前段(前臺)
    • iOS,Android
  • 服務器(後端)web

    • 後臺
    • Java、PHP、.NET
    • 遠程服務器-面向全部用戶(上線)
    • 本地服務器-面向公司內部(測試)
  • URL數據庫

    • URL的全稱是Uniform Resource Locator(統一資源定位符)
    • 經過1個URL,能找到互聯網上惟一的1個資源
    • URL就是資源的地址、位置,互聯網上的每一個資源都有一個惟一的URL
    • URL的基本格式 = 協議://主機地址/路徑
  • URL中常見協議json

HTTP通訊

  • http的做用是統一客戶端和服務器的數據交換格式,使得彼此能夠理解。
  • 優勢後端

    • 簡單快速,服務器規模小,通訊速度快
    • 靈活,容許傳輸任意類型的數據
    • HTTP 0.9和1.0使用短鏈接方式(非持續鏈接):每次鏈接只處理一個請求,服務器作出響應後,立刻斷開鏈接。

iOS中經常使用的HTTP請求方式

  • 原生數組

    • NSURLConnection - 最古老的方案
    • NSURLSession - iOS7推出的新技術
    • CFNetworking - NSURL的底層,純C語言
  • 第三方框架xcode

    • ASIHttpRequest - 外號「HTTP終結者」,功能強大,惋惜已經中止更新
    • AFNetworking - 維護使用者多
    • MKNetworkKit - 印度,維護使用者少
  • HTTP 請求緩存

    • HTTP/1.1 中定義了8種方法
    • GETPOST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH
    • 最經常使用的就是GET、POST

HTTP 實踐 - NSURLConnection(瞭解便可)

  • HTTP同步請求
// 發送同步請求,會一直等待, 直到接收到數據 - (void)requestSynch { // 1 建立請求鏈接 NSURL *url = [NSURL URLWithString:@"http://www.lala.com/login?username=123&pwd=123"]; // 2 建立請求 NSURLRequest *request = [NSURLRequest requestWithURL:url ]; NSHTTPURLResponse *response = nil; NSError *error = nil; // 3 發送同步請求 // endSynchronousRequest阻塞式的方法,等待服務器返回數據 NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; // 4.解析服務器返回的數據(解析成字符串) NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"--%@--%@-- %zd",str,response.allHeaderFields,response.statusCode); }
  • HTTP異步請求
// 發送異步請求 - (void)requestAsync { // 1 建立請求鏈接 NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=123"]; // 2 建立請求 NSURLRequest *request = [NSURLRequest requestWithURL:url ]; // 3 發送異步請求 [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { // 4.解析服務器返回的數據(解析成字符串) NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSHTTPURLResponse *httpRes = (NSHTTPURLResponse* )response; NSLog(@"--%@--%zd--%@--",str,httpRes.statusCode,httpRes.allHeaderFields); }]; }
  • HTTP代理請求模式

    • 協議:NSURLConnectionDataDelegate
    • 實現方法
// 1 建立請求鏈接 NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=520it&pwd=520it"]; // 2 建立請求 NSURLRequest *request = [NSURLRequest requestWithURL:url ]; // 3 代理請求模式,要遵照協議並實現代理方法 [NSURLConnection connectionWithRequest:request delegate:self]; ///-----------------------------------------------------------------/// // 經常使用代理方法 // 接收服務器響應 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { self.localData = [NSMutableData data]; NSLog(@"-didReceiveResponse-%zd",((NSHTTPURLResponse *)response).statusCode); } // 接收到服務器的數據(若是數據量比較大,這個方法會被調用屢次) - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self.localData appendData:data]; NSLog(@"-didReceiveData-"); } // 完成數據下載 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSString *str = [[NSString alloc] initWithData:self.localData encoding:NSUTF8StringEncoding]; NSLog(@"-connectionDidFinishLoading-%@",str); } // 請求失敗:請求超時等 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"-didFailWithError-"); }

簡單登錄界面

  • GET請求
- (IBAction)loginBtn:(id)sender { // 獲取控件數據和網絡數據進行比對 NSString *userName = self.userText.text; if (userName.length == 0 ) { [SVProgressHUD showErrorWithStatus:@"用戶名不能爲空"]; return; } NSString *pwd = self.pwdText.text; if (pwd.length == 0) { [SVProgressHUD showErrorWithStatus:@"密碼不能爲空"]; return; } // 顯示陰影 [SVProgressHUD showWithStatus:@"正在登錄中" maskType:SVProgressHUDMaskTypeBlack]; // NSString *format = [NSString stringWithFormat:@"http://123.123.123.123/login?username=%@&pwd=%@",userName,pwd]; NSLog(@"%@",format); // 1 建立請求鏈接 NSURL *url = [NSURL URLWithString:format]; // 2 建立請求 NSURLRequest *request = [NSURLRequest requestWithURL:url ]; // 3 發送異步請求 [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { // JSON:{"success":"登陸成功"} // 4.解析服務器返回的數據(解析成字符串) NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; // 對字符串進行分割 NSInteger loc = [str rangeOfString:@"\":\""].location + 3; NSInteger len = [str rangeOfString:@"\"}"].location - loc; NSString *result = [str substringWithRange:NSMakeRange(loc, len)]; // 顯示結果 if ([result containsString:@"success"]) { [SVProgressHUD showSuccessWithStatus:result]; } else { [SVProgressHUD showErrorWithStatus:result]; } }];
  • POST請求
NSString *format = [NSString stringWithFormat:@"http://123.123.123.123/login"]; // 1 建立請求鏈接 NSURL *url = [NSURL URLWithString:format]; // 2 建立請求 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url ]; // 更改請求方法 request.HTTPMethod = @"POST"; // 設置請求體 request.HTTPBody = [@"username=520it&pwd=520it" dataUsingEncoding:NSUTF8StringEncoding]; // 設置超時 request.timeoutInterval = 5; // 設置請求頭 // [request setValue:@"ios9.0" forHTTPHeaderField:@"User-agent"]; // 3 發送請求 [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { if (connectionError) { NSLog(@"失敗"); } else { NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); } }];
  • 路徑中有漢字的話必須進行轉換
  • GET:手動轉換
format = [format stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  • POST:在設置請求體時直接設置了編碼格式,會自動轉換
// 設置請求體 request.HTTPBody = [@"username=小碼哥&pwd=520it" dataUsingEncoding:NSUTF8StringEncoding];

解析JSON

  • 服務器返回給客戶端的數據通常都是JSON或者XML
  • JSON的格式很像OC中的字典和數組

    • {"name" : "jack", "age" : 10}
    • {"names" : ["jack", "rose", "jim"]}
  • 標準JSON格式的注意點:key必須用雙引號
  • JSON和OC的對應關係

JSON OC
{ } 字典 NSDictionry
[] 數組 NSArray
「 」 字符串 NSString
10,10.4 NSNumber

IOS中JSON解決方案

  • 第三方

    • JSONKit、SBJson、TouchJSON(性能從左到右,越差)
  • 蘋果原生(自帶):NSJSONSerialization(性能最好)

NSJSONSerialization

  • 解析JSON
  • data轉JSON
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error; // data轉JSON NSString *str = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
  • JSON轉data
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
  • 關於參數
typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) { NSJSONReadingMutableContainers = (1UL << 0), // 可變容器 NSJSONReadingMutableLeaves = (1UL << 1), // 子節點也是可變的,也就是說轉換的全部數據都是可變的 NSJSONReadingAllowFragments = (1UL << 2) // 接收零散數據,好比說單個的‘10’,'false' } NS_ENUM_AVAILABLE(10_7, 5_0);
  • 參數NSJSONReadingAllowFragments使用以下
// 參數NSJSONReadingAllowFragments 用來讀取單個元素 NSString *str = @"10"; NSData *data = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil]; NSLog(@"-- %@ --",data);
  • JSON轉模型
  • 每次都手動去轉換的話,很是費時費力。可使用第三方框架
  • MJExtension
#import <MJExtension.h> // 得到視頻的模型數組 self.videos = [SLQVideo objectArrayWithKeyValuesArray:dict[@"videos"]]; 

蘋果自帶的movie播放器

  • 只能播放有限的幾種格式(mp四、mov等)
// 播放視頻 NSURL *url = [NSURL URLWithString:@"http://123.123.123.123"]; // MPMoviePlayerViewController // 視圖控制器 // MPMoviePlayerController // 內部沒有view,不能直接彈出 MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc] initWithContentURL:[url URLByAppendingPathComponent:video[@"url"]]]; // modal 出視頻並播放 [self presentViewController:vc animated:YES completion:nil];

字典轉模型框架

  • Mantle

    • 全部模型都必須繼承自MTModel
  • JSONModel

    • 全部模型都必須繼承自JSONModel
  • MJExtension

    • 不須要強制繼承任何其餘類

設計框架須要考慮的問題

  • 侵入性

    • 侵入性大就意味着很難離開這個框架
  • 易用性

    • 好比少許代碼實現N多功能
  • 擴展性

    • 很容易給這個框架增長新框架

解析XML

  • XML解析方式

    • SAX:逐行解釋
    • DOM:一次性加載到內存
  • 蘋果自帶:NSXMLParser

    • SAX 方式
  • 第三方庫

    • libxml2 : 純C語言,默認包含在iOS SDK 中,,同時支持SAX、DOM
    • GDataXML : DOM方式,由google開發,基於libxml2
  • 建議

    • 大文件 : NSXMLParser、libxml2
    • 小文件 : GDataXML、XSXMLParser、libxml2

XSXMLParser

  • 使用過程

    • 一、設置源,初始化一個XSXMLParser對象
    • 二、設置代理,實現代理方法
    • 三、啓動掃描
// 初始化方法 - (instancetype)initWithContentsOfURL:(NSURL *)url; // initializes the parser with the specified URL. - (instancetype)initWithData:(NSData *)data; // create the parser from data
  • 使用方法
// 1 使用蘋果的XML類解析xml文檔 NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; parser.delegate = self; // 2 設置代理 [parser parse]; // 3 啓動掃描
  • 主要是代理方法的使用
#pragma mark -NSXMLParserDelegate代理方法 // 讀取文檔開始 - (void)parserDidStartDocument:(NSXMLParser *)parser { // NSLog(@"parserDidStartDocument"); // self.videoArray = [NSMutableArray array]; } // 讀取文檔結束 - (void)parserDidEndDocument:(NSXMLParser *)parser { // NSLog(@"parserDidEndDocument--%@",self.videoArray); } // 開始讀取元素,attributes 參數表示要讀取的元素 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{ // NSLog(@"didStartElement---%@",attributeDict); // 全部的元素都會通過這裏進行讀取,包括根 // 因此要進行判斷,把根給排除 if ([elementName isEqualToString:@"videos"]) { return; } // 獲取模型數據,放入數組 SLQVideoItem *video = [SLQVideoItem objectWithKeyValues:attributeDict]; [self.videoArray addObject:video]; } // 讀取元素結束 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { }

格式化服務器返回的JSON數據

GDataXML

  • 這個配置起來很麻煩

    • 首先不支持CocoaPods,因此只能手動拖拽進項目,並且項目比較舊。
    • 而後進入工程設置 Header Search Paths 添加/usr/include/libxml2
    • 設置工程 Other Linker Flags contain 添加 -lxml2
    • 改變文件的編譯方式爲非ARC - -fno -objc -arc
    • 最後編譯纔不會出錯
  • 使用過程

    • GDataXMLDocument - 整個文檔
    • GDataXMLElement - xml中某個元素
// 1 使用GDataXML解析xml文件 GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil]; // 2 獲取全部video元素,首先要得到根節點 NSArray *elements = [doc.rootElement elementsForName:@"video"]; // 3 遍歷全部元素 for (GDataXMLElement *ele in elements) { SLQVideoItem *video = [[SLQVideoItem alloc] init]; // 4 獲取元素屬性,轉換成字符串 video.name = [[ele attributeForName:@"name"] stringValue]; video.image = [[ele attributeForName:@"image"] stringValue]; video.url = [[ele attributeForName:@"url"] stringValue]; video.length = [[[ele attributeForName:@"length"] stringValue] intValue]; [self.videoArray addObject:video]; }

多值參數

  • 同一個參數傳如多個數據,逗號分隔
  • 一個參數包括多個字典
// NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/weather?place=beijing&place=shanghai"]; NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/weather?place=beijing,shanghai"];

解決輸出到控制檯顯示中文亂碼的問題

  • 重寫descriptionWithLocale方法,這二個方法會在轉換JSON時自動調用。
@implementation NSDictionary (Log) - (NSString *)descriptionWithLocale:(id)locale { // {"weathers":[{"city":"beijing,shanghai","status":"晴轉多雲"}]}\ // 將這句話格式化輸出 NSMutableString *str =[NSMutableString string]; [str appendString:@"{\n"]; [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { // 拼接字符串 [str appendFormat:@"\t%@",key]; [str appendString:@" : "]; [str appendFormat:@"%@,\n",obj]; }]; [str appendString:@"}"]; // 取出最後一個逗號 NSRange range = [str rangeOfString:@"," options:NSBackwardsSearch]; if (range.location != NSNotFound) { [str deleteCharactersInRange:range]; } return str; } @end /* 2015-07-15 18:43:08.137 05-掌握-多值參數[65936:116425] { weathers : [ { status : 晴轉多雲, city : Beijing }, { status : 晴轉多雲, city : Shanghai } ] } */ @implementation NSArray (Log) - (NSString *)descriptionWithLocale:(id)locale { // 將這句話格式化輸出 NSMutableString *str =[NSMutableString string]; [str appendString:@"[\n"]; [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [str appendFormat:@"\t%@,\n",obj]; }]; [str appendString:@"\t]"]; // 取出最後一個逗號 NSRange range = [str rangeOfString:@"," options:NSBackwardsSearch]; if (range.location != NSNotFound) { [str deleteCharactersInRange:range]; } return str; } @end

文件下載

小文件下載

  • 直接使用NSData下載

    NSData *data = [NSData dataWithContentsOfURL:url];
  • 使用NSURLConnection 異步鏈接

    NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/images/minion_13.png"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSLog(@"---%zd---",data.length); }];
  • 使用NSURLConnection代理方式實現

- (void)viewDidLoad { [super viewDidLoad]; // 創建鏈接 NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"]; [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url] delegate:self]; } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response { NSLog(@"didReceiveResponse:%@",response); // 初始化 self.data = [NSMutableData data]; self.movieCount = [response.allHeaderFields[@"Content-Length"] integerValue]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // 緩存到內存 [self.data appendData:data]; CGFloat progress = 1.0 * self.data.length / self.movieCount; self.progressView.progress = progress; NSLog(@"%f",progress * 100 ); } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { // 這裏進行文件的保存,保存到cache裏 NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; [self.data writeToFile:[filePath stringByAppendingPathComponent:@"1.mp4"] atomically:YES]; self.data = nil; }

大文件下載

  • 使用NSURLConnection代理方式實現
// 接收到響應的時候:建立一個空的文件 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response { // 獲取文件長度 self.movieCount = [response.allHeaderFields[@"Content-Length"] integerValue]; // 建立一個空文件 [[NSFileManager defaultManager] createFileAtPath:SLQFilePath contents:nil attributes:nil]; // 建立文件句柄 self.handle = [NSFileHandle fileHandleForWritingAtPath:SLQFilePath]; } // 接收到具體數據:立刻把數據寫入一開始建立好的文件 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // 移動到文件末尾 [self.handle seekToEndOfFile]; // 寫入數據 [self.handle writeData:data]; // self.currentCount += data.length; CGFloat progress = 1.0 * self.currentCount / self.movieCount; self.progressView.progress = progress; NSLog(@"%f",progress * 100 ); } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { self.movieCount = 0; // 關閉文件 [self.handle closeFile]; self.handle = nil; }

解壓縮

  • 解壓縮使用第三方庫SSZipArchive
// 1 使用指定文件,建立一個壓縮文件 NSArray *paths = @[ @"/Users/song/Desktop/test/1.png", @"/Users/song/Desktop/test/2.png", @"/Users/song/Desktop/test/3.png", @"/Users/song/Desktop/test/4.png", @"/Users/song/Desktop/test/5.png" ]; [Main createZipFileAtPath:@"/Users/song/Desktop/test.zip" withFilesAtPaths:paths]; // 2 使用指定目錄建立一個壓縮文件 [Main createZipFileAtPath:@"/Users/song/Desktop/test121212.zip" withContentsOfDirectory:@"/Users/song/Desktop/test"]; // 3 解壓縮一個文件到指定目錄 [Main unzipFileAtPath:@"/Users/song/Desktop/test.zip" toDestination:@"/Users/song/Desktop"];

文件上傳

// 必定要注意這個格式是固定的 /* 文件參數格式 --分割線\r\n Content-Disposition: form-data; name="參數名"; filename="文件名"\r\n Content-Type: 文件的MIMEType\r\n \r\n 文件數據 \r\n */ // 文件上傳 // 一、建立請求 NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/upload"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 二、設置協議 request.HTTPMethod = @"POST"; // 三、設置請求頭 [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",SLQBoundary] forHTTPHeaderField:@"Content-Type"]; // 四、設置請求體 NSMutableData *body = [NSMutableData data]; // 設置文件參數 // 設置邊界 [body appendData:SLQUTF(@"--")]; [body appendData:SLQUTF(SLQBoundary)]; [body appendData:SLQEnter]; // 文件參數名 [body appendData:SLQUTF([NSString[] stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"1.png\""])]; [body appendData:SLQEnter]; // 文件類型 [body appendData:SLQUTF([NSString stringWithFormat:@"Content-Type: image/png"])]; [body appendData:SLQEnter]; // 文件內容 [body appendData:SLQEnter]; UIImage *image = [UIImage imageNamed:@"1"]; [body appendData:UIImagePNGRepresentation(image)]; [body appendData:SLQEnter]; /* 非文件參數格式 --分割線\r\n Content-Disposition: form-data; name="參數名"\r\n \r\n 參數值 \r\n */ // 設置非文件參數 [body appendData:SLQUTF(@"--")]; [body appendData:SLQUTF(SLQBoundary)]; [body appendData:SLQEnter]; [body appendData:SLQUTF([NSString stringWithFormat:@"Content-Disposition: form-data; name=\"username\""])]; [body appendData:SLQEnter]; [body appendData:SLQEnter]; [body appendData:SLQUTF(@"bulabulabula")]; [body appendData:SLQEnter]; /* 結束標記 --分割--線\r\n \r\n */ // 結束標記 [body appendData:SLQUTF(@"--")]; [body appendData:SLQUTF(SLQBoundary)]; [body appendData:SLQUTF(@"--")]; [body appendData:SLQEnter]; request.HTTPBody = body; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { // 這個方法會調用descriptionWithLocale方法,能夠在這裏解決輸出到控制檯顯示中文亂碼的問題 NSLog(@"%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); }];

獲取MIMEType

  • OC 方法
- (NSString *)getMIMEType:(NSString *)path { NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]; NSURLResponse *response = nil; [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil]; return response.MIMEType; }
  • c語言
// 要包含頭文件MobileCoreServices.h + (NSString *)mimeTypeForFileAtPath:(NSString *)path { if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { return nil; } CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[path pathExtension], NULL); CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType); CFRelease(UTI); if (!MIMEType) { return @"application/octet-stream"; } return (__bridge NSString *)(MIMEType); }

NSOutputStream

  • 文件流,文件輸出流,能夠輸出到內存、硬盤、NSData
- (void)viewDidLoad { [super viewDidLoad]; // 創建鏈接 NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"]; [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url] delegate:self]; } /** * 接收到響應的時候:建立一個空的文件 */ - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response { // 獲取服務器那裏給出的建議名字 response.suggestedFilename); NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; // 建立文件流 self.stream = [[NSOutputStream alloc] initToFileAtPath:path append:YES]; // 打開文件流 [self.stream open]; } /** * 接收到具體數據:立刻把數據寫入一開始建立好的文件 */ - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // 參數1要求是bytes [self.stream write:[data bytes] maxLength:data.length]; NSLog(@"---"); } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { // 關閉文件流 [self.stream close]; }

NSURLConnection和NSRunLoop

  • 使用NSURLConnection建立的請求,其內部和NSRunLoop有關聯,必須保證NSRunLoop處於運行狀態,不然代理方法運行起來就會出問題。
  • 若是要在子線程裏建立請求,必需要手動啓動NSRunLoop,而且要在方法使用結束手動關閉NSRunLoop。
// 創建鏈接 NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/images/minion_05.png"]; NSURLConnection *con = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url] delegate:self]; // 決定代理方法在哪一個隊列中執行 [con setDelegateQueue:[[NSOperationQueue alloc] init]]; // 開啓子線程runloop self.runloop = CFRunLoopGetCurrent(); CFRunLoopRun();

在代理方法中使用完畢,中止runloop

- (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"--connectionDidFinishLoading--%@",[NSThread currentThread]); CFRunLoopStop(self.runloop); }

NSURLSession

  • 這個是在iOS7以後推出的用於替代NSURLConnection的新類,推薦掌握這個
  • NSURLSession 主要由兩部分組成,一個是Session實例對象,一個是任務。
  • 使用步驟

    • 建立task(dataTaskWithRequest),啓動task(resume
    • 抽象類,使用其子類(NSURLSessionDataTaskNSURLSessionDownloadTaskNSURLSessionUploadTask
    • 大小文件都同樣,默認寫入到tmp目錄下面,下載完畢後要本身移動文件
  • NSURLSession 代理

    • 初始化時設置代理<NSURLSessionDataDelegate>
    • 實現過程

      • 接收響應,指定響應方式:取消、下載、變爲下載 didReceivedResponse
      • 接收數據didReceivedData
      • 接收完畢(成功和失敗都會進入這個方法)didComplete
    • 這個能夠實現大文件下載
  • 大文件斷點下載

    • NSURLSession 的方法:suspend、resume、cancel
    • resumeData 保存暫停時程序數據狀態,取消任務後要根據狀態恢復下載
    • (很差 ,實現複雜)將下載的tmp文件保存到cachae,而後恢復如今時再從cache移動到臨時文件
    • 下載失敗後要從NSError中獲取失敗時的恢復數據
  • 何爲斷點下載

    • 程序因意外事件終止,致使下載被中止,主要考慮用戶忽然關閉程序。
    • 能夠將下載的數據同步到沙盒中,而且記錄下載大小,以及記錄已下載的文件,每次下載以前都進行掃描一番。
    • 若是下載一半就在請求頭裏指定要下載的範圍
  • 上傳

    • NSURLSessionUploadTast
    • POST 請求設置注意methodBody爲上傳的參數fromData
    • NSURLSessionConfiguration 統一配置(好比能夠在這裏設置是否容許設置程序使用蜂窩移動網絡)

GET

NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=4324"]; // 1 得到NSURLSession單例對象 NSURLSession *session = [NSURLSession sharedSession]; // 2 建立任務 NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { // 4 處理數據 NSLog(@"----%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); }]; // 3 啓動任務 [task resume];

POST

// post請求 NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=4324"]; // 得到NSURLSession單例對象 NSURLSession *session = [NSURLSession sharedSession]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 設置請求頭 request.HTTPMethod = @"POST"; // 設置請求體 NSMutableData *body = [NSMutableData data]; [body appendData:[@"username=123&pwd=234" dataUsingEncoding:NSUTF8StringEncoding]]; request.HTTPBody = body; // 建立任務 NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"----%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); }]; // 啓動任務 [task resume];

下載

  • 直接使用downloadTaskWithURL:url進行下載,不過下載成功的文件是放在tmp臨時目錄裏面的,必定要及時把文件給移出來。
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"]; // 得到NSURLSession單例對象 NSURLSession *session = [NSURLSession sharedSession]; // 建立任務 NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; // 這個方式下載的文件在tmp文件夾下,要把下載的文件移動到cache中永久保存,參數是 fileURLWithPath,看清了 // loaction 表示在本地臨時存儲區的路徑 [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil]; }]; // 啓動任務 [task resume];

代理方式

- (void)viewDidLoad { [super viewDidLoad]; NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"]; // 建立 NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]]; // 建立任務 NSURLSessionDataTask *task = [session dataTaskWithURL:url]; // 啓動任務 [task resume]; } // 接收服務器響應,必須手動執行後續的執行方式(容許接收數據仍是不容許接收) - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { NSLog(@"%s",__func__); // 必須手動指定接下來的數據要不要接收 completionHandler(NSURLSessionResponseAllow); } // 接收數據,屢次調用 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { NSLog(@"%s",__func__); } // 下載完畢後調用,若是失敗,看參數error的值 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { NSLog(@"%s",__func__); } typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) { NSURLSessionResponseCancel = 0,/* Cancel the load, this is the same as -[task cancel] */ NSURLSessionResponseAllow = 1,/* Allow the load to continue */ NSURLSessionResponseBecomeDownload = 2,/* Turn this request into a download */ } NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0); 

斷點下載

  • 經過自定義NSURLSession ,使用dataWithTask來進行下載,而且手動控制器下載文件的去向。
  • 每次下載以前都要去沙盒讀取已下載的文件,用於判斷從哪裏進行下載
  • 主要方法以下:
- (NSURLSessionDataTask *)dataTask { if (!_dataTask) { // 獲取下載進度,直接從沙盒中讀取文件長度 NSInteger total = [[NSMutableDictionary dictionaryWithContentsOfFile:SLQDownloadFilePath][SLQFileName] integerValue]; NSInteger current = [[[NSFileManager defaultManager] attributesOfItemAtPath:SLQFilePath error:nil][NSFileSize] integerValue]; if (total && total == current ) { NSLog(@"已經下載完畢"); return nil; } // 若是長度和 NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 指定要從服務器獲取的數據的範圍 NSString *range = [NSString stringWithFormat:@"bytes=%zd-",current]; [request setValue:range forHTTPHeaderField:@"Range"]; // 建立任務 _dataTask = [self.session dataTaskWithRequest:request]; } return _dataTask; } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { // NSLog(@"----%@",[response class]); // 開啓輸出流 [self.stream open]; // 計算總得數據長度,response會返回請求的數據長度,不包括已經下載的數據長度,因此要累加起來 self.totalCount = [response.allHeaderFields[@"Content-Length"] integerValue] + SLQFileLength; NSString *name = response.suggestedFilename; // 存儲總長度,將所要下載的文件長度保存起來 NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:SLQDownloadFilePath]; if (dict == nil) { dict = [NSMutableDictionary dictionary]; } dict[SLQFileName] = @(self.totalCount); [dict writeToFile:SLQDownloadFilePath atomically:YES]; // 繼續下載 completionHandler(NSURLSessionResponseAllow); } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { // 寫入數據到沙盒 [self.stream write:[data bytes]maxLength:data.length]; // 獲取下載進度,直接從沙盒中讀取文件長度 NSLog(@"---%f",1.0 * SLQFileLength / self.totalCount); } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { // 清空 self.dataTask = nil; [self.stream close]; self.stream = nil; }

NSURLSession 上傳文件

  • 必須按照格式寫,一個空格或者回車都不能多。
// 必定要注意這個格式是固定的 /* 文件參數格式 --分割線\r\n Content-Disposition: form-data; name="file"; filename="文件名"\r\n Content-Type: 文件的MIMEType\r\n \r\n 文件數據 \r\n // 結束標記 \r\n --分割線--\r\n \r\n */ // 主要是參數第二個參數要傳入 **`請求體`** [[self.session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"---%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); }] resume];

AFNetworking

  • GET\POST

    • AFHTTPRequestManager
    • AFHTTPSessionManager
- (void)GET { // GET AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager]; // 將數據做爲參數傳入 NSDictionary *dict = @{ @"username":@"12", @"pwd":@"13" }; [mgr GET:[NSString stringWithFormat:@"http://123.123.123.123/login"] parameters:dict success:^(NSURLSessionDataTask *task, id responseObject) { NSLog(@"success:%@",responseObject); } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"failure:%@",error); }]; } - (void)POST { // POST AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager]; // 將數據做爲參數傳入 NSDictionary *dict = @{ @"username":@"12", @"pwd":@"13" }; [mgr POST:[NSString stringWithFormat:@"http://123.123.123.123/login"] parameters:dict success:^(NSURLSessionDataTask *task, id responseObject) { NSLog(@"success:%@",responseObject); } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"failure:%@",error); }]; }
  • 文件上傳:appendPartWithFileData:
- (void)upload { // 文件上傳 AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager]; // 將數據做爲參數傳入 [mgr POST:@"http://123.123.123.123/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { // formdata 爲要上傳的數據 // [formData appendPartWithFileURL:[NSURL fileURLWithPath:@"/Users/song/Desktop/test.png"] name:@"file" error:nil]; [formData appendPartWithFileData:[NSData dataWithContentsOfFile:@"/Users/song/Desktop/test.png"] name:@"file" fileName:@"wer.png" mimeType:@"image/png"]; } success:^(NSURLSessionDataTask *task, id responseObject) { NSLog(@"success:%@",responseObject); } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"failure:%@",error); }]; }
  • 文件下載

    • 下載文件須要返回一個保存路徑,還須要手動啓動resume
- (void)download { // 下載 AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager]; [[mgr downloadTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://123.123.123.123/resources/images/minion_02.png"]] progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) { // 下載文件須要返回一個保存路徑,還須要手動啓動resume NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; return [NSURL fileURLWithPath:[path stringByAppendingPathComponent:response.suggestedFilename]]; } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { NSLog(@"%@",filePath.path); }] resume]; }
  • 默認是解析json,若是想解析xml,須要指定管理器的解析器爲xml

    • 若是解析其餘類型的文件,就將responseSerializer屬性設置爲ADHTTPResonseSericlizer,服務器返回什麼就接受什麼類型的數據。
-(void)returnType { // 默認返回的數據時JSON,若是想返回XML,設置屬性responseSerializer // 若是想返回服務器上文件原本的類型,設置AFHTTPResponseSerializer AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager]; // responseSerializer 用來解析服務器返回的數據 mgr.responseSerializer = [AFHTTPResponseSerializer serializer]; // 直接使用「服務器原本返回的數據」,不作任何解析 // 告訴AFN,以XML形式解析服務器返回的數據 // mgr.responseSerializer = [AFXMLParserResponseSerializer serializer]; // 將數據做爲參數傳入 [mgr GET:[NSString stringWithFormat:@"http://123.123.123.123/resources/images/minion_02.png"] parameters:nil success:^(NSURLSessionDataTask *task,id response) { NSLog(@"success:%zd",[response length]); } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"failure:%@",error); }]; }

手機聯網狀態

- 手機聯網狀態:`AFNetWorkReachabityManager` - 蘋果自帶:`Reachability` ,經過通知監聽系統狀態
  • 手機聯網狀態:AFNetWorkReachabityManager
- (void)monitor { // 監控網絡狀態 AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager]; // 網絡狀態改變就會調用這個block [mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { NSLog(@"網絡狀態改變:%zd",status); }]; // 打開監聽器 [mgr startMonitoring]; /* typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) { AFNetworkReachabilityStatusUnknown = -1, // 未知 AFNetworkReachabilityStatusNotReachable = 0, // 未聯網 AFNetworkReachabilityStatusReachableViaWWAN = 1, // 蜂窩網絡 AFNetworkReachabilityStatusReachableViaWiFi = 2, // wifi }; */ }
  • 手機聯網狀態:Reachability

    • 手機的狀態改變,會給系統發送通知,因此能夠添加監聽器,接收這個通知。
/**通知*/ @property (nonatomic, strong) Reachability *reach; - (void)viewDidLoad { [super viewDidLoad]; // 添加通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getNetworkStatus) name:kReachabilityChangedNotification object:nil]; // 接收通知 self.reach = [Reachability reachabilityForInternetConnection]; [self.reach startNotifier]; } - (void)getNetworkStatus { /* typedef enum : NSInteger { NotReachable = 0, // 網絡不可知 ReachableViaWiFi, // WIFI ReachableViaWWAN // 移動網絡 } NetworkStatus; */ // 獲取手機網絡狀態 if([Reachability reachabilityForLocalWiFi].currentReachabilityStatus != NotReachable) { NSLog(@"wifi"); } else if([Reachability reachabilityForInternetConnection].currentReachabilityStatus != NotReachable) { NSLog(@"3G?4G"); } else { NSLog(@"Nothing at all!"); } } - (void)dealloc { // 中止監聽器 [self.reach startNotifier]; // 移除通知 [[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil]; }

MD5加密

  • 使用:主要是對用戶的敏感信息進行加密

    • 對輸入信息生成惟一的128位散列值(32個字符)
    • 根據輸出值,不能獲得原始的明文,即其過程不可逆
  • MD5改進

    • 加鹽(Salt):在明文的固定位置插入隨機串,而後再進行MD5
    • 先加密,後亂序:先對明文進行MD5,而後對加密獲得的MD5串的字符進行亂序
    • 等等,就是讓信息更加複雜

HTTPS

  • 使用https要實現代理方法 didReceiveChallenge

  • 1 建立HTTPS連接

_dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); }];
  • 2 實現代理方法 didReceiveChallenge
/** 代理方法 * challenge : 挑戰、質詢 * completionHandler : 經過調用這個block,來告訴URLSession要不要接收這個證書 */ - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler { // NSURLSessionAuthChallengeDisposition : 如何處理這個安全證書 // NSURLCredential :安全證書 // NSLog(@"%@",challenge); if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { return; } if(completionHandler) { // 利用這個block說明使用這個證書 completionHandler(NSURLSessionAuthChallengeUseCredential,challenge.proposedCredential); } }

UIWebView

  • 顯示網頁數據
  • 代理方法<UIWebViewDelegate>

    • shouldStartLoadWithRequest: 請求以前判斷是否容許訪問(過濾某些網址)
    • 屬性UIScrollView能夠控制滾動範圍
    • loadHTMLString
    • loadData:
    • 能夠加載網絡資源和本地資源
    • scalesPageToFit 屏幕自適應
    • dataDetectorTypes 自動檢測網頁中出現的電話號碼,網址等,添加下劃線和連接。
// 始發送請求(加載數據)時調用這個方法 - (void)webViewDidStartLoad:(UIWebView *)webView; // 請求完畢(加載數據完畢)時調用這個方法 - (void)webViewDidFinishLoad:(UIWebView *)webView; // 請求錯誤時調用這個方法 - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error; // UIWebView在發送請求以前,都會調用這個方法,若是返回NO,表明中止加載請求,返回YES,表明容許加載請求 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
/* * 每當webView即將發送一個請求以前,都會調用這個方法 * 返回YES:容許加載這個請求 * 返回NO:禁止加載這個請求 */ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{ NSLog(@"%s",__func__); if ([request.URL.absoluteString containsString:@"life"]) { return NO; } return YES; }

JS介紹

HTML5

  • html(內容) + CSS(樣式) + JS(動態效果、事件交互)
  • 經常使用JS函數

    • -alert(10); // 彈框
    • document.getElementById(‘test’); // 根據ID得到某個DOM元素
  • JS和OC通訊
  • oc執行js

    • stringByEvaluatingJavaScriptFromString
    • JS 函數
    • function
  • JS執行OC

    • 經過代理法方法 shouldStartLoadWithRequest
    • 在js函數中調用 loaction.href = 'slq://sendMessage_?參數1&參數2';
    • 傳遞參數的話,在方法後邊寫入一符號(_、@等)標識要傳遞參數,而後參數之間也要加入符號分割

OC執行JS

  • 是用OC執行那個JS腳本
  • stringByEvaluatingJavaScriptFromString
[webView stringByEvaluatingJavaScriptFromString:@"alert(100)"]; // 調用JS中的函數, NSLog(@"%@",[webView stringByEvaluatingJavaScriptFromString:@"login();"]); self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title;"];

JS執行OC

  • 經過代理法方法 shouldStartLoadWithRequest

  • 無參數傳遞

/** * 經過這個方法完成JS調用OC * JS和OC交互的第三方框架:WebViewJavaScriptBridge */ // location.href = 'slq://call'; - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // NSLog(@"%@",request.URL); NSString *url = request.URL.absoluteString; NSString *pre = @"slq://"; if([url hasPrefix:pre]) { // 調用OC方法 // NSLog(@"調用OC方法"); NSString *method = [url substringFromIndex:pre.length]; // NSSelectorFromString 將字符串轉換成方法名 [self performSelector:NSSelectorFromString(method) withObject:nil]; return NO; } // NSLog(@"發送請求"); return YES; }
  • 2個參數

    • 使用'_'代替':','?'區分參數和函數名,'&'區分參數
// location.href = 'slq://call2_number2_?&100'; - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *url = request.URL.absoluteString; NSString *pre = @"slq://"; if([url hasPrefix:pre]) { // 調用OC方法 NSString *method = [url substringFromIndex:pre.length]; // method = call2_number2_?200&300 // 分割字符串 NSArray *arr = [method componentsSeparatedByString:@"?"]; // call2:number2: NSString *methodName = [[arr firstObject] stringByReplacingOccurrencesOfString:@"_" withString:@":"]; // 200&300 NSString *paramStr = [arr lastObject]; NSArray *params = nil; if (arr.count == 2 && [paramStr containsString:@"&"]) { params = [paramStr componentsSeparatedByString:@"&"]; } NSString *param1 = [params firstObject]; NSString *param2 = params.count <= 1 ? nil : [params lastObject]; NSLog(@"%@",methodName); [self performSelector:NSSelectorFromString(methodName) withObject:param1 withObject:param2]; // 兩個參數 // [self performSelector:NSSelectorFromString(methodName) withObject:para];// 一個參數 return NO; } return YES; }
  • 3個參數

    • 若是有3個以上參數,只能使用方法簽名的方式來肯定傳遞參數
- (id)performSelector:(SEL)selector withObjects:(NSArray *)params { // 設置方法簽名 NSMethodSignature *sig = [[self class] instanceMethodSignatureForSelector:selector]; // if (sig == nil) { NSLog(@"方法沒找到"); } // NSInvocation 包裝對象利用一個NSInvocation對象包裝一次方法調用(方法調用者、方法名、方法參數、方法返回值) NSInvocation *invo = [NSInvocation invocationWithMethodSignature:sig]; invo.target = self; invo.selector = selector; // 設置參數 NSInteger paramNum = sig.numberOfArguments - 2; // 包含兩個隱含參數:self and _cmd // 取最小值做爲參數, paramNum = MIN(paramNum, params.count); for (int i = 0 ; i < paramNum; i ++) { id obj = params[i]; if ([obj isKindOfClass:[NSNull class]]) { continue; } [invo setArgument:&obj atIndex:i + 2]; // 從第三個參數開始 } // 設置回調 [invo invoke]; // 返回值 id returnVal = 0; if (sig.methodReturnLength) { [invo getReturnValue:&returnVal]; } return returnVal; }

程序崩潰處理

  • 在appdelegate中判斷
void handleException(NSException *exception) { [[UIApplication sharedApplication].delegate performSelector:@selector(handle)]; } - (void)handle { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"哈哈" message:@"崩潰了把" delegate:self cancelButtonTitle:@"好的" otherButtonTitles:nil, nil]; [alertView show]; // 從新啓動RunLoop [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { NSLog(@"-------點擊了好的"); exit(0); } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 設置捕捉異常的回調 NSSetUncaughtExceptionHandler(handleException); return YES; }

去除Xcode編譯警告

  • 若是對於某些警告須要屏蔽,須要找到這個警告 的代號

// 去除Xcode編譯警告 //#pragma clang diagnostic push // 開始 #pragma clang diagnostic ignored "-Warc-performSelector-leaks" //#pragma clang diagnostic pop // 結束

異常處理

  • 若是方法名錯誤,拋出異常 @throw
  • 捕獲異常 @try @catch @finally
相關文章
相關標籤/搜索