第七天 AFN、webView、https請求

0.AFN框架基本使用

  • 0.1 AFN內部結構
AFN結構體
    - NSURLConnection
        + AFURLConnectionOperation(已經被廢棄)
        + AFHTTPRequestOperation(已經被廢棄)
        + AFHTTPRequestOperationManager(封裝了經常使用的 HTTP 方法)(已經被廢棄)
            * 屬性
                * baseURL :AFN建議開發者針對 AFHTTPRequestOperationManager 自定義個一個單例子類,設置 baseURL, 全部的網絡訪問,都只使用相對路徑便可
                * requestSerializer :請求數據格式/默認是二進制的 HTTP
                * responseSerializer :響應的數據格式/默認是 JSON 格式
                * operationQueue
                * reachabilityManager :網絡鏈接管理器
            * 方法
                * manager :方便建立管理器的類方法
                * HTTPRequestOperationWithRequest :在訪問服務器時,若是要告訴服務器一些附加信息,都須要在 Request 中設置
                * GET
                * POST

    - NSURLSession
        + AFURLSessionManager
        + AFHTTPSessionManager(封裝了經常使用的 HTTP 方法)
            * GET
            * POST
            * UIKit + AFNetworking 分類
            * NSProgress :利用KVO

    - 半自動的序列化&反序列化的功能
        + AFURLRequestSerialization :請求的數據格式/默認是二進制的
        + AFURLResponseSerialization :響應的數據格式/默認是JSON格式
    - 附加功能
        + 安全策略
            * HTTPS
            * AFSecurityPolicy
        + 網絡檢測
            * 對蘋果的網絡鏈接檢測作了一個封裝
            * AFNetworkReachabilityManager

建議:
能夠學習下AFN對 UIKit 作了一些分類, 對本身能力提高是很是有幫助的
  • 0.2 AFN的基本使用

(1)發送POST請求的方式css

-(void)post
{
    //1.建立會話管理者
    //AFHTTPSessionManager內部是基於NSURLSession實現的
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //2.建立參數
    NSDictionary *dict = @{
                           @"username":@"520it",
                           @"pwd":@"520it",
                           };

    //3.發送POST請求
    /*
     http://120.25.226.186:32812/login?username=ee&pwd=ee&type=JSON
     第一個參數:NSString類型的請求路徑,AFN內部會自動將該路徑包裝爲一個url並建立請求對象
     第二個參數:請求參數,以字典的方式傳遞,AFN內部會判斷當前是POST請求仍是GET請求,以選擇直接拼接仍是轉換爲NSData放到請求體中傳遞
     第三個參數:進度回調 此處爲nil
     第四個參數:請求成功以後回調Block
     第五個參數:請求失敗回調Block
     */
    [manager POST:@"http://120.25.226.186:32812/login" parameters:dict progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

        //注意:responseObject:請求成功返回的響應結果(AFN內部已經把響應體轉換爲OC對象,一般是字典或數組)
        NSLog(@"請求成功---%@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"請求失敗---%@",error);
    }];
}

(2)使用AFN下載文件html

-(void)download
{
    //1.建立會話管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];


    //2.建立請求對象
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_13.png"]];

    //3.建立下載Task
    /*
     第一個參數:請求對象
     第二個參數:進度回調
        downloadProgress.completedUnitCount :已經下載的數據
        downloadProgress.totalUnitCount:數據的總大小
     第三個參數:destination回調,該block須要返回值(NSURL類型),告訴系統應該把文件剪切到什麼地方
        targetPath:文件的臨時保存路徑
        response:響應頭信息
     第四個參數:completionHandler請求完成後回調
        response:響應頭信息
        filePath:文件的保存路徑,即destination回調的返回值
        error:錯誤信息
     */
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        NSLog(@"%f",1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount);

    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {

        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
        NSLog(@"%@\n%@",targetPath,fullPath);
        return [NSURL fileURLWithPath:fullPath];

    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        NSLog(@"%@",filePath);
    }];

    //4.執行Task
    [downloadTask resume];
}

