如何使用 activity 指标进行 Web 服务登录
How to use an activity indicator for web service login
我刚刚创建了一个使用 Web 服务的 iOS 应用程序,我的问题是当我在视图控制器中点击登录时处于空闲状态,不显示 activity 指示器,但是当响应和数据来自获取网络服务并加载下一个视图控制器; activity 指示符很快出现。我希望在点击登录按钮时 activity 指示器可见
代码示例:
NSString *username = TextUsername.text;
NSString *password = Textpassword.text;
NSString *strLogInUrl=[NSString stringWithFormat:@""];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSLog(@"Url %@",strLogInUrl);
NSURL *URLGet = [NSURL URLWithString:strLogInUrl];
NSData *data = [NSData dataWithContentsOfURL:URLGet];
NSError* error;
DicForAllData = [NSJSONSerialization JSONObjectWithData: data options:kNilOptions error:&error];
听起来您正在使用同步代码登录。如果您这样做:
display activity indicator
log in (synchronously)
hide activity indicator
然后 activity 指标永远没有机会显示。 (UI 直到您的代码 returns 并且应用程序访问事件循环后,更改才会呈现到屏幕上。)
您应该更改登录代码以异步工作(最佳选择)或重写代码以访问显示 activity 指示器和登录之间的事件循环。伪代码可能如下所示:
display activity indicator
[self performSelector: @selector(login) withObject: nil afterDelay: 0];
以及您的登录方法伪代码:
- (void) login;
{
log in (synchronously)
hide activity indicator
}
(performSelector:withObject:afterDelay:
不会立即执行来自选择器的代码。相反,它会在下次应用程序访问事件循环时排队调用您的选择器。您的代码在系统之后被调用有机会更新屏幕{具体来说,在它有机会显示您的 activity 指标之后}。)
一旦您点击登录按钮,在调用 Web 服务调用 activity 指示器之前以及在第二次调用 Web 服务之后,activity 指示器将是 shown/displayed。收到响应后,首先停止 activity 指示器,然后推送到下一个视图控制器。
记得在进入下一个屏幕之前关闭键盘。这是一个很好的做法。
正如其他人所指出的,要让 UI 更新,您需要异步执行此操作。在我向您介绍一些细节之前,让我们考虑一下您问题中代码的高级抽象:
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSData *data = [NSData dataWithContentsOfURL:URLGet];
// do something with data
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
你真的想发出一个异步请求,而不是那个同步请求:
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSMutableURLRequest *request = ...;
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// handle the data or connectionError here, inside this block, and remember to turn off activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}];
问题是,您的代码片段没有正确创建请求。你过度简化了这个过程。你的过程真的还应该考虑:
如果您要提供凭据,那通常是 POST
请求,而不是 dataWithContentsOfURL
执行的简单 GET
。
你真的应该构建一个合适的 application/x-www-form-urlencoded
请求。
您必须对传递给服务器的数据进行百分比转义(否则,如果密码恰好包含某些保留字符,例如 +
或 &
,登录将失败)。
你真的应该处理错误。
将所有这些放在一起,看起来更像:
// tell the user we're going to do this request for them
// maybe show a `UIActivityIndicatorView`, too
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
// construct the body of the request; replace the keys `username` and `password` with whatever your web service requires
NSString *username = textUsername.text;
NSString *password = textPassword.text;
NSString *parameterString = [NSString stringWithFormat:@"username=%@&password=%@", [self percentEscapeString:username], [self percentEscapeString:password]];
NSData *httpBody = [parameterString dataUsingEncoding:NSUTF8StringEncoding];
// now create the request itself
NSString *strLogInUrl = @"http://example.com";
NSURL *URLGet = [NSURL URLWithString:strLogInUrl];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URLGet];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:httpBody];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
// now send the request
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (!data) {
NSLog(@"connectionError: %@", connectionError);
} else {
NSError* error;
dicForAllData = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
// do what you want with the data/error here, e.g. `[self.tableView reloadData]` or whatever
}
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}];
假设您有一个百分比转义例程,例如:
- (NSString *)percentEscapeString:(NSString *)string
{
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)string,
(CFStringRef)@" ",
(CFStringRef)@":/?@!$&'()*+,;=",
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:@" " withString:@"+"];
}
早些时候,UnicoRahul 询问您是否使用 AFNetworking。值得考虑,因为它大大简化了您必须编写的代码:
NSDictionary *params = @{@"username": username, @"password": password};
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:@"http://example.com" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
dicForAllData = responseObject;
// do what you want with the data here, e.g. `[self.tableView reloadData]` or whatever
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"%@", error);
}];
我刚刚创建了一个使用 Web 服务的 iOS 应用程序,我的问题是当我在视图控制器中点击登录时处于空闲状态,不显示 activity 指示器,但是当响应和数据来自获取网络服务并加载下一个视图控制器; activity 指示符很快出现。我希望在点击登录按钮时 activity 指示器可见
代码示例:
NSString *username = TextUsername.text;
NSString *password = Textpassword.text;
NSString *strLogInUrl=[NSString stringWithFormat:@""];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSLog(@"Url %@",strLogInUrl);
NSURL *URLGet = [NSURL URLWithString:strLogInUrl];
NSData *data = [NSData dataWithContentsOfURL:URLGet];
NSError* error;
DicForAllData = [NSJSONSerialization JSONObjectWithData: data options:kNilOptions error:&error];
听起来您正在使用同步代码登录。如果您这样做:
display activity indicator
log in (synchronously)
hide activity indicator
然后 activity 指标永远没有机会显示。 (UI 直到您的代码 returns 并且应用程序访问事件循环后,更改才会呈现到屏幕上。)
您应该更改登录代码以异步工作(最佳选择)或重写代码以访问显示 activity 指示器和登录之间的事件循环。伪代码可能如下所示:
display activity indicator
[self performSelector: @selector(login) withObject: nil afterDelay: 0];
以及您的登录方法伪代码:
- (void) login;
{
log in (synchronously)
hide activity indicator
}
(performSelector:withObject:afterDelay:
不会立即执行来自选择器的代码。相反,它会在下次应用程序访问事件循环时排队调用您的选择器。您的代码在系统之后被调用有机会更新屏幕{具体来说,在它有机会显示您的 activity 指标之后}。)
一旦您点击登录按钮,在调用 Web 服务调用 activity 指示器之前以及在第二次调用 Web 服务之后,activity 指示器将是 shown/displayed。收到响应后,首先停止 activity 指示器,然后推送到下一个视图控制器。
记得在进入下一个屏幕之前关闭键盘。这是一个很好的做法。
正如其他人所指出的,要让 UI 更新,您需要异步执行此操作。在我向您介绍一些细节之前,让我们考虑一下您问题中代码的高级抽象:
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSData *data = [NSData dataWithContentsOfURL:URLGet];
// do something with data
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
你真的想发出一个异步请求,而不是那个同步请求:
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSMutableURLRequest *request = ...;
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// handle the data or connectionError here, inside this block, and remember to turn off activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}];
问题是,您的代码片段没有正确创建请求。你过度简化了这个过程。你的过程真的还应该考虑:
如果您要提供凭据,那通常是
POST
请求,而不是dataWithContentsOfURL
执行的简单GET
。你真的应该构建一个合适的
application/x-www-form-urlencoded
请求。您必须对传递给服务器的数据进行百分比转义(否则,如果密码恰好包含某些保留字符,例如
+
或&
,登录将失败)。你真的应该处理错误。
将所有这些放在一起,看起来更像:
// tell the user we're going to do this request for them
// maybe show a `UIActivityIndicatorView`, too
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
// construct the body of the request; replace the keys `username` and `password` with whatever your web service requires
NSString *username = textUsername.text;
NSString *password = textPassword.text;
NSString *parameterString = [NSString stringWithFormat:@"username=%@&password=%@", [self percentEscapeString:username], [self percentEscapeString:password]];
NSData *httpBody = [parameterString dataUsingEncoding:NSUTF8StringEncoding];
// now create the request itself
NSString *strLogInUrl = @"http://example.com";
NSURL *URLGet = [NSURL URLWithString:strLogInUrl];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URLGet];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:httpBody];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
// now send the request
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (!data) {
NSLog(@"connectionError: %@", connectionError);
} else {
NSError* error;
dicForAllData = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
// do what you want with the data/error here, e.g. `[self.tableView reloadData]` or whatever
}
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}];
假设您有一个百分比转义例程,例如:
- (NSString *)percentEscapeString:(NSString *)string
{
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)string,
(CFStringRef)@" ",
(CFStringRef)@":/?@!$&'()*+,;=",
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:@" " withString:@"+"];
}
早些时候,UnicoRahul 询问您是否使用 AFNetworking。值得考虑,因为它大大简化了您必须编写的代码:
NSDictionary *params = @{@"username": username, @"password": password};
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:@"http://example.com" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
dicForAllData = responseObject;
// do what you want with the data here, e.g. `[self.tableView reloadData]` or whatever
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"%@", error);
}];