先解釋一下下面代碼的做用:後端
整個方法是判斷是否登錄成功並返回判斷結果。網絡
使用JSON格式的數據發送帳號密碼到後端,並獲得一個JSON,裏面包括登錄是否成功的信息,LoginState爲0成功,其餘爲失敗session
其中NSURLSessionDataTask是異步執行的app
疑問在註釋中異步
-(NSInteger)postLoginJson:(NSString *)url withStuid:(NSString *)stuid withPwd:(NSString *)pwd{函數
NSDictionary *dic = @{@"stuid":stuid,@"pwd":pwd};post
NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];ui
NSURL *URL = [NSURL URLWithString:url];url
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];spa
[request setHTTPMethod:@"POST"];
[request setValue:@"application/jason" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:data];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data,NSURLResponse *response,NSError *error){
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//其中 setBool 有bug
NSLog(@"loginState:%@",dic[@"loginState"]); //這是一個輸出,返回狀態值。
if([dic[@"loginState"] integerValue] == 0){
[userDefaults setInteger:0 forKey:@"tempBool"];
[userDefaults synchronize];
}
else{
[userDefaults setInteger:1 forKey:@"tempBool"];
[userDefaults synchronize];
}
}];
[task resume];
while ([task state] != NSURLSessionTaskStateCompleted) {
NSLog(@"state %ld",(long)[task state]);//這也是一個輸出,當未完成時,一直輸出。
} //此段代碼是爲了讓任務完成後再往下執行,但不管如何,都是先輸出willReturn而不是loginState
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSInteger willReturn = [userDefaults integerForKey:@"tempBool"];
NSLog(@"willReturn %ld",(long)willReturn);//這是函數返回值
[userDefaults removeObjectForKey:@"tempBool"];
[userDefaults synchronize];
//NSLog(willReturn);
return willReturn;
}
最終輸出的結果就是:
先是一堆 while中的state
而後willReturn
而後loginState
按道理不是應該先loginState先輸出嗎?
3月21日更新
雖然加入了while等待任務完成,但這個任務指的是數據下載任務,也就是當收到登錄狀態返回值以後,此任務就爲completed狀態了,可是complationHandler中的指令這時纔開始執行,而且是異步的,因此此while沒用,最後的解決辦法是把這個函數放在了LoginViewContorller,直接在complationHandler中執行相關UI更新。
目前找不到斷定complationHandler運行狀態的方法。
3月22日更新
從NSURLSessionDataTaskDelegate下手完全解決了這個問題。仍能夠封裝網絡訪問爲一個model,爲NSURLSessionDataTask傳入代理指針,LoginViewController實現代理便可。
代碼
VisitWeb.m
-(void)getJson:(NSString *)url withCurrentController:(id)delegate{
NSURLSessionConfiguration* ephConfiguration=[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession* session=[NSURLSession sessionWithConfiguration:ephConfiguration delegate:delegate delegateQueue:[NSOperationQueue mainQueue]];
NSURL* URL=[NSURL URLWithString:url];
NSURLSessionDataTask* dataTask=[session dataTaskWithURL:URL];
[dataTask resume];
}
在相應文件裏新建實例並設置代理便可。
VisitToGetJson *vj = [[VisitToGetJson alloc]init];
[vj getJson:@"http://120.27.120.48/stucard" withCurrentController:self];