AFN - HTTPS - UIWebView
1.AFN使用技巧
1.在開發的時候能夠建立一個工具類,繼承自咱們的AFN中的請求管理者,再控制器中真正發請求的代碼使用本身封裝的工具類。
2.這樣作的優勢是之後若是修改了底層依賴的框架,那麼咱們修改這個工具類就能夠了,而不用再一個一個的去修改。
3.該工具類通常提供一個單例方法,在該方法中會設置一個基本的請求路徑。
4.該方法一般還會提供對GET或POST請求的封裝。
5.在外面的時候經過該工具類來發送請求
6.單例方法:
+ (instancetype)shareNetworkTools
{
static TCJNetworkTools *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)upload
{
//1.建立一個請求管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//2.發送POST請求上傳數據
/*
第一個參數:請求路徑:NSString類型
第二個參數:要上傳的非文件參數
第三個參數:block回調
在該回調中,須要利用formData拼接即將上傳的二進制數據
第三個參數:上傳成功的block回調
task:dataTask(任務)
responseObject:服務器返回的數據
第四個參數:上傳失敗的block回調
error:錯誤信息,若是上傳文件失敗,那麼error裏面包含了錯誤的描述信息
*/
NSDictionary *dict = @{
@"username":@"123"
};
[manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
//把本地的圖片轉換爲NSData類型的數據
UIImage *image = [UIImage imageNamed:@"123"];
NSData *data = UIImagePNGRepresentation(image);
/*
//拼接二進制文件數據
第一個參數:要上傳的文件的二進制數據
第二個參數:服務器接口規定的名稱
第三個參數:這個參數上傳到服務器以後用什麼名字來進行保存
第四個參數:上傳文件的MIMEType類型
*/
[formData appendPartWithFileData:data name:@"file" fileName:@"xxoo.png" mimeType:@"application/octet-stream"];
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
NSLog(@"請求成功---%@",responseObject);
} failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
NSLog(@"請求失敗--%@",error);
}];
}
-(void)upload2
{
NSLog(@"%s",__func__);
//1.建立一個請求管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//2.發送POST請求上傳數據
/*
第一個參數:請求路徑:NSString類型
第二個參數:要上傳的非文件參數
第三個參數:block回調
在該回調中,須要利用formData拼接即將上傳的二進制數據
第三個參數:上傳成功的block回調
task:dataTask(任務)
responseObject:服務器返回的數據
第四個參數:上傳失敗的block回調
error:錯誤信息,若是上傳文件失敗,那麼error裏面包含了錯誤的描述信息
*/
NSDictionary *dict = @{
@"username":@"123"
};
[manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
//本地文件的url
NSURL *fileUrl = [NSURL fileURLWithPath:@"/Users/changjiang/Desktop/KF[WTI`AQ3T`A@3R(B96D89.gif"];
/*
//拼接二進制文件數據
第一個參數:要上傳文件的url路徑
第二個參數:服務器要求的參數名稱
第三個參數:這個文件上傳到服務器以後叫什麼名稱
第四個參數:文件的mimetype類型
第五個參數:錯誤信息
*/
// [formData appendPartWithFileURL:fileUrl name:@"file" fileName:@"xx.png" mimeType:@"application/octet-stream" error:nil];
//另一種上傳文件的方式
/*
說明:該方法和上面的方法等價,不過該方法更加簡單其內部會自動的的根據url路徑肯定文件保存名稱,並經過內部方法獲取上傳文件的mimetype類型
*/
[formData appendPartWithFileURL:fileUrl name:@"file" error:nil];
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
NSLog(@"請求成功---%@",responseObject);
} failure:^(NSURLSessionDataTask * _Nonnull 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服務器返回的數據內容是什麼類型的 Content-Type*/
manager.responseSerializer.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 reachabilityForLocalWiFi].currentReachabilityStatus != NotReachable)
{
NSLog(@"當前網絡爲WIFI");
}else if ([Reachability reachabilityForInternetConnection].currentReachabilityStatus != NotReachable)
{
NSLog(@"當前網絡爲手機自帶網絡");
}else
{
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.對開發的影響。
3.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);
}
}
3.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的說明
新的需求:點擊按鈕的時候撥打電話
可是我在點擊按鈕的時候,用戶是不知道的,咱們怎麼可以知道用戶點擊了網頁上面的一個按鈕,只能經過一個技巧,那就是本身搞一個特定的協議頭好比說cj://,當我攔截到你的網絡請求的時候,只須要判斷一下當前的協議頭是否是這個就能判斷你如今是不是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
9 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];
}
10 異常處理
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];
//把該信息保存到本地沙盒,下次回傳給服務器。
}