1.AFN使用技巧

1.在開發的時候能夠建立一個工具類,繼承自咱們的AFN中的請求管理者,再控制器中真正發請求的代碼使用本身封裝的工具類。
2.這樣作的優勢是之後若是修改了底層依賴的框架,那麼咱們修改這個工具類就能夠了,而不用再一個一個的去修改。
3.該工具類通常提供一個單例方法,在該方法中會設置一個基本的請求路徑。
4.該方法一般還會提供對GET或POST請求的封裝。
5.在外面的時候經過該工具類來發送請求
6.單例方法:
+ (instancetype)shareNetworkTools
{
    static XMGNetworkTools *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 注意: BaseURL中必定要以/結尾
        instance = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"http://120.25.226.186:32812/"]];
    });
    return instance;
}

2.AFN文件上傳

1.文件上傳拼接數據的第一種方式
[formData appendPartWithFileData:data name:@"file" fileName:@"xxoo.png" mimeType:@"application/octet-stream"];
2.文件上傳拼接數據的第二種方式
 [formData appendPartWithFileURL:fileUrl name:@"file" fileName:@"xx.png" mimeType:@"application/octet-stream" error:nil];
3.文件上傳拼接數據的第三種方式
 [formData appendPartWithFileURL:fileUrl name:@"file" error:nil];
4.【注】在資料中已經提供了一個用於文件上傳的分類。

/*文件上傳相關的代碼以下*/
-(void)upload1
{
    //1.建立會話管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //2.處理參數(非文件參數)
    NSDictionary *dict = @{
                           @"username":@"123"
                           };

    //3.發送請求上傳文件
    /*
     第一個參數:請求路徑(NSString類型)
     第二個參數:非文件參數,以字典的方式傳遞
     第三個參數:constructingBodyWithBlock 在該回調中拼接文件參數
     第四個參數:progress 進度回調
        uploadProgress.completedUnitCount:已經上傳的數據大小
        uploadProgress.totalUnitCount:數據的總大小
     第五個參數:success 請求成功的回調
        task:上傳Task
        responseObject:服務器返回的響應體信息(已經以JSON的方式轉換爲OC對象)
     第六個參數:failure 請求失敗的回調
        task:上傳Task
        error:錯誤信息
     */
    [manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

        UIImage *image = [UIImage imageNamed:@"Snip20160117_1"];
        NSData *imageData = UIImagePNGRepresentation(image);

        //在該block中拼接要上傳的文件參數
        /*
         第一個參數:要上傳的文件二進制數據
         第二個參數:文件參數對應的參數名稱,此處爲file是該臺服務器規定的(一般會在接口文檔中提供)
         第三個參數:該文件上傳到服務後以什麼名稱保存
         第四個參數:該文件的MIMeType類型
         */
        [formData appendPartWithFileData:imageData name:@"file" fileName:@"123.png" mimeType:@"image/png"];

    } progress:^(NSProgress * _Nonnull uploadProgress) {
        NSLog(@"%f",1.0 * uploadProgress.completedUnitCount / uploadProgress.totalUnitCount);
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

        NSLog(@"請求成功----%@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

        NSLog(@"請求失敗----%@",error);
    }];
}

