Xcode的插件安裝路徑:
/Users/用戶名/Library/Application Support/Developer/Shared/Xcode/Plug-ins
訪問網絡的基本流程:5點
構造NSURL實例(地址)--》生成 NSURLRequest請求 --》
通過 NSURLConnection發(fā)送請求--》通過 NSURLResponse實例和NSError返回結果 --》 接受返回數據
HTTP協議
1.面試題: 聊一下HTTP協議(協議的完整的通信過程)
*HTTP協議的全稱:超文本傳輸協議羔巢,定制傳輸數據的規(guī)范(客戶端和服務器之間的數據傳輸規(guī)范)
*描述HTTP協議完整的通信過程
2.通信過程
1> 請求
* 客戶端 --> 服務器
* 請求的內容
a. "請求行":(請求方法\請求資源路徑\HTTP協議版本)
b. "請求頭":(描述客戶端的信息,如手機的系統(tǒng)版本、語言等)
c. "請求體":(POST請求才需要有, 存放具體數據,如用戶名賬號、密碼等)
2> 響應
* 服務器 --> 客戶端
* 響應的內容
a. "狀態(tài)行"(HTTP協議版本\狀態(tài)碼\狀態(tài)信息\"響應行")
*HTTP/1.1 200 OK
b. "響應頭"(服務器信息, 返回數據的類型, 返回數據的長度)
Server: Apache-Coyote/1.1
Content-Type: application/jsion;charset=UTF-8
Content-Lenngth: 248
c. "實體內容"( 返回給客戶端的具體內容,"響應體")
*比如服務器返回的JSON對象
*比如服務器返回的文件數據
--------------請求的方法-----get 和 post ----------------
3.HTTP請求的方法
1> GET
* 參數都拼接在URL后面
* 參數有限制
2> POST
* 參數都在請求體
* 參數沒有限制
* 文件上傳自能用POST
// -------------請求的手段------asyn 和 sync----------------
4.iOS中發(fā)送GET\POST請求的"手段3種"
1胳螟、> NSURLConnection(蘋果原生態(tài))号阿,使用起來比ASI\AFN復雜
2艇纺、> ASI (基于CFNetwork),提供了非常強大的功能完疫,使用簡單
3、> AFN (基于NSURLConnection),提供了常用功能债蓝,使用簡單
"建議:"
- 為了提高開發(fā)效率和減少調試時間壳鹤,盡量使用著名的第三方框架
- 因此使用HTTP請求,更建議使用ASI或AFN
1>" NSURLConnection"
// 1.發(fā)送一個同步請求
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error;
// 2.發(fā)送一個異步請求(block)
+ (void)sendAsynchronousRequest:(NSURLRequest*) request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse* response, NSData* data, NSError* connectionError)) handler;
// 3.代理的方法(異步需要實現該方法)
[NSURLConnection connectionWithRequest:request delegate:self];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[conn start];
2>文件下載(大文件下載)
1*"實現方案":邊下載邊寫入(寫入沙河里)
2*"具體實現步驟":
a.在接收到服務器的"響應時"
*.創(chuàng)建一個空的文件到沙盒中--NSFileManager
*.創(chuàng)建寫數據的文件句柄對象--NSFileHandle
b.在接收到服務器的"數據時"
// 利用句柄對象將服務器返回的數據寫到文件的末尾
// 移動文件的尾部
[self.writeHandle seekToEndOfFile];
// 從當前移動的位置(文件尾部)開始寫入數據
[self.writeHandle writeData:data];
c.在接收完畢服務器返回的數據時
// 關閉句柄
[self.writeHandle closeFile];
self.writeHandle = nil;
3*"斷點下載"
1> 關鍵技術點
*設置"請求頭Range"饰迹,告訴服務器下載哪一段數據(開始芳誓、結束)余舶,其它的和文件下載沒區(qū)別
4*文件上傳
1>明確
*只能用POST請求
*請求參數都在請求體(文件參數、非文件參數類型的普通參數)
2>實現步驟
a.拼接請求體(文件參數锹淌、非文件參數類型的普通參數)
*文件參數
//參數的開始標記(分隔線)
--heima\r\n
//參數描述(參數名匿值。。葛圃。)
Content-Disposition: form-data; name="參數名"; filename="文件名"\r\n
//文件類型
Content-Type: 文件的類型MIMEType\r\n
// 文件的二進制數據(參數值)
\r\n
// 文件的二進制數據
\r\n
*非文件參數(普通參數)
//參數的開始標記(分隔線)
--heima\r\n
//參數描述(參數名千扔。。库正。)
Content-Disposition: form-data; name="參數名"\r\n
// 參數值
\r\n
//參數值
\r\n
// * 所有參數結束的標記(分隔線)
--heima--\r\n
b.設置請求頭
*請求體的長度
Content-Lenngth : 請求體的長度
*請求數據的類型
Content-Type:
// 普通POSTQQ:application/x-www-from-urlencoded
// 上傳文件的POST請求:multipart/form-data; boundary=--heima
3> "文件上傳"
二曲楚、> ASI
1、緩存
1> 緩存單個請求
// 1褥符、 獲得全局的緩存對象(決定著緩存存儲路徑)
ASIDownloadCache *cache = [ASIDownloadCache sharedCache];
// 設置系統(tǒng)默認的緩存加載策略
cache.defaultCachePolicy = ASIOnlyLoadIfNotCachedCachePolicy;
// 2龙誊、設置請求對象的緩存對象(使用哪個緩存對象)
request.downloadCache = cache;
// 3、設置請求對象的緩存---加載策略
request.cachePolicy = ASIOnlyLoadIfNotCachedCachePolicy;
// 4喷楣、設置請求對象的緩存---存儲策略(存儲的時長)
request.cacheStoragePolicy = ASICachePermanentlyCacheStoragePolicy; //Permanently(永久的)
但是默認是ASICacheForSessionDurationCacheStoragePolicy
------------------------------------------------
// ----注意:緩存加載策略的優(yōu)先級:request.cachePolicy > cache.defaultCachePolicy
2> 緩存所有請求
1.獲得全局的緩存對象(決定緩存的存儲路徑趟大,存儲到什么位置)
ASIDownloadCache *cache = [ASIDownloadCache sharedCache];
// 設置默認的緩存加載策略(默認的緩存加載策略 : 不讀取緩存)
cache.defaultCachePolicy = ASIOnlyLoadIfNotCachedCachePolicy;
// 2、設置全局緩存對象
[ASIHTTPRequest setDefaultCache:cache];
// 判斷數據是否從緩存讀认澈浮: BOOL useCache[request didUseCachedResponse];
// 或者設置7天逊朽,但這個要用ASI框架: [request setSecondsToCache:60 * 60 * 24 * 7];
三. > "NSURLCache"
緩存的使用步驟
// 獲得全局(默認是全局)的緩存對象
NSURLCache *cache = [NSURLCache sharedURLCache];
//設置緩存容量
cache.memoryCapacity = 4 * 1024 * 1024;
cache.diskCapacity = 20 * 1024 * 1024;
//設置緩存策略(有緩存就用緩存,沒有緩存就重新請求)
request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
"使用框架---發(fā)送請求":
1> "同步請求"
[request startSynchronous];
2> "異步請求"
[request startAsynchronous];
3> "GET\POST"
1.GET請求
// ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
2.POST請求
// ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
// 添加普通參數(非文件參數)
[request setPostValue:@"zhangsan" forKey:@"username"];
[request setPostValue:@"124" forKey:@"pwd"];
4> "文件下載"
// 文件的存儲路徑(文件下載到什么地方)
request.downloadDestinationPath = filepath;
// 3.設置下載代理--進度
request.downloadProgressDelegate = self.circleView; //圓形條
// request.downloadProgressDelegate = self.progressView;// 進度條
// 4.支持斷點下載
request.allowResumeForFileDownloads = YES;
5> "文件上傳"
// 添加文件參數(file:需要上傳文件的路徑)
[request setFile:file forKey:@"file"];
[request setFile:file withFileName:@"123.txt" andContentType:@"text/plain" forKey:@"file"];
[request setData:data withFileName:@"minion.png" andContentType:@"image/png" forKey:@"file"]; // (二進制曲伊,直接上傳到服務器叽讳,適用于相機)
// 設置上傳代理(監(jiān)聽上傳進度)
request.uploadProgressDelegate = self.circleView;
6>------------------------ "監(jiān)聽請求的過程" --3種方式(代理、SEL坟募、block)
1> 代理方法(1)
// 設置代理
request.delegate = self;
// 遵守協議
ASIHTTPRequestDelegate
// 實現代理的方法
- (void)requestStarted:(ASIHTTPRequest *)request;
- (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data;
- (void)requestFinished:(ASIHTTPRequest *)request;
- (void)requestFailed:(ASIHTTPRequest *)request;
2> SEL(方法2,---該方式較少用)
// 設置代理
request.delegate = self;
[request setDidStartSelector(start)]; // 開始發(fā)送請求岛蚤,就會調用代理的start的方法
// 實現方法
- (void)start
{
// ....
}
3> block(方法3)
[request setStartedBlock:^{
NSLog(@"setStartedBlock");
}];
[request setDataReceivedBlock:^{
NSLog(@"setDataReceivedBlock");
}];
[request setCompletionBlock:^{
NSLog(@"setCompletionBloc");
}];
[request setFailedBlock:^{
NSLog(@"setFailedBlock---");
}];
7> 通過request對象獲得服務器返回的數據(響應)
1> 獲得響應頭信息
@property (atomic, retain) NSDictionary *responseHeaders;
2> 獲得響應體(實體內容)
- (NSData *)responseData; // 直接返回服務器的二進制數據
- (NSString *)responseString; // 將二進制的數據轉成字符串(方便調試)
二、"框架AFN --- "
1懈糯、GET\POST
1."GET請求"
// 1.獲得請求管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
// 2.封裝請求參數
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
// 3.發(fā)送GET請求
mgr GET:@"http://192.168.1.200:8080/MJServer/login" parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) { // responseObject : 在這種情況下是字典
NSLog(@"請求成功---%@", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"請求失敗---%@", error);
}];
------------------
2."POST請求"
// 1.獲得請求管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
// 2.封裝請求參數
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
// 3.發(fā)送POST請求
mgr POST:@"http://192.168.1.200:8080/MJServer/login" parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) { // responseObject : 在這種情況下是字典
NSLog(@"請求成功---%@", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"請求失敗---%@", error);
}];
2."文件上傳"
// 1.獲得請求管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
// 2.發(fā)送請求(做文件上傳)
// parameters : 只能放非文件參數
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"zhangsan";
[mgr POST:@"http://192.168.1.200:8080/MJServer/upload" parameters:params
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// 一定要在這個block中添加文件參數
// 加載文件數據
NSString *file = [[NSBundle mainBundle] pathForResource:@"test.txt" ofType:nil];
NSData *data = [NSData dataWithContentsOfFile:file];
// 拼接文件參數
[formData appendPartWithFileData:data name:@"file" fileName:@"123.txt" mimeType:@"text/plain"];
}
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"上傳成功----%@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"上傳失敗----%@", error);
}];
- "使用框架--網絡狀態(tài)監(jiān)控"
1 >"使用框架Reachability"
// 使用通知--監(jiān)聽網絡狀態(tài)改變的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkStateChange) name:kReachabilityChangedNotification object:nil];
// 創(chuàng)建Reachability
self.conn = [Reachability reachabilityForInternetConnection];
// 開始監(jiān)控網絡(一旦網絡狀態(tài)發(fā)生改變涤妒,就會發(fā)出kReachabilityChangedNotification)
[self.conn startNotifier];
// 處理網絡狀態(tài)改變
- (void)checkNetworkState
{
// 1.檢測wifi狀態(tài)
Reachability *wifi = [Reachability reachabilityForLocalWiFi];
// 2.檢測手機是否能上網絡(WIFI\3G\2.5G)
Reachability *conn = [Reachability reachabilityForInternetConnection];
// 3.判斷網絡狀態(tài)
if ([wifi currentReachabilityStatus] != NotReachable) { // 有wifi
NSLog(@"有wifi");
} else if ([conn currentReachabilityStatus] != NotReachable) { // 沒有使用wifi, 使用手機自帶網絡進行上網
NSLog(@"使用手機自帶網絡進行上網");
} else { // 沒有網絡
NSLog(@"沒有網絡");
}
2 >"使用框架AFN"
// 1.獲得網絡監(jiān)控的管理者
AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];// 單例
// 2.設置網絡狀態(tài)改變后的處理
[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
// 當網絡狀態(tài)改變了, 就會調用這個block
switch (status) {
case AFNetworkReachabilityStatusUnknown: // 未知網絡
NSLog(@"未知網絡");
break;
case AFNetworkReachabilityStatusNotReachable: // 沒有網絡(斷網)
NSLog(@"沒有網絡(斷網)");
break;
case AFNetworkReachabilityStatusReachableViaWWAN: // 手機自帶網絡
NSLog(@"手機自帶網絡");
break;
case AFNetworkReachabilityStatusReachableViaWiFi: // WIFI
NSLog(@"WIFI");
break;
}
}];
// 3.開始監(jiān)控
[mgr startMonitoring];
// 主動判斷當前的網絡是否可以用(方法)
// mgr.isReachableViaWiFi
// mgr.isReachableViaWWAN
-----------------------面試:--------------------------
面試:
ASI和AFN的區(qū)別?
// 回答角度:
1.性能
2.發(fā)送請求
3.處理服務器數據
4.ASI的特色
5.AFN的特色
1.性能
*ASI基于底層CFNetwork框架
*AFN基于NSURLConnection
*運行性能:ASI > AFN
- 處理服務器數據
1> AFN : 根據服務器返回的數據赚哗,進行自動解析(智能)
*服務器返回的是JSON數據她紫,自動轉換為NSDictionary 或者NSArray
*服務器返回的是XML數據,自動轉換為NSXMLParser
*
2> ASI : 并沒有對服務器的數據進行解析屿储,直接返回NSData二進制數據
3.處理請求的過程
1> AFN : success 和 failure 兩個block
2> ASI : 有3種方式處理請求過程(代理方法犁苏、SEL、block)
4.ASI的特色(重點)
1> 緩存
2> 下載和上傳
*輕松監(jiān)聽請求進度
*輕松實現斷點下載(ASI沒有斷點上傳功能扩所,斷點上傳功能得使用socket技術)
3> 提供了很多擴展接口(比如做數據壓縮)
*
"ASIDataCompressor.h"
"ASIDataDecompressor.h"
*
4> ASIHTTPRequest繼承自NSOperation
*能用隊列統(tǒng)一管理所有請求
*請求之間能依賴
5> ASINetworkQueue
*統(tǒng)一管理所有請求
*如5個下載或上傳請求 --> ASINetworkQueue : 監(jiān)聽5個請求的總進度
*監(jiān)聽所有請求的開始\失敗\完畢
*shouldCancelAllRequestsOnFailure
*YES : 隊列中某個請求失敗了,其它所有請求都消失
*NO :隊列中的某個請求失敗了朴乖,其它請求不受影響祖屏,繼續(xù)請求
5.AFN的特色(重點)
1助赞、使用簡單
2、方便
擴展:重構
//--------// 封裝方法 --重構---------
- (void)viewDidLoad
{
// 封裝前的效果 -- 代碼庸于
[super viewDidLoad];
// 設置導航欄按鈕
// UIButton *leftButton = [[UIButton alloc] init];
// [leftButton setBackgroundImage:[UIImage imageWithName:@"navigationbar_friendsearch"] forState:UIControlStateNormal];
// [leftButton setBackgroundImage:[UIImage imageWithName:@"navigationbar_friendsearch_highlighted"] forState:UIControlStateHighlighted];
// // 設置按鈕的尺寸為背景圖片的尺寸
// leftButton.size = leftButton.currentBackgroundImage.size;
// // 監(jiān)聽按鈕點擊
// [leftButton addTarget:self action:@selector(friendSearch) forControlEvents:UIControlEventTouchUpInside];
// self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:leftButton];
//
// // 設置右邊按鈕
// UIButton *rightButton = [[UIButton alloc] init];
// [rightButton setBackgroundImage:[UIImage imageWithName:@"navigationbar_pop"] forState:UIControlStateNormal];
// [rightButton setBackgroundImage:[UIImage imageWithName:@"navigationbar_pop_highlighted"] forState:UIControlStateHighlighted];
// // 設置按鈕的尺寸為背景圖片的尺寸
// rightButton.size = rightButton.currentBackgroundImage.size;
// // 監(jiān)聽按鈕點擊
// [rightButton addTarget:self action:@selector(pop) forControlEvents:UIControlEventTouchUpInside];
// self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:rightButton];
// 封裝后的效果袁勺,// 注意:target:(id)target
// 設置導航欄按鈕
self.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_friendsearch" highImageName:@"navigationbar_friendsearch_highlighted" target:self action:@selector(friendSearch)];
self.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_pop" highImageName:@"navigationbar_pop_highlighted" target:self action:@selector(pop)];
}
// 封裝方法 // 注意:target:(id)target
- (UIBarButtonItem *)itemWithImageName:(NSString *)imageName highImageName:(NSString *)highImageName target:(id)target action:(SEL)action
{
UIButton *button = [[UIButton alloc] init];
[button setBackgroundImage:[UIImage imageWithName:imageName] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageWithName:highImageName] forState:UIControlStateHighlighted];
// 設置按鈕的尺寸為背景圖片的尺寸
button.size = button.currentBackgroundImage.size;
// 監(jiān)聽按鈕點擊
[button addTarget:self action:@selector(pop) forControlEvents:UIControlEventTouchUpInside];
return [[UIBarButtonItem alloc] initWithCustomView:button];
}
// -----------封裝方法----------
- (void)viewDidLoad
{
[super viewDidLoad];
// 封裝前的效果
// UIViewController *home = [[UIViewController alloc] init];
// home.tabBarItem.title = @"首頁";
// home.tabBarItem.image = [UIImage imageWithName:@"tabbar_home"];
//...
//...
// 封裝后的效果
// 添加子控制器
HMHomeViewController *home = [[HMHomeViewController alloc] init];
[self addOneChlildVc:home title:@"首頁" imageName:@"tabbar_home" selectedImageName:@"tabbar_home_selected"];
HMMessageViewController *message = [[HMMessageViewController alloc] init];
[self addOneChlildVc:message title:@"消息" imageName:@"tabbar_message_center" selectedImageName:@"tabbar_message_center_selected"];
HMDiscoverViewController *discover = [[HMDiscoverViewController alloc] init];
[self addOneChlildVc:discover title:@"發(fā)現" imageName:@"tabbar_discover" selectedImageName:@"tabbar_discover_selected"];
HMProfileViewController *profile = [[HMProfileViewController alloc] init];
[self addOneChlildVc:profile title:@"我" imageName:@"tabbar_profile" selectedImageName:@"tabbar_profile_selected"];
}
* 添加一個子控制器
* @param childVc 子控制器對象
* @param title 標題
* @param imageName 圖標
* @param selectedImageName 選中的圖標
- (void)addOneChlildVc:(UIViewController *)childVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName
{
childVc.view.backgroundColor = HMRandomColor;
// 設置標題
// 相當于同時設置了tabBarItem.title和navigationItem.title
childVc.title = title;
// childVc.tabBarItem.title = title; // tabbar標簽上
// childVc.navigationItem.title = title; // 導航欄
// 設置圖標
childVc.tabBarItem.image = [UIImage imageWithName:imageName];
// 設置選中的圖標
UIImage *selectedImage = [UIImage imageWithName:selectedImageName];
if (iOS7) {
// 聲明這張圖片用原圖(別渲染)
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}
childVc.tabBarItem.selectedImage = selectedImage;
// 添加為tabbar控制器的子控制器
HMNavigationController *nav = [[HMNavigationController alloc] initWithRootViewController:childVc];
[self addChildViewController:nav];
}