同步請求和異步請求
- 同步請求:阻塞式請求,會導致用戶體驗的中斷
- 異步請求:非阻塞式請求,不中斷用戶體驗恨闪,百度地圖,百度建議等都使用了異步請求來獲取數(shù)據(jù)放坏,不用中斷用戶操作咙咽。
- NSURL
- +URLWithString:類方法:用字符串創(chuàng)建統(tǒng)一資源定位符對象
NSURLRequest / NSMutaleURLRequest - +requestWithURL:類方法:用統(tǒng)一資源定位符對象創(chuàng)建請求
- +requestWithURL:cachePolicy:timeoutInterval:類方法:用統(tǒng)一資源定位符創(chuàng)建請求并指定緩存策略和超時時間
- -HTTPBody屬性:設置請求消息體
- -HTTPBodyStream屬性:指定請求消息體的輸入流
- -HTTPMethod屬性:設置請求方法(最常用的是GET或POST)
- -setValue:forHTTPHeaderField:方法:設置請求頭
- NSURLConnection
- +connectionWithRequest:delegate:類方法:創(chuàng)建連接對象并指定委托
- -start / -cancel方法:啟動/取消異步請求
- +sendSynchronousRequest:returningResponse:error:類方法:發(fā)送同步請求,第一個參數(shù)是請求對象淤年,第二個參數(shù)是NSURLResponse對象的二重指針钧敞,第三個參數(shù)是NSError對象的二重指針缸棵,返回NSData對象代表從服務器獲得的數(shù)據(jù)。
- +sendAsynchronousRequest:queue:completionHandler:類方法:發(fā)送異步請求丛晌,第一個參數(shù)是請求對象签餐,第二個參數(shù)是NSOperationQueue對象(管理各種操作的隊列,操作除非完成或取消否則一直由隊列對其進行管理)愚战,第三參數(shù)是用block語法給出的回調代碼(當服務器響應完成時進行回調)娇唯。該方法返回類型是void,因為不需要等待獲得服務器響應的數(shù)據(jù)寂玲,當服務器返回數(shù)據(jù)完成或請求發(fā)生錯誤或超時時塔插,會執(zhí)行相應的回調。
- NSURLConnectionDataDelegate
- connection:willSendRequest:redirectResponse:方法:處理重定向的回調方法
- connection:didReceiveResponse:方法:當前連接接收到足夠的數(shù)據(jù)來構造響應對象時回調此方法
- connection:didReceiveData:方法收到服務器數(shù)據(jù)的回調方法拓哟,該方法可能被調用多次想许,需要進行數(shù)據(jù)的拼接
- connection:needNewBodyStream:方法:在重定向時需要提供新的消息體時的回調方法
- connection:willCacheResponse:方法:緩存響應時的回調方法
- connectionDidFinishLoading:方法:當前連接數(shù)據(jù)加載完成時的回調方法
- connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:方法:POST請求上傳文件時會回調此方法,該方法用于估計上傳的進度
- JSON的由來
JSON全稱JavaScript Object Notation断序,JavaScript中創(chuàng)建對象的表達式流纹,廣泛的應用于系統(tǒng)之間的數(shù)據(jù)交換(尤其是異構系統(tǒng))。
2. JSON和XML的比較
XML全稱eXtensible Markup Language逢倍,是通過自定義的擴展標簽來保存數(shù)據(jù)捧颅,是曾經異構系統(tǒng)之間交換數(shù)據(jù)的事實標準,也被很多系統(tǒng)用于保存配置信息(如plist文件)较雕,但是目前這兩項功能都幾乎被JSON取代碉哑。個人認為XML僅存的優(yōu)勢是數(shù)據(jù)可讀性更強,而且可以通過DTD和Schema的方式對整個XML進行約束和驗證亮蒋。
- JSON的創(chuàng)建和解析
NSJSONSerialization類
- +JSONObjectWithData:options:error:類方法:將JSON格式的NSData轉成對象(通常是數(shù)組或字典)
- +JSONObjectWithStream:options:error類方法:將JSON格式的NSInputStream轉成對象(通常是數(shù)組或字典)
- SDWebImage異步圖片下載
- SDWebImage的作用:
- 對UIImageView進行擴展以支持基于Web的圖像和緩存管理
- 異步圖片下載/加載
- 自動緩存圖像超時管理
- 支持GIF/WebP格式
- 背景圖壓縮
- 相同URL的圖像不會被下載兩次
- 無效的地址不會多次重試
- 主線程不會被阻塞
- 使用GCD和block扣典,擁有更好的性能
- SDWebImage用法示例:
// 通過SDWebImage對UIImage的擴展方法sd_animatedGIFNamed:加載GIF圖片
// 注意:新版本的SDWebImage的方法都加上了sd_前綴作為標識與之前的版本有所不同
// 指定GIF圖片名稱時不能加后綴.gif否則無法呈現(xiàn)動畫效果
UIImage *image = [UIImage sd_animatedGIFNamed:@"gourdboy"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(5, 50, 370, 300);
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
- 用SDWebImage下載圖像并顯示進度
-(void)viewDidLoad {
[super viewDidLoad];
UIProgressView *progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
progressView.frame = CGRectMake(10, 50, 300, 100);
progressView.tintColor = [UIColor blueColor];
progressView.trackTintColor = [UIColor yellowColor];
[self.view addSubview:progressView];
NSURL *imageUrl = [NSURL URLWithString:@"http://www.baidu.com/img/bd_logo1.png"];
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:imageUrl options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize) {
NSLog(@"%f", receivedSize / (double) expectedSize);
progressView.progress = (double) receivedSize / expectedSize;
}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image) {
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(10, 200, 350, 300);
[self.view addSubview:imageView];
}
}
];
}```
- NSURLSession的使用
??2013的WWDC上,蘋果推出了NSURLConnection的繼任者:NSURLSession慎玖。與NSURLConnection相比贮尖,NSURLsession最直接的改進就是可以配置每個session的緩存、協(xié)議趁怔、cookie以及證書策略(credential policy)湿硝,甚至跨程序共享這些信息。這將允許程序和網(wǎng)絡基礎框架之間相互獨立润努,不會發(fā)生干擾关斜。每個NSURLSession對象都由一個NSURLSessionConfiguration對象來進行初始化,后者指定了剛才提到的那些策略以及一些用來增強移動設備上性能的新選項铺浇。
??NSURLSession中另一大塊就是會話任務(NSURLSessionTask)痢畜,它負責處理數(shù)據(jù)的加載以及文件和數(shù)據(jù)在客戶端與服務端之間的上傳和下載。NSURLSessionTask與NSURLConnection最大的相似之處在于它也負責數(shù)據(jù)的加載,最大的不同之處在于所有的task共享其創(chuàng)造者NSURLSession這一公共委托者(common delegate)丁稀。
- NSURLSession
- +sessionWithConfiguration:類方法:用指定的配置創(chuàng)建會話對象
- +sessionWithConfiguration:delegate:delegateQueue:類方法:用指定的配置吼拥、委托和操作隊列創(chuàng)建會話
- +sharedSession:類方法:使用默認配置獲得會話的單例
- -dataTaskWithURL:方法:用指定的統(tǒng)一資源定位符創(chuàng)建GET請求
- -dataTaskWithURL:completionHandler:方法:用指定的統(tǒng)一資源定位符創(chuàng)建GET請求并用Block指定請求完成的回調代碼
- -dataTaskWithRequest:方法:用指定的請求對象創(chuàng)建一個請求
- -dataTaskWithRequest:completionHandler:方法:用指定的請求對象創(chuàng)建一個請求并用Block指定請求完成的回調代碼
- -downloadTaskWithURL:方法:用指定的統(tǒng)一資源定位符創(chuàng)建一個下載任務
- -downloadTaskWithURL:completionHandler:方法:用指定的統(tǒng)一資源定位符創(chuàng)建一個下載任務并用Block指定請求完成的回調代碼
- -downloadTaskWithRequest:方法:用指定的請求對象創(chuàng)建一個下載任務
- -downloadTaskWithRequest:completionHandler:方法:用指定的請求對象創(chuàng)建一個下載任務并用指定的請求對象創(chuàng)建一個下載任務
- -uploadTaskWithRequest:fromData:方法:用指定的請求和數(shù)據(jù)創(chuàng)建一個上傳任務
- -uploadTaskWithRequest:fromData:completionHandler:方法:用指定的請求和數(shù)據(jù)創(chuàng)建一個上傳任務并用Block指定請求完成的回調代碼
- -uploadTaskWithRequest:fromFile:方法:用指定請求和文件創(chuàng)建一個上傳任務
- -uploadTaskWithRequest:fromFile:completionHandler:方法:用指定請求和文件創(chuàng)建一個上傳任務并用Block指定請求完成的回調代碼
- NSURLSessionConfiguration
??NSURLSessionConfiguration有三個類工廠方法,這很好地說明了 NSURLSession設計時所考慮的不同的使用場景线衫。
- +defaultSessionConfiguration方法:返回一個標準的配置凿可,這個配置實際上與NSURLConnection具有相同的共享NSHTTPCookieStorage,共享NSURLCache和共享 NSURLCredentialStorage桶雀。
- +ephemeralSessionConfiguration方法:返回一個預設配置矿酵,這個配置中不會對緩存唬复,Cookie和證書進行持久性的存儲矗积。這對于實現(xiàn)像秘密瀏覽這種功能來說是很理想的。
- +backgroundSessionConfiguration:方法:該方法的獨特之處在于敞咧,它會創(chuàng)建一個后臺 session棘捣。后臺session不同于普通的session,它甚至可以在應用程序掛起休建,退出或者崩潰的情況下運行上傳和下載任務乍恐。初始化時指定的標識符,被用于向任何可能在進程外恢復后臺傳輸?shù)氖刈o進程(daemon)提供上下文测砂。
- NSURLSessionTask
- -cancel方法:取消任務
- -resume方法:恢復任務
- -suspend方法:掛起任務
??**GET請求的示例**
```Objective-C
NSURL *URL = [NSURL URLWithString:@"http://example.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// ...
}];
[task resume];
上傳的示例
NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSData *data = ...;
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:data
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// ...
}
];
[uploadTask resume];
下載的示例
NSURL *URL = [NSURL URLWithString:@"http://example.com/file.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSURL *documentsDirectoryURL = [NSURL fileURLWithPath:documentsPath];
NSURL *newFileLocation = [documentsDirectoryURL URLByAppendingPathComponent:[[response URL] lastPathComponent]];
[[NSFileManager defaultManager] copyItemAtURL:location toURL:newFileLocation error:nil];
}
];
[downloadTask resume];
NSURLSessionConfiguration擁有20項配置屬性茵烈。熟練掌握這些配置屬性的用處,可以讓應用程序充分地利用其網(wǎng)絡環(huán)境砌些。
- HTTPAdditionalHeaders屬性:指定了一組默認的可以設置請求頭呜投。
NSString *userPasswordString = [NSString stringWithFormat:@"%@:%@", user, password];
NSData * userPasswordData = [userPasswordString dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64EncodedCredential = [userPasswordData base64EncodedStringWithOptions:0];
NSString *authString = [NSString stringWithFormat:@"Basic %@", base64EncodedCredential];
NSString *userAgentString = @"AppName/com.example.app (iPhone 5s;iOS 7.0.2; Scale/2.0)";
configuration.HTTPAdditionalHeaders = @{
@"Accept": @"application/json",
@"Accept-Language": @"en",
@"Authorization": authString,
@"User-Agent": userAgentString
};
- allowsCellularAccess屬性和discretionary屬性:被用于節(jié)省通過蜂窩網(wǎng)絡連接的帶寬。對于后臺傳輸?shù)那闆r存璃,推薦大家使用discretionary這個屬性仑荐,而不是allowsCellularAccess,因為前者會把WIFI和電源的可用性考慮在內
- timeoutIntervalForRequest屬性和timeoutIntervalForResource屬性分別指定了對于請求和資源的超時間隔纵东。許多開發(fā)人員試圖使用timeoutInterval去限制發(fā)送請求的總時間粘招,但其實它真正的含義是:分組(packet)之間的時間。實際上我們應該使用timeoutIntervalForResource來規(guī)定整體超時的總時間偎球,但應該只將其用于后臺傳輸洒扎,而不是用戶實際上可能想要去等待的任何東西
- HTTPCookieStorage屬性存儲了session所使用的cookie∷バ酰可以使用NSHTTPCookieShorage類的sharedHTTPCookieStorage類方法獲得這個單例對象
- HTTPCookieAcceptPolicy決定了什么情況下session應該接受從服務器發(fā)出的cookie
- HTTPShouldSetCookies指定了請求是否應該包含cookie袍冷,也就是剛才我們提到的 HTTPCookieStorage屬性的值,如果在請求中包含cookie岂傲,可以實現(xiàn)用戶跟蹤的功能
- URLCredentialStorage存儲了session所使用的證書难裆。默認情況下會使用 NSURLCredentialStorage的sharedCredentialStorage類方法獲得這個單例對象
- TLSMaximumSupportedProtocol和TLSMinimumSupportedProtocol確定session是否支持 SSL協(xié)議。
- URLCache是session使用的緩存。默認情況下會使用NSURLCache的sharedURLCache類方法會提供這個單例對象
- requestCachePolicy指定了一個請求的緩存響應應該在什么時候返回乃戈。這相當于NSURLRequest的cachePolicy方法褂痰。
和NSURLSession相關的有四個協(xié)議,分別是:NSURLSessionDelegate / NSURLSessionTaskDelegate / NSURLSessionDataDelegate / NSURLSessionDownloadDelegate
理解KVC和KVO##
KVC全稱是Key Value Coding(鍵值對編程)症虑,其本質上是對NSObject類的擴展(NSObject類的Category)缩歪,它提供一種機制來間接訪問對象的屬性。KVO全稱Key Value Observing(鍵值對觀察)谍憔,是建立KVC之上的模型對象的觀察者模式的實現(xiàn)匪蝙。
??KVO:Key-Value Observing(KVO)建立在KVC之上,它能夠觀察一個對象指定屬性值的變化习贫,在需要的時候產生對應的通知逛球。
- valueForKey:方法用于以字符串調用對象的get屬性方法,或者讀取成員變量的值苫昌;與之相對的是setValue:forKey:颤绕,它用于以字符串調用對象的set屬性方法,或者修改成員變量的值祟身。
- 對于基本數(shù)據(jù)類型奥务,KVC方法會對基本數(shù)據(jù)類型進行封裝,基本數(shù)據(jù)類型封裝為NSNumber袜硫,其他結構體類型封裝為NSValue
- 在使用KVC時氯葬,如果找不到字符串對應的屬性和成員變量時會調用valueForUndefinedKey:或者setValue:forUndefinedKey:這兩個方法,默認情況下會拋出異常
- 在默認情況下KVC方法能夠直接訪問類的私有成員變量婉陷,如果我們不想這樣帚称,可以重寫accessInstanceVariablesDirectly方法,并令其返回NO(默認是返回YES)
- KVC方法定義在NSKeyValueCoding類別中憨攒,該類別附加于NSObject類上世杀,所以所有對象都具有這些方法
- 在一些特殊的類的對象上調用KVC方法會有特別的效果。對于數(shù)組NSArray肝集、集合NSSet瞻坝,調用valueForKey:會對每個數(shù)組和集合成員調用valueForKey:,并返回新的數(shù)組或者集合
- 在KVC中還有一種常用技術杏瞻,稱為鍵值鏈(Key Path)所刀。鍵值鏈是用點將若干鍵相連的字符串,例如“manufacturer.product.name”捞挥。通過在對象上調用valueForKeyPath:或者setValue:forKeyPath:浮创,我們就可以在一條語句中級聯(lián)調用指定的屬性。
????KVO##
// 當觀察到被觀察對象屬性變化時要執(zhí)行的回調方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(fractionCompleted))]) {
// NSLog(@"%@", change);
double currentProgress = [change[@"new"] doubleValue];
hud.progress = (float) currentProgress;
if (currentProgress >= 1.0) {
// 移除觀察者(避免內存泄露的問題)
[object removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
}
}
}```
##????YYModel##
@property (nonatomic, copy) NSArray *eduinfo;
@property (nonatomic, copy) NSArray *workinfo;
@property (nonatomic, readonly) NSString *fullBirthday;
// 設置容器類型的屬性中的對象類型 輔助YYModel進行模型和JSON轉換
+(NSDictionary *) modelContainerPropertyGenericClass {
// value should be Class or Class name.
return @{
@"eduinfo" : [CDEduInfo class],
@"workinfo" : [CDWorkInfo class]
};
}
- (NSString *) fullBirthday {
return [NSString stringWithFormat:@"%@年%@月%@日", _birthyear, _birthmonth, _birthday];
}
- (NSDictionary *)modelCustomPropertyMapper {
return @{
@"albumId" : @"id",
@"pictureCount" : @"pics",
@"albumName" : @"albumname"
};
}```
AFNetworking
AFNetworking是一個能夠快速使用的iOS和MacOS X下的網(wǎng)絡框架砌函,它是構建在Foundation URL Loading System之上的斩披,封裝了網(wǎng)絡的抽象層溜族,可以方便的使用,是一個模塊化架構并擁有豐富API的框架垦沉。
HTTP請求和操作
// GET請求
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:@"http://example.com/resources.json" parameters: nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
// 帶有表單參數(shù)的POST請求
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"foo": @"bar"};
[manager POST:@"http://example.com/resources.json" parameters: parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
// 上傳表單和文件
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"foo": @"bar"};
NSURL *filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"];
[manager POST:@"http://example.com/resources.json" parameters: parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileURL: filePath name:@"image" error: nil];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Success: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
Session管理
// 創(chuàng)建一個下載任務
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:@"http://example.com/download.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL: URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest: request progress: nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory: NSDocumentDirectory inDomain: NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(@"File downloaded to: %@", filePath);
}];
[downloadTask resume];
// 創(chuàng)建一個上傳任務
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURL *filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"];
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"Success: %@ %@", response, responseObject);
}
}];
[uploadTask resume];
// 創(chuàng)建一個帶進度的上傳任務
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileURL:[NSURL fileURLWithPath:@"file://path/to/image.jpg"] name:@"file" fileName:@"filename.jpg" mimeType:@"image/jpeg" error:nil];
} error:nil];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSProgress *progress = nil;
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"%@ %@", response, responseObject);
}
}];
[uploadTask resume];
// 創(chuàng)建請求對象
NSString *URLString = @"http://example.com";
NSDictionary *parameters = @{@"foo": @"bar", @"baz": @[@1, @2, @3]};
[[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:URLString parameters:parameters error:nil];
// 網(wǎng)絡可達性檢測
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(@"Reachability: %@", AFStringFromNetworkReachabilityStatus(status));
}];
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
// 基于HTTP請求操作管理器的網(wǎng)絡可達性檢測
NSURL *baseURL = [NSURL URLWithString:@"http://example.com/"];
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL: baseURL];
NSOperationQueue *operationQueue = manager.operationQueue;
[manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusReachableViaWWAN:
case AFNetworkReachabilityStatusReachableViaWiFi:
[operationQueue setSuspended: NO];
break;
case AFNetworkReachabilityStatusNotReachable:
default:
[operationQueue setSuspended:YES];
break;
}
}];
[manager.reachabilityManager startMonitoring];
// 批量任務處理
NSMutableArray *mutableOperations = [NSMutableArray array];
for (NSURL *fileURL in filesToUpload) {
NSURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileURL:fileURL name:@"images[]" error:nil];
}];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[mutableOperations addObject:operation];
}
NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:@[...] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
NSLog(@"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations);
} completionBlock:^(NSArray *operations) {
NSLog(@"All operations in batch complete");
}];
[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];
下拉刷新和上拉刷新(觸底刷新)##
- UIRefreshControl和觸底刷新的原理
self.tableView.delegate = self; self.ref = [[UIRefreshControl alloc] init]; self.ref.tintColor = [UIColor orangeColor]; [self.ref addTarget:self action:@selector(doRefresh) forControlEvents:UIControlEventValueChanged]; [self.tableView addSubview:self.ref];
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if(scrollView.contentOffset.y + scrollView.frame.size.height > scrollView.contentSize.height + 50) { } }
- 第三方庫:MJRefresh
????iOS8 以前的聯(lián)網(wǎng)方式
// NSData和NSString通過URL獲取網(wǎng)絡資源屬于同步請求
// 這就意味著在獲取資源的過程中代碼會阻塞直到得到資源
// 因此可能會導致界面出現(xiàn)假死狀態(tài) 所以如果可以的話
// 我們應當盡可能使用異步請求(非阻塞式請求)來獲取網(wǎng)絡資源
// iOS 8 以前的聯(lián)網(wǎng)方式
NSString *username = _uidField.text;
NSString *password = _pwdField.text;
// 提示: 如果用戶名有非ASCII字符需要轉換成對應的百分號編碼
NSString *urlStr = [NSString stringWithFormat:@"http://10.0.8.8/sns/my/login.php?username=%@&password=%@", [username stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], password];
// 1. 創(chuàng)建一個統(tǒng)一資源定位符對象
NSURL *url = [NSURL URLWithString:urlStr];
// 2. 創(chuàng)建一個請求對象
// 第一個參數(shù): 統(tǒng)一資源定位符
// 第二個參數(shù): 緩存策略
// 第三個參數(shù): 請求超時時間
NSURLRequest *req = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5];
// 3. 通過連接對象發(fā)送請求
// 同步請求 - 阻塞式請求(代碼會在此阻塞直到服務器完成響應或超時)
// 異步請求 - 非阻塞式請求(代碼會往下執(zhí)行, 當收到服務器數(shù)據(jù)時通過Block回調處理服務器返回的數(shù)據(jù))
NSURLResponse *resp = nil;
NSError *err = nil;
// NSURLSession是NSURLConnection的繼任者
// AFNetworking第三方庫
NSData *data = [NSURLConnection sendSynchronousRequest:req returningResponse:&resp error:&err];
// 4. 解析數(shù)據(jù)
if (!err) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:1 error:nil];
[CDUtility showAlertWithMessage:dict[@"message"] onViewController:self];
if ([dict[@"code"] isEqualToString:@"login_success"]) {
// 通過單例對象保存用戶的uid
[CDSNSContext sharedSNSContext].uid = [dict[@"uid"] integerValue];
CDUserInfoViewController *userInfoVC = [[CDUserInfoViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:userInfoVC];
self.view.window.rootViewController = nav;
} }
else {
NSLog(@"%@", err);
}
????NSURLConnection##
NSString *urlStr = [NSString stringWithFormat:@"http://10.0.8.8/sns/my/register.php?username=%@&password=%@&email=%@", [username stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], password, email];
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *req = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5];
// 發(fā)送異步請求
// 第一個參數(shù): 請求對象
// 第二個參數(shù): 操作隊列(異步請求操作放在哪個隊列中執(zhí)行)
// 第三個參數(shù): Block回調(處理服務器返回的數(shù)據(jù))
[NSURLConnection sendAsynchronousRequest:req queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (!connectionError) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:1 error:nil];
if ([dict[@"code"] isEqualToString:@"registered"]) {
// 反向傳值
if (_handler) {
_handler(username, password);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
else {
[CDUtility showAlertWithMessage:dict[@"message"] onViewController:self];
}
}
else {
NSLog(@"%@", connectionError);
}
sender.enabled = YES;
}];
????NSURLSession聯(lián)網(wǎng)##
// NSURLSessionConfiguration對象可以保存公共設置
// 設置一次之后通過該對象創(chuàng)建的NSURLSession都使用相同的設置
// 創(chuàng)建一個默認的配置
// config = [NSURLSessionConfiguration defaultSessionConfiguration];
// config.HTTPAdditionalHeaders = @{
// @"apikey" : @"ae774eed68e97890749971a8a5a8e3e4"
// };
// config.timeoutIntervalForRequest = 5;
// config.discretionary = YES;
// 創(chuàng)建一個無痕瀏覽的配置
// config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
// 創(chuàng)建一個后臺運行的配置
// config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"ABC"];
- (void) addAlbumButtonClicked:(UIBarButtonItem *) sender {
UIAlertController *ac = [UIAlertController alertControllerWithTitle:@"創(chuàng)建相冊" message:@"請輸入相冊的名稱" preferredStyle:UIAlertControllerStyleAlert];
// 給警告控制器中添加文本框
[ac addTextFieldWithConfigurationHandler:^(UITextField *textField) {
// 此處可以對文本框進行定制
textField.clearButtonMode = UITextFieldViewModeAlways;
textField.delegate = self;
textField.returnKeyType = UIReturnKeyDone;
}];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
// 點擊確定按鈕就創(chuàng)建相冊
UITextField *textField = [ac.textFields firstObject];
NSString *name = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (name.length > 0) {
[self createAlbum:name];
}
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
[ac addAction:okAction];
[ac addAction:cancelAction];
[self presentViewController:ac animated:YES completion:nil];
}```
##????NSURLSession聯(lián)網(wǎng)##
-
(void) createAlbum:(NSString *) name {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://10.0.8.8/sns/my/create_album.php?albumname=%@&privacy=0", [name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];// 通過NSURLSessionConfiguration對象創(chuàng)建NSURLSession對象
NSURLSession *session = [NSURLSession sessionWithConfiguration:[CDSNSContext sharedSNSContext].configure delegate:self delegateQueue:nil];
// 通過指定的NSURL對象創(chuàng)建一個獲取數(shù)據(jù)的任務
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:1 error:nil];
if ([dict[@"code"] isEqualToString:@"do_success"]) {
CDAlbum *model = [[CDAlbum alloc] init];
model.albumId = [dict[@"albumid"] integerValue];
model.albumName = name;
model.pictureCount = 0;
// 將模型對象放在裝模型的數(shù)組中
[dataArray insertObject:model atIndex:0];
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主線程在表格視圖中插入新行
[myTableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationRight];
});
}
else {
NSLog(@"然并卵!!!");
}
}
else {
NSLog(@"%@", error);
}}];
// 執(zhí)行任務
[task resume];
}```
????NSURLSession聯(lián)網(wǎng)獲取數(shù)據(jù)煌抒、NSOperation##
- (void) loadDataModel {
if (!dataArray) {
dataArray = [NSMutableArray array];
}
NSURL *url = [NSURL URLWithString:@"http://10.0.8.8/sns/my/album_list.php"];
NSURLRequest *req = [NSURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:5];
// 創(chuàng)建默認設置的網(wǎng)絡請求會話
NSURLSession *session = [NSURLSession sharedSession];
// 通過會話創(chuàng)建一個獲取數(shù)據(jù)的任務
NSURLSessionDataTask *task = [session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:1 error:nil];
for (NSDictionary *albumDict in dict[@"albums"]) {
// 通過MJExtension將字典轉成模型對象
CDAlbum *model = [CDAlbum yy_modelWithDictionary:albumDict];
[dataArray addObject:model];
}
// 模型對象準備就緒后就可以刷新表格視圖了
// 蘋果官方規(guī)定: 刷新界面的代碼要在主線程中執(zhí)行
// 否則界面可能無法刷新 因此下面的代碼要回到主線程執(zhí)行
// 寫法一: GCD
// dispatch_async(dispatch_get_main_queue(), ^{
// [myTableView reloadData];
// });
// 寫法二: NSOperation和NSOperationQueue
// 創(chuàng)建一個操作對象封裝要執(zhí)行的代碼
NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
[myTableView reloadData];
}];
// 將該操作添加到主隊列(主隊列中的操作在主線程中執(zhí)行)中
[[NSOperationQueue mainQueue] addOperation:op];
}
else {
NSLog(@"%@", error);
}
}];
// 任務恢復
[task resume];
// 任務掛起
// [task suspend];
// 任務取消
// [task cancel];
}```
##????AFNetworking上傳照片##
// 上傳照片
-
(void) uploadPhoto:(UIImage *) photoImage {
NSDictionary *params = @{ @"albumid": @(_albumId) };
// 通過AFHTTPRequestSerializer對象創(chuàng)建請求對象
// AFHTTPRequestSerializer對象創(chuàng)建請求的方法有五個參數(shù):
// 第一個參數(shù): 設置請求方法(如果上傳表單數(shù)據(jù)中如果有附件(二進制數(shù)據(jù))必須使用POST請求)
// 第二個參數(shù): 統(tǒng)一資源定位符
// 第三個參數(shù): 提交給服務器的請求參數(shù)(表單中的參數(shù))
// 第四個參數(shù): 提交給服務器的二進制數(shù)據(jù)(表單中的附件)
// 第五個參數(shù): NSError對象指針的指針
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://10.0.8.8/sns/my/upload_photo.php" parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// 通過UUID生成一個全局唯一的文件名
NSString *filename = [NSString stringWithFormat:@"%@.png", [NSUUID UUID].UUIDString];
// 將UIImage對象轉成NSData對象(二進制數(shù)據(jù))
NSData *data = UIImagePNGRepresentation(photoImage);
// 第一個參數(shù): 上傳的二進制數(shù)據(jù)
// 第二個參數(shù): 上傳文件對應的參數(shù)名(通過查API手冊獲得)
// 第三個參數(shù): 上傳文件的文件名(這個名字通常沒用, 因為服務器通常會用自己的命名規(guī)則給上傳的文件起名字來避免名字沖突)
// 第四個參數(shù): MIME類型(告知服務器上傳的文件的類型)
[formData appendPartWithFileData:data name:@"attach" fileName:filename mimeType:@"image/png"];
} error:nil
];// 通過會話配置對象創(chuàng)建AFNetworking的會話管理器對象
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[CDSNSContext sharedSNSContext].configure];
AFHTTPResponseSerializer *serializer = manager.responseSerializer;
serializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", nil];
// 表示完成進度的對象
NSProgress *progress = nil;
// 創(chuàng)建會話任務(獲取數(shù)據(jù)任務、下載任務厕倍、上傳任務)
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
NSLog(@"%@", responseObject);
if (!error) {
[CDUtility showAlertWithMessage:responseObject[@"message"] onViewController:self];
hud.labelText = responseObject[@"message"];
[hud hide:YES afterDelay:2];
}
else {
NSLog(@"%@", error);
}
dispatch_async(dispatch_get_main_queue(), ^{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
});
}];
// 在狀態(tài)欄顯示網(wǎng)絡活動指示器(旋轉的小菊花)
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeDeterminateHorizontalBar;
hud.labelText = @"正在上傳";
hud.opacity = 0.5;
[uploadTask resume];// KVO - Key Value Observing
// GoF設計模式中觀察者模式的應用
// 給NSProgress對象添加一個觀察者觀察它指定屬性的變化
[progress addObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) options:NSKeyValueObservingOptionNew context:nil];
}```
????AFNetworking創(chuàng)建請求##
- (void) loadDataModel {
if (!dataArray) {
dataArray = [NSMutableArray array];
}
// 創(chuàng)建會話管理器對象(AFNetworking提供的專門用于管理NSURLSession的對象)
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[CDSNSContext sharedSNSContext].configure];
// 設置AFNetworking支持的響應內容的MIME類型
// text/html - 超文本
// text/plain - 純文本
// application/json - JSON
// 說明: 有很多后臺寫得很爛的服務器(包括千鋒SNS)在返回
// JSON數(shù)據(jù)的時候沒有指定Content-Type響應頭(MIME類型)是
// application/json類型 這樣的話AFNetworking會報錯
// 因為AFNetworking默認只支持application/json類型
AFHTTPResponseSerializer *serializer = manager.responseSerializer;
serializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html", @"application/json", @"text/plain", nil];
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"http://10.0.8.8/sns/my/photo_list.php?uid=%ld&id=%ld", [CDSNSContext sharedSNSContext].uid, _albumId]];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (!error) {
for (NSDictionary *photoDict in responseObject[@"photos"]) {
CDPhoto *model = [CDPhoto yy_modelWithDictionary:photoDict];
[dataArray addObject:model];
}
dispatch_async(dispatch_get_main_queue(), ^{
[myCollView reloadData];
});
}
else {
NSLog(@"Error: %@", error);
}
}];
[dataTask resume];
}```
##????AFNetworkReachabilityManager##
-
(void)viewDidLoad {
[super viewDidLoad];AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
[manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeDeterminateHorizontalBar;
hud.progress = 0.5;
switch (status) {
case AFNetworkReachabilityStatusNotReachable:
hud.labelText = @"沒有網(wǎng)絡連接";
break;
case AFNetworkReachabilityStatusReachableViaWWAN:
hud.labelText = @"使用移動蜂窩網(wǎng)絡";
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
hud.labelText = @"使用WiFi網(wǎng)絡";
default:
break;
}
dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(2);
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
});
}];
[manager startMonitoring];
}```
????MJRefresh##
MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
[self loadDataModel];
[myTableView.header endRefreshing];
}];
[header setTitle:@"放開那個師太!!!" forState:2];
[header setTitle:@"師太跟和尚跑了!" forState:3];
myTableView.header = header;
MJRefreshBackNormalFooter *footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
[self loadMoreDataModel];
[myTableView.footer endRefreshing];
}];
[footer setTitle:@"需要爺幫你加載更多嗎?" forState:2];
myTableView.footer = footer;
????UIStoryboardSegue##
// 定制Storyboard上segue(連接)的回調方法
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// 通過segue對象獲得目標視圖控制器
CDRegViewController *regVC = segue.destinationViewController;
// 綁定Block屬性實現(xiàn)反向傳值
regVC.handler = ^(NSString *username, NSString *password) {
_uidField.text = username;
_pwdField.text = password;
};
}```
----------------------------------------------------