-(void)upload2
{
    //1.建立會話管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //2.處理參數(非文件參數)
    NSDictionary *dict = @{
                           @"username":@"123"
                           };

    //3.發送請求上傳文件
    /*
     第一個參數:請求路徑(NSString類型)
     第二個參數:非文件參數,以字典的方式傳遞
     第三個參數:constructingBodyWithBlock 在該回調中拼接文件參數
     第四個參數:progress 進度回調
        uploadProgress.completedUnitCount:已經上傳的數據大小
        uploadProgress.totalUnitCount:數據的總大小
     第五個參數:success 請求成功的回調
        task:上傳Task
        responseObject:服務器返回的響應體信息(已經以JSON的方式轉換爲OC對象)
     第六個參數:failure 請求失敗的回調
        task:上傳Task
        error:錯誤信息
     */
    [manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

        NSURL *fileUrl = [NSURL fileURLWithPath:@"/Users/文頂頂/Desktop/Snip20160117_1.png"];


        //在該block中拼接要上傳的文件參數
        //第一種拼接方法
        /*
         第一個參數:要上傳的文件的URL路徑
         第二個參數:文件參數對應的參數名稱,此處爲file是該臺服務器規定的(一般會在接口文檔中提供)
         第三個參數:該文件上傳到服務後以什麼名稱保存
         第四個參數:該文件的MIMeType類型
         第五個參數:錯誤信息,傳地址
         */
        //[formData appendPartWithFileURL:fileUrl name:@"file" fileName:@"1234.png" mimeType:@"image/png" error:nil];


        //第二種拼接方法:簡寫方法
        /*
         第一個參數:要上傳的文件的URL路徑
         第二個參數:文件參數對應的參數名稱,此處爲file
         第三個參數:錯誤信息
         說明:AFN內部自動得到路徑URL地址的最後一個節點做爲文件的名稱,內部調用C語言的API得到文件的類型
         */
        [formData appendPartWithFileURL:fileUrl name:@"file" error:nil];

    } progress:^(NSProgress * _Nonnull uploadProgress) {
        NSLog(@"%f",1.0 * uploadProgress.completedUnitCount / uploadProgress.totalUnitCount);
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

        NSLog(@"請求成功----%@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

        NSLog(@"請求失敗----%@",error);
    }];
}

3.使用AFN進行序列化處理

/*
1.AFN它內部默認把服務器響應的數據當作json來進行解析,因此若是服務器返回給個人不是JSON數據那麼請求報錯,這個時候須要設置AFN對響應信息的解析方式。AFN提供了三種解析響應信息的方式,分別是:
1)AFXMLParserResponseSerializer----XML
2) AFHTTPResponseSerializer---------默認二進制響應數據
3)AFJSONResponseSerializer---------JSON

2.還有一種狀況就是服務器返回給咱們的數據格式不太一致(開發者工具Content-Type:text/xml),那麼這種狀況也有可能請求不成功。解決方法:
1) 直接在源代碼中修改,添加相應的Content-Type
2) 拿到這個屬性,添加到它的集合中

3.相關代碼
-(void)srializer
{
    //1.建立請求管理者,內部基於NSURLSession
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    /* 知識點1:設置AFN採用什麼樣的方式來解析服務器返回的數據*/

    //若是返回的是XML,那麼告訴AFN,響應的時候使用XML的方式解析
    manager.responseSerializer = [AFXMLParserResponseSerializer serializer];

    //若是返回的就是二進制數據,那麼採用默認二進制的方式來解析數據
    //manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    //採用JSON的方式來解析數據
    //manager.responseSerializer = [AFJSONResponseSerializer serializer];


    /*知識點2 告訴AFN,再序列化服務器返回的數據的時候,支持此種類型
    [AFJSONResponseSerializer serializer].acceptableContentTypes = [NSSet setWithObject:@"text/xml"];

    //2.把全部的請求參數經過字典的方式來裝載,GET方法內部會自動把全部的鍵值對取出以&符號拼接並最後用?符號鏈接在請求路徑後面
    NSDictionary *dict = @{
                           @"username":@"223",
                           @"pwd":@"ewr",
                           @"type":@"XML"
                           };

    //3.發送GET請求
    [manager GET:@"http://120.25.226.186:32812/login" parameters:dict success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {

        //4.請求成功的回調block
        NSLog(@"%@",[responseObject class]);
    } failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {

        //5.請求失敗的回調,能夠打印error的值查看錯誤信息
        NSLog(@"%@",error);
    }];
}

4.使用AFN來檢測網絡狀態

/*
說明:可使用AFN框架中的AFNetworkReachabilityManager來監聽網絡狀態的改變,也能夠利用蘋果提供的Reachability來監聽。建議在開發中直接使用AFN框架處理。
 */
