一步一步搭建自己的iOS網絡請求庫(一)
大家好,我是LastDay,很久沒有寫博客了,這週會分享一個的HTTP請求庫的編寫經驗。
簡單的介紹
介紹一下,NSURLSession是iOS7中新的網絡接口,它與NSURLConnection是並列的。在程序在前臺時,NSURLSession與NSURLConnection可以互爲替代工作。兩者在前臺的時候其實沒有什麼區別,最主要的是程序在進入後臺的時候,Background Session會更加靈活
測試NSURLSession
首先我們來新建一個工程,起名爲LyHttp,在頁面上放置一個按鈕 ,起名爲”測試”。
將按鈕關聯到我們的ViewController.m,起名爲test。
添加以下代碼
- (IBAction)test:(id)sender {
NSURL *url = [NSURL URLWithString:@"http://cityuit.sinaapp.com/1.php"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *reponse,NSError *error){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}];
[task resume];
}
http://cityuit.sinaapp.com/1.php是我自己寫的一個接口用來測試的,會返回succeed。
我們來看一下觸發效果:
測試完成
接下來我們來看看我們的NSURLSession是否爲異步?OK,我們來簡單的修改一下我們的程序吧。講兩個阻塞,來看看我們的主線程變化。
- (IBAction)test:(id)sender {
NSURL *url = [NSURL URLWithString:@"http://cityuit.sinaapp.com/1.php"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *reponse,NSError *error){
//阻塞3秒
[NSThread sleepForTimeInterval:3];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}];
[task resume];
}
可以看見效果就是連續點擊3次,每隔三秒進行一次輸出,直到三次執行完事,這就說明我們的主線程沒有被阻塞,驗證說明NSURLSession爲異步。
曾將看過一篇文章中,介紹過,那篇文章裏介紹NSURLSession 採用的是 “異步阻塞” 模型,即所有請求在發出後都進入 2# 線程執行,在 2# 線程內部按照阻塞隊列模式執行。初步判斷,此阻塞特性爲 [NSURLSession sharedSession] 單例模式的結果。
一步一步搭建自己的iOS網絡請求庫(二)
大家好,我是LastDay,上一次分享了簡單體驗並且測試下一下NSURLSession。
我的博客地址:http://lastday.github.io
進行簡單的封裝
我們接下來將要加入動態的動態的HTTP參數(parameters)的功能,之後封裝出我們自己的接口。
首先呢,我們先來對上一次的代碼進行一次簡單的封裝,建立一個新的類LyNetWork,繼承於NSObject類
。新建一個靜態的request方法。將請求方式和URL傳入
代碼如下:
+(void)request :(NSString *)method URL:(NSString *)URL{
NSURL *url = [NSURL URLWithString:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = method;
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *reponse,NSError *error){
//NSdata轉String
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}];
[task resume];
}
OK
讓我們在ViewController中進行一下測試,代碼如下:
@IBAction func mainButtonBeTapped(sender: AnyObject) {
[LyNetWork request:@"GET" URL:@"http://cityuit.sinaapp.com/1.php"];
}
接下來運行一下:OK 依然顯示我們正確的測試結果:succeed
使用Block處理請求返回值
簡單的介紹下閉包(block),對於OC來說是一個新詞,但不是新的概念,不是新的東西。學過Javascript的小夥伴對閉包應該不陌生吧~學過PHP的應該也不陌生,在PHP5.3版本以後也支持閉包, 也就是OC中所提到的Block。
現在對我們的request函數進行修改,LyNetWork.m代碼如下:
+(void)requestMethod:(NSString *)method
URL:(NSString *)URL
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
NSURL *url = [NSURL URLWithString:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = method;
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *response,NSError *error){
if (error) {
failure(error);
}else{
if (success) {
success(data,response);
}
}
}];
[task resume];
}
接下來修改ViewController中的函數調用,代碼修改後如下:
- (IBAction)test:(id)sender {
[LyNetWork requestMethod:@"GET"
URL:@"http://cityuit.sinaapp.com/1.php"
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}
failure:^(NSError *error){
NSLog(@"%@",error);
}];
}
測試結果依然返回succeed,測試結果正確
接下來進行我們最難處理的地方,增加parameters處理能力
我們先來處理GET方法吧
GET 方法下,params 在經過 url encode 之後直接附在 URL 末尾發送給服務器
類似於這個樣子GET /foo.php?first_name=John&last_name=Doe&action=Submit HTTP/1.1
修改我們的requestMethod方法,將其進行一下更改,引入parameters參數
+(void)requestMethod:(nullable NSString *)method
URL:(nullable NSString *)URL
parameters:(nullable id) parameters
success:(nullable void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(nullable void (^)(NSError *__nullable error))failure;
接下來就該處理我們的parameters參數了
我們從AFNetworking中借鑑一下他的處理方案(其實這裏本人就是模仿編寫罷了)
我們新建一個類起名爲LYURLRequestSerialization,在LYURLRequestSerialization.h添加一下方法
+(NSString *)LYQueryStringFromParameters:(NSDictionary *)parameters;
進入我們的LYURLRequestSerialization.m文件中,添加以下代碼:
#import "LYURLRequestSerialization.h"
@interface LYURLRequestSerialization()
@property (readwrite, nonatomic, strong) id value;
@property (readwrite, nonatomic, strong) id field;
@end
@implementation LYURLRequestSerialization
- (id)initWithField:(id)field value:(id)value {
self = [super init];
if (!self) {
return nil;
}
self.field = field;
self.value = value;
return self;
}
#pragma mark -
FOUNDATION_EXPORT NSArray * LYQueryStringPairsFromDictionary(NSDictionary *dictionary);
FOUNDATION_EXPORT NSArray * LYQueryStringPairsFromKeyAndValue(NSString *key, id value);
+(NSString *)LYQueryStringFromParameters:(NSDictionary *)parameters {
NSMutableArray *mutablePairs = [NSMutableArray array];
for (LYURLRequestSerialization *pair in LYQueryStringPairsFromDictionary(parameters)) {
[mutablePairs addObject:[pair URLEncodedStringValue]];
}
return [mutablePairs componentsJoinedByString:@"&"];
}
NSArray * LYQueryStringPairsFromDictionary(NSDictionary *dictionary) {
return LYQueryStringPairsFromKeyAndValue(nil, dictionary);
}
NSArray * LYQueryStringPairsFromKeyAndValue(NSString *key, id value) {
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];
if ([value isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = value;
for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
id nestedValue = dictionary[nestedKey];
if (nestedValue) {
[mutableQueryStringComponents addObjectsFromArray:LYQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
}
}
} else if ([value isKindOfClass:[NSArray class]]) {
NSArray *array = value;
for (id nestedValue in array) {
[mutableQueryStringComponents addObjectsFromArray:LYQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
}
} else if ([value isKindOfClass:[NSSet class]]) {
NSSet *set = value;
for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
[mutableQueryStringComponents addObjectsFromArray:LYQueryStringPairsFromKeyAndValue(key, obj)];
}
} else {
[mutableQueryStringComponents addObject:[[LYURLRequestSerialization alloc] initWithField:key value:value]];
}
return mutableQueryStringComponents;
}
static NSString * LYPercentEscapedStringFromString(NSString *string) {
static NSString * const kLYCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
static NSString * const kLYCharactersSubDelimitersToEncode = @"!$&'()*+,;=";
NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[allowedCharacterSet removeCharactersInString:[kLYCharactersGeneralDelimitersToEncode stringByAppendingString:kLYCharactersSubDelimitersToEncode]];
static NSUInteger const batchSize = 50;
NSUInteger index = 0;
NSMutableString *escaped = @"".mutableCopy;
while (index < string.length) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wgnu"
NSUInteger length = MIN(string.length - index, batchSize);
#pragma GCC diagnostic pop
NSRange range = NSMakeRange(index, length);
range = [string rangeOfComposedCharacterSequencesForRange:range];
NSString *substring = [string substringWithRange:range];
NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
[escaped appendString:encoded];
index += range.length;
}
return escaped;
}
- (NSString *)URLEncodedStringValue {
if (!self.value || [self.value isEqual:[NSNull null]]) {
return LYPercentEscapedStringFromString([self.field description]);
} else {
return [NSString stringWithFormat:@"%@=%@", LYPercentEscapedStringFromString([self.field description]), LYPercentEscapedStringFromString([self.value description])];
}
}
@end
簡單的說一下吧,以上的方法都是爲了處理傳入的NSDictonary參數,因爲我們在使用的時候爲了方便我們傳入動態的parameters,所以他的的格式是這樣的:
id parmenters = @{
@"value":@"LastDays",
};
將它處理後我們希望得到的樣式應該是這樣,對吧?
http:URL.php?value=LastDays
這個參數是一個動態的,我們不能確定裏面到底有幾組參數,而且還需要考慮的一個問題就是NSDictonary中嵌套NSDictonary的情況,我們處理這種問題的一個思想就是遞歸。從最裏面開始處理。
OK,這樣我們就實現了parameters處理能力
然後我們需要測試一下
爲了進行測試我又重新更改了接口,提供了參數處理的能力,以下是新的接口:
http://cityuit.sinaapp.com/1.php value=將要返回的值
更改下requestMethod方法
+(void)requestMethod:(NSString *)method
URL:(NSString *)URL
parameters:(id) parameters
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
NSString *newURL;
if ([method isEqual:@"GET"]) {
newURL = [[URL stringByAppendingString:@"?"] stringByAppendingString: [LYURLRequestSerialization LYQueryStringFromParameters:parameters]];
NSLog(@"%@",newURL);
}
NSURL *url = [NSURL URLWithString:newURL];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = method;
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *response,NSError *error){
if (error) {
failure(error);
}else{
if (success) {
success(data,response);
}
}
}];
[task resume];
}
其中變化的地方:
if ([method isEqual:@"GET"]) {
newURL = [[URL stringByAppendingString:@"?"] stringByAppendingString: [LYURLRequestSerialization LYQueryStringFromParameters:parameters]];
NSLog(@"%@",newURL);
}
以上代碼的意思就是判斷一下是否未GET請求,如果是的話將處理後的parameters加到尾部,以剛纔的參數爲例子,處理後的newURL爲:http://cityuit.sinaapp.com/1.php?value=LastDays
也就是說返回值爲LastDays
到ViewController.m中進行測試,測試代碼如下:
- (IBAction)test:(id)sender {
id parmenters = @{
@"value":@"LastDays",
};
[LyNetWork requestMethod:@"GET"
URL:@"http://cityuit.sinaapp.com/1.php"
parameters:parmenters
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}
failure:^(NSError *error){
NSLog(@"%@",error);
}];
}
ok返回結果爲LastDays,成功添加入動態的動態的HTTP參數(parameters)的功能。
下一次將會分享POST請求的處理。
一步一步搭建自己的iOS網絡請求庫(三)
大家好,我是LastDay,上一次分享了簡單的封裝,和GET請求。這次帶給大家POST方法
我的博客地址:http://lastday.github.io
POST方法
POST 下很很多協議可提供我們選擇,因爲我們沒有寫文件的上傳,所以我們就採用 application/x-www-form-urlencoded 這種簡單的方式發送請求吧。requestMethod 中進行一些修改,增加POST方法。
代碼如下:
+(void)requestMethod:(NSString *)method
URL:(NSString *)URL
parameters:(id) parameters
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
NSString *newURL;
if ([method isEqual:@"GET"]) {
newURL = [[URL stringByAppendingString:@"?"] stringByAppendingString: [LYURLRequestSerialization LYQueryStringFromParameters:parameters]];
NSLog(@"%@",newURL);
}else{
newURL = URL;
}
NSURL *url = [NSURL URLWithString:newURL];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = method;
if([method isEqual:@"POST"]){
[request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
request.HTTPBody =[[LYURLRequestSerialization LYQueryStringFromParameters:parameters] dataUsingEncoding:NSUTF8StringEncoding];
}
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *response,NSError *error){
if (error) {
failure(error);
}else{
if (success) {
success(data,response);
}
}
}];
[task resume];
}
接下來我們進行測試,原來的那個接口不支持POST請求,爲了測試我就新寫了一個藉口,有兩個參數爲username和password,只有當兩個參數都爲1的時候返回ok,其餘返回no
我們給出POST請求測試代碼:
- (IBAction)test:(id)sender {
NSString *URL = @"http://cityuit.sinaapp.com/p.php";
id parmenters = @{
@"username":@"1",
@"password":@"1"
};
[LyNetWork requestMethod:@"POST"
URL:URL
parameters:parmenters
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}
failure:^(NSError *error){
NSLog(@"%@",error);
}];
}
查看結果爲:
若parmenters爲1,222
id parmenters = @{
@"username":@"1",
@"password":@"222"
};
結果爲:
對LyHttp進行降耦處理
大家好,我是LastDays,這次分享解耦處理,提高代碼的可擴展性,和重用性。
我的博客地址:http://lastday.github.io
原來的那些代碼雖然,看起來比較容易理解,但是最大的問題還是功能太單一,代碼太雜亂了。接下來我們將是用適配器模型來實現獨立於底層結構的網絡API,構造我們自己真正的”庫”
分析NSURLSession
1.構造 NSURLRequest
1.確定 URL
2.確定 HTTP 方法(GET、POST 等)
3.添加特定的 HTTP 頭
4.填充 HTTP Body
2.驅動 [session dataTaskWithRequest] 方法,開始請求
開始搞
新建一個LYHTTPRequestOperationManager類,然後初始化一些參數
#import "LYHTTPRequestOperationManager.h"
#import "LYURLRequestSerialization.h"
@interface LYHTTPRequestOperationManager()
@property(nonatomic,strong) NSString *URL;
@property(nonatomic,strong) NSString *method;
@property(nonatomic,strong) NSDictionary *parameters;
@property(nonatomic,strong) NSMutableURLRequest *request;
@property(nonatomic,strong) NSURLSession *session;
@property(nonatomic,strong) NSURLSessionDataTask *task;
@end
@implementation LYHTTPRequestOperationManager
- (instancetype)initWithMethod:(NSString *)method URL:(NSString *)URL parameters:(id)parameters
{
self = [super init];
if (!self) {
return nil;
}
self.URL = URL;
self.method = method;
self.parameters = parameters;
self.request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URL]];
self.session = [NSURLSession sharedSession];
return self;
}
@end
看看我們剛纔分析東西:
1.構造 NSURLRequest
1.確定 URL
2.確定 HTTP 方法(GET、POST 等)
3.添加特定的 HTTP 頭
4.填充 HTTP Body
根據上面的分析,我們建立一個setRequest函數:
-(void)setRequest{
if ([self.method isEqual:@"GET"]&&self.parameters.count>0) {
self.request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[[self.URL stringByAppendingString:@"?"] stringByAppendingString: [LYURLRequestSerialization LYQueryStringFromParameters:self.parameters]]]];
}
self.request.HTTPMethod = self.method;
if (self.parameters.count>0) {
[self.request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
}
setRequest完成了我們已經分析的前三個步驟
接下來創建setBody函數:
-(void)setBody{
if (self.parameters.count>0&&![self.method isEqual:@"GET"]) {
self.request.HTTPBody = [[LYURLRequestSerialization LYQueryStringFromParameters:self.parameters] dataUsingEncoding:NSUTF8StringEncoding];
}
}
setBody就是完成了我們最後一個步驟
以上處理完成了構造 NSURLRequest
我們該進行驅動 [session dataTaskWithRequest] 方法,開始請求
-(void)driveTask:(void(^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
[self setRequest];
[self setBody];
[self setTaskWithSuccess:success failure:failure];
}
採用適配器模式封裝LyHttp
簡單的來介紹一下適配器的概念:
適配器模式,可以這麼說,用於連接兩種不同種類的對象,使其毫無問題地協同工作。思想其實非常的簡單。適配器實現客戶端需要的某種接口的行爲。同時它又連接到另一個具有不同行爲的對象。一邊是客戶端懂得如何使用的目標接口,另一邊還客戶端一無所知的適配者,適配器站在兩者中間。適配器主要的作用是把適配者的行爲傳遞給管道另一端的客戶端,其實這種所謂的很高大賞的適配器模型很多人其實已經使用過了
接下來就是來修改我們的LyNetWork
封裝多級API
不帶parameters:
+(void)requestWithMethod:(NSString *)method
URL:(NSString *)URL
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
LYHTTPRequestOperationManager *manange = [[LYHTTPRequestOperationManager alloc] initWithMethod:method URL:URL parameters:nil];
[manange driveTask:success failure:failure];
}
不帶parameters的GET方法:
+(void)requestGetWithURL:(NSString *)URL
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
LYHTTPRequestOperationManager *manange = [[LYHTTPRequestOperationManager alloc] initWithMethod:@"GET" URL:URL parameters:nil];
[manange driveTask:success failure:failure];
}
帶parameters的GET方法:
//GET帶parameters
+(void)requestGetWithURL:(NSString *)URL
parameters:(id) parameters
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
LYHTTPRequestOperationManager *manange = [[LYHTTPRequestOperationManager alloc] initWithMethod:@"GET" URL:URL parameters:parameters];
[manange driveTask:success failure:failure];
}
POST不帶parameters
+(void)requestPostWithURL:(NSString *)URL
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
LYHTTPRequestOperationManager *manange = [[LYHTTPRequestOperationManager alloc] initWithMethod:@"POST" URL:URL parameters:nil];
[manange driveTask:success failure:failure];
}
POST帶parameters
+(void)requestPostWithURL:(NSString *)URL
parameters:(id) parameters
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
LYHTTPRequestOperationManager *manange = [[LYHTTPRequestOperationManager alloc] initWithMethod:@"POST" URL:URL parameters:parameters];
[manange driveTask:success failure:failure];
}
接下來就是進入我們的修改ViewController代碼進行測試:
- (IBAction)test:(id)sender {
NSString *postURL = @"http://cityuit.sinaapp.com/p.php";
NSString *getURL= @"http://cityuit.sinaapp.com/1.php";
id parmentersPost = @{
@"username":@"1",
@"password":@"1"
};
id parmentersGet = @{
@"value":@"Lastday",
};
[LyNetWork requestWithMethod:@"POST"
URL:@"http://cityuit.sinaapp.com/1.php?value=Lastday"
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"requestWithMethod = %@",string);
}
failure:^(NSError *error){
NSLog(@"====%@",error);
}];
[LyNetWork requestPostWithURL:postURL
parameters:parmentersPost
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"requestPostWithURL(帶參數) = %@",string);
}
failure:^(NSError *error){
}];
[LyNetWork requestPostWithURL:postURL
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"requestPostWithURL(不帶參數) = %@",string);
}
failure:^(NSError *error){
}];
[LyNetWork requestGetWithURL:getURL
parameters:parmentersGet
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"requestGetWithURL(帶參數) = %@",string);
}
failure:^(NSError *error){
}];
[LyNetWork requestGetWithURL:getURL
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"requestGetWithURL(不帶參數) = %@",string);
}
failure:^(NSError *error){
}];
}
看一下執行結果