//使用AFN框架來檢測網絡狀態的改變
-(void)AFNReachability
{
    //1.建立網絡監聽管理者
    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];

    //2.監聽網絡狀態的改變
    /*
     AFNetworkReachabilityStatusUnknown          = 未知
     AFNetworkReachabilityStatusNotReachable     = 沒有網絡
     AFNetworkReachabilityStatusReachableViaWWAN = 3G
     AFNetworkReachabilityStatusReachableViaWiFi = WIFI
     */
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusUnknown:
                NSLog(@"未知");
                break;
            case AFNetworkReachabilityStatusNotReachable:
                NSLog(@"沒有網絡");
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                NSLog(@"3G");
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                NSLog(@"WIFI");
                break;

            default:
                break;
        }
    }];

    //3.開始監聽
    [manager startMonitoring];
}

------------------------------------------------------------
//使用蘋果提供的Reachability來檢測網絡狀態,若是要持續監聽網絡狀態的概念,須要結合通知一塊兒使用。
//提供下載地址:https://developer.apple.com/library/ios/samplecode/Reachability/Reachability.zip

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //1.註冊一個通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkChange) name:kReachabilityChangedNotification object:nil];

    //2.拿到一個對象,而後調用開始監聽方法
    Reachability *r = [Reachability reachabilityForInternetConnection];
    [r startNotifier];

    //持有該對象,不要讓該對象釋放掉
    self.r = r;
}

//當控制器釋放的時候,移除通知的監聽
-(void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

-(void)networkChange
{
    //獲取當前網絡的狀態
   if ([Reachability reachabilityForInternetConnection].currentReachabilityStatus == ReachableViaWWAN)
    {
        NSLog(@"當前網絡狀態爲3G");
        return;
    }

    if ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == ReachableViaWiFi)
    {
        NSLog(@"當前網絡狀態爲wifi");
        return;
    }

    NSLog(@"當前沒有網絡");
}

5.數據安全

01 攻城利器:Charles(公司中通常都使用該工具來抓包,並作網絡測試)
注意:Charles在使用中的亂碼問題,能夠顯示包內容,而後打開info.plist文件,找到java目錄下面的VMOptions,在後面添加一項:-Dfile.encoding=UTF-8
02 MD5消息摘要算法是不可逆的。
03 數據加密的方式和規範通常公司會有具體的規定,沒必要多花時間。

6.HTTPS的基本使用

1.https簡單說明
    HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。
    即HTTP下加入SSL層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL。 它是一個URI scheme(抽象標識符體系),句法類同http:體系。用於安全的HTTP數據傳輸。
    https:URL代表它使用了HTTP,但HTTPS存在不一樣於HTTP的默認端口及一個加密/身份驗證層(在HTTP與TCP之間)。

2.HTTPS和HTTP的區別主要爲如下四點:
        1、https協議須要到ca申請證書,通常免費證書不多,須要交費。
        2、http是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的ssl加密傳輸協議。
        3、http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。
        4、http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

3.簡單說明
1)HTTPS的主要思想是在不安全的網絡上建立一安全信道,並可在使用適當的加密包和服務器證書可被驗證且可被信任時,對竊聽和中間人攻擊提供合理的保護。
2)HTTPS的信任繼承基於預先安裝在瀏覽器中的證書頒發機構(如VeriSign、Microsoft等)(意即「我信任證書頒發機構告訴我應該信任的」)。
3)所以,一個到某網站的HTTPS鏈接可被信任,若是服務器搭建本身的https 也就是說採用自認證的方式來創建https信道,這樣通常在客戶端是不被信任的。
4)因此咱們通常在瀏覽器訪問一些https站點的時候會有一個提示,問你是否繼續。

4.對開發的影響。
4.1 若是是本身使用NSURLSession來封裝網絡請求,涉及代碼以下。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    NSURLSessionDataTask *task =  [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }];
    [task resume];
}

/*
 只要請求的地址是HTTPS的, 就會調用這個代理方法
 咱們須要在該方法中告訴系統, 是否信任服務器返回的證書
 Challenge: 挑戰 質問 (包含了受保護的區域)
 protectionSpace : 受保護區域
 NSURLAuthenticationMethodServerTrust : 證書的類型是 服務器信任
 */
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
    //    NSLog(@"didReceiveChallenge %@", challenge.protectionSpace);
    NSLog(@"調用了最外層");
    // 1.判斷服務器返回的證書類型, 是不是服務器信任
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSLog(@"調用了裏面這一層是服務器信任的證書");
        /*
         NSURLSessionAuthChallengeUseCredential = 0,                     使用證書
         NSURLSessionAuthChallengePerformDefaultHandling = 1,            忽略證書(默認的處理方式)
         NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2,     忽略書證, 並取消此次請求
         NSURLSessionAuthChallengeRejectProtectionSpace = 3,            拒絕當前這一次, 下一次再詢問
         */
//        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];

        NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential , card);
    }
}

4.2 若是是使用AFN框架,那麼咱們不須要作任何額外的操做,AFN內部已經作了處理。

7 WebView的基本使用

1 概念性知識
    01 webView是有缺點的,會致使內存泄露,並且這個問題是它系統自己的問題。
    02 手機上面的safai其實就是用webView來實現的
    03 如今的開發並不徹底是原生的開發,而更加傾向於原生+Html5的方式
    04 webView是OC代碼和html代碼之間進行交互的橋樑

2 代碼相關
/*A*網頁操控相關方法**/
    [self.webView goBack];      回退
    [self.webView goForward];   前進
    [self.webView reload];      刷新

    //設置是否可以前進和回退
    self.goBackBtn.enabled = webView.canGoBack;
    self.fowardBtn.enabled = webView.canGoForward;

/*B*經常使用的屬性設置**/
    self.webView.scalesPageToFit = YES; 設置網頁自動適應
    self.webView.dataDetectorTypes = UIDataDetectorTypeAll; 設置檢測網頁中的格式類型,all表示檢測全部類型包括超連接、電話號碼、地址等。
    self.webView.scrollView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0);

/*C*相關代理方法**/
    //每當將加載請求的時候調用該方法,返回YES 表示加載該請求,返回NO 表示不加載該請求
    //能夠在該方法中攔截請求
    -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    {
        return ![request.URL.absoluteString containsString:@"dushu"];
    }

    //開始加載網頁,不只監聽咱們指定的請求,還會監聽內部發送的請求
    -(void)webViewDidStartLoad:(UIWebView *)webView

    //網頁加載完畢以後會調用該方法
    -(void)webViewDidFinishLoad:(UIWebView *)webView

    //網頁加載失敗調用該方法
    -(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error

/*D*其它知識點-加載本地資源**/
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"text.html" withExtension:nil];
    [self.webView loadRequest:[NSURLRequest requestWithURL:url]];

8 HTML

1.Html決定網頁的內容,css決定網頁的樣式,js決定網頁的事件
2.html學習網站:http://www.w3school.com.cn

9 OC和JS代碼的互調

01 OC調用JS的代碼
    NSString *str = [self.webView stringByEvaluatingJavaScriptFromString:@"sum()"];

02 JS怎麼調用OC的說明
    新的需求:點擊按鈕的時候撥打電話
    可是我在點擊按鈕的時候,用戶是不知道的,咱們怎麼可以知道用戶點擊了網頁上面的一個按鈕,只能經過一個技巧,那就是本身搞一個特定的協議頭好比說xmg://,當我攔截到你的網絡請求的時候,只須要判斷一下當前的協議頭是否是這個就能判斷你如今是不是JS調用。
    OC裏面有經過字符串生成SEL類型的方法,因此當拿到數據以後作下面的事情
    1)截取方法的名稱
    2)將截取出來的字符串轉換爲SEL
    3)利用performSelect方法來調用SEL

03 涉及到的相關方法
    [@"abc" hasPrefix:@"A"] //判斷字符串是否以一個固定的字符開頭,這裏爲A
    //截串操做
    - (NSString *)substringFromIndex:(NSUInteger)from;
    //切割字符串,返回一個數組
    - (NSArray<NSString *> *)componentsSeparatedByString:(NSString *)separator;
    //替換操做
    - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement
    //把string包裝成SEL

    SEL selector = NSSelectorFromString(sel);

04 如何屏蔽警告
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            //-Warc-performSelector-leaks爲惟一的警告標識
            [self performSelector:selector withObject:nil];
    #pragma clang diagnostic pop

10 NSInvocation的基本使用

//封裝invacation能夠調用多個參數的方法
-(void)invacation
{
    //1.建立一個MethodSignature,簽名中保存了方法的名稱,參數和返回值
    //這個方法屬於誰,那麼就用誰來進行建立
    //注意:簽名通常是用來設置參數和得到返回值的,和方法的調用沒有太大的關係
    NSMethodSignature *signature = [ViewController instanceMethodSignatureForSelector:@selector(callWithNumber:andContext:withStatus:)];

    /*注意不要寫錯了方法名稱
     //    NSMethodSignature *signature = [ViewController methodSignatureForSelector:@selector(call)];
     */

    //2.經過MethodSignature來建立一個NSInvocation
    //NSInvocation中保存了方法所屬於的對象|方法名稱|參數|返回值等等
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];

    /*2.1 設置invocation,來調用方法*/

    invocation.target = self;
    //    invocation.selector = @selector(call);
    //    invocation.selector = @selector(callWithNumber:);
    //    invocation.selector = @selector(callWithNumber:andContext:);
    invocation.selector = @selector(callWithNumber:andContext:withStatus:);

    NSString *number = @"10086";
    NSString *context = @"下課了";
    NSString *status = @"睡覺的時候";

    //注意:
    //1.自定義的參數索引從2開始,0和1已經被self and _cmd佔用了
    //2.方法簽名中保存的方法名稱必須和調用的名稱一致
    [invocation setArgument:&number atIndex:2];
    [invocation setArgument:&context atIndex:3];
    [invocation setArgument:&status atIndex:4];

    /*3.調用invok方法來執行*/
    [invocation invoke];
}

11 異常處理

01 通常處理方式:
    a.app異常閃退,那麼捕獲crash信息,並記錄在本地沙盒中。
    b.當下次用戶從新打開app的時候,檢查沙盒中是否保存有上次捕獲到的crash信息。
    c.若是有那麼利用專門的接口發送給服務器,以求在後期版本中修復。

02 如何拋出異常

    //拋出異常的兩種方式
        // @throw  [NSException exceptionWithName:@"好大一個bug" reason:@"異常緣由:我也不知道" userInfo:nil];

        //方式二
        NSString *info = [NSString stringWithFormat:@"%@方法找不到",NSStringFromSelector(aSelector)];
        //下面這種方法是自動拋出的
        [NSException raise:@"這是一個異常" format:info,nil];

03 如何捕獲異常
    NSSetUncaughtExceptionHandler (&UncaughtExceptionHandler);

    void UncaughtExceptionHandler(NSException *exception) {
    NSArray *arr = [exception callStackSymbols];//獲得當前調用棧信息
    NSString *reason = [exception reason];//很是重要,就是崩潰的緣由
    NSString *name = [exception name];//異常類型

    NSString *errorMsg = [NSString stringWithFormat:@"當前調用棧的信息:%@\nCrash的緣由:%@\n異常類型:%@\n",arr,reason,name];
    //把該信息保存到本地沙盒,下次回傳給服務器。
}

補充

關於JS相關的學習框架:WebViewJavascriptBridge

12.Cocoapods的安裝

1.先升級Gem
    sudo gem update --system
2.切換cocoapods的數據源
    【先刪除,再添加,查看】
    gem sources --remove https://rubygems.org/
    gem sources -a https://ruby.taobao.org/
    gem sources -l
3.安裝cocoapods
    sudo gem install cocoapods
    或者(如10.11系統)sudo gem install -n /usr/local/bin cocoapods
4.將Podspec文件託管地址從github切換到國內的oschina
    【先刪除,再添加,再更新】
    pod repo remove master
    pod repo add master http://git.oschina.net/akuandev/Specs.git
    pod repo add master https://gitcafe.com/akuandev/Specs.git
    pod repo update
5.設置pod倉庫
    pod setup
6.測試
    【若是有版本號,則說明已經安裝成功】
    pod --version
7.利用cocoapods來安裝第三方框架
    01 進入要安裝框架的項目的.xcodeproj同級文件夾
    02 在該文件夾中新建一個文件podfile
    03 在文件中告訴cocoapods須要安裝的框架信息
        a.該框架支持的平臺
        b.適用的iOS版本
        c.框架的名稱
        d.框架的版本
8.安裝
pod install --no-repo-update
pod update --no-repo-update

9.說明
platform :ios, '8.0' 用來設置全部第三方庫所支持的iOS最低版本
pod 'SDWebImage','~>2.6' 設置框架的名稱和版本號
版本號的規則:
'>1.0'    能夠安裝任何高於1.0的版本
'>=1.0'   能夠安裝任何高於或等於1.0的版本
'<1.0'    任何低於1.0的版本
'<=1.0'   任何低於或等於1.0的版本
'~>0.1'   任何高於或等於0.1的版本,可是不包含高於1.0的版本
'~>0'     任何版本,至關於不指定版本,默認採用最新版本號

10.使用pod install命令安裝框架後的大體過程:
01 分析依賴:該步驟會分析Podfile,查看不一樣類庫之間的依賴狀況。若是有多個類庫依賴於同一個類庫,可是依賴於不一樣的版本,那麼cocoaPods會自動設置一個兼容的版本。
02 下載依賴:根據分析依賴的結果,下載指定版本的類庫到本地項目中。
03 生成Pods項目:建立一個Pods項目專門用來編譯和管理第三方框架,CocoaPods會將所需的框架,庫等內容添加到項目中,而且進行相應的配置。
04 整合Pods項目:將Pods和項目整合到一個工做空間中,而且設置文件連接。

13.Base64補充

1.Base64簡單說明
    描述:Base64能夠成爲密碼學的基石,很是重要。
    特色:能夠將任意的二進制數據進行Base64編碼
    結果:全部的數據都能被編碼爲並只用65個字符就能表示的文本文件。
    65字符:A~Z a~z 0~9 + / =
    對文件進行base64編碼後文件數據的變化:編碼後的數據~=編碼前數據的4/3,會大1/3左右。

2.命令行進行Base64編碼和解碼
    編碼:base64 123.png -o 123.txt
    解碼:base64 123.txt -o test.png -D

2.Base64編碼原理
    1)將全部字符轉化爲ASCII碼;
    2)將ASCII碼轉化爲8位二進制;
    3)將二進制3個歸成一組(不足3個在後邊補0)共24位,再拆分紅4組,每組6位;
    4)統一在6位二進制前補兩個0湊足8位;
    5)將補0後的二進制轉爲十進制;
    6)從Base64編碼表獲取十進制對應的Base64編碼;

處理過程說明:
    a.轉換的時候,將三個byte的數據,前後放入一個24bit的緩衝區中,先來的byte佔高位。
    b.數據不足3byte的話,於緩衝區中剩下的bit用0補足。而後,每次取出6個bit,按照其值選擇查表選擇對應的字符做爲編碼後的輸出。
    c.不斷進行,直到所有輸入數據轉換完成。
    d.若是最後剩下兩個輸入數據,在編碼結果後加1個「=」;
    e.若是最後剩下一個輸入數據,編碼結果後加2個「=」;
    f.若是沒有剩下任何數據,就什麼都不要加,這樣才能夠保證資料還原的正確性。

3.實現
    a.說明:
        1)從iOS7.0 開始,蘋果就提供了base64的編碼和解碼支持
        2)若是是老項目,則還能看到base64編碼和解碼的第三方框架,若是當前再也不支持iOS7.0如下版本,則建議替換。

    b.相關代碼:
    //給定一個字符串,對該字符串進行Base64編碼,而後返回編碼後的結果
    -(NSString *)base64EncodeString:(NSString *)string
    {
        //1.先把字符串轉換爲二進制數據
        NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];

        //2.對二進制數據進行base64編碼,返回編碼後的字符串
        return [data base64EncodedStringWithOptions:0];
    }

    //對base64編碼後的字符串進行解碼
    -(NSString *)base64DecodeString:(NSString *)string
    {
        //1.將base64編碼後的字符串『解碼』爲二進制數據
        NSData *data = [[NSData alloc]initWithBase64EncodedString:string options:0];

        //2.把二進制數據轉換爲字符串返回
        return [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
    }

    c.終端測試命令
        $ echo -n A | base64
        $ echo -n QQ== |base64 -D

14.加密相關

網絡應用程序數據的原則:

1. 在網絡上"不容許"傳輸用戶隱私數據的"明文"
2. 在本地"不容許"保存用戶隱私數據的"明文"

加密相關

1. base64 編碼格式
2. 密碼學演化 "祕密本"-->RSA

RSA簡單說明:加密算法算法是公開的,加密方式以下:

- "公鑰"加密,"私鑰"解密
- "私鑰"加密,"公鑰"解密

目前流行的加密方式:
---------------
- 哈希(散列)函數
    - MD5
    - SHA1
    - SHA256

- 對稱加密算法
    - DES
    - 3DES
    - AES(高級密碼標準,美國國家安全局使用的)

- 非對稱加密算法(RSA)

散列函數:
---------------
特色:
    - 算法是公開的
    - "對相同的數據加密,獲得的結果是同樣的"
    - 對不一樣的數據加密,獲得的結果是定長的,MD5對不一樣的數據進行加密,獲得的結果都是 32 個字符長度的字符串
    - 信息摘要,信息"指紋",是用來作數據識別的!
    - 不能反算的

用途:
    - 密碼,服務器並不須要知道用戶真實的密碼!
    - 搜索
        張老師 楊老師 蒼老師
        蒼老師 張老師 楊老師

        張老師            1bdf605991920db11cbdf8508204c4eb
        楊老師             2d97fbce49977313c2aae15ea77fec0f
        蒼老師             692e92669c0ca340eff4fdcef32896ee

        如何判斷:對搜索的每一個關鍵字進行三列,獲得三個相對應的結果,按位相加結果若是是同樣的,那搜索的內容就是同樣的!
    - 版權
        版權保護,文件的識別。

破解:
    - http://www.cmd5.com 記錄超過24萬億條,共佔用160T硬盤 的密碼數據,經過對海量數據的搜索獲得的結果!

提高MD5加密安全性,有兩個解決辦法
1. 加"鹽"(佐料)
2. HMAC:給定一個"祕鑰",對明文進行加密,而且作"兩次散列"!-> 獲得的結果,仍是 32 個字符
相關文章
相關標籤/搜索