I implemented login method in this way:
我用这种方式实现了login方法:
[KVNProgress show];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//some error handling like:
if ([_usernameField.text length] < 4) {
[KVNProgress showErrorWithStatus:@"Username too short!"];
_passwordField.text = @"";
return;
}
//Then I call login web service synchronously here:
result = [ServerRequests login];
dispatch_async(dispatch_get_main_queue(), ^{
if(!result)
{
[KVNProgress showErrorWithStatus:@"problem!" completion:NULL];
_passwordField.text = @"";
}
else if([result.successful boolValue])
{
[KVNProgress showSuccessWithStatus:result.message];
}
});
});
It crashed mostly and by surrounding blocks with only Main Queue (no priority default one) that solved! but the problem is:KVNProgress is only showing in error handling area not the next part that we call web service. It's not user friendly at all! Any idea is welcomed :)
它主要是由周围的块崩溃而只有主队列(没有优先级默认值)解决了!但问题是:KVNProgress只在错误处理区域显示而不是我们称之为Web服务的下一部分。它根本不是用户友好的!欢迎任何想法:)
1 个解决方案
#1
0
You MUST call methods that update the user interface in any way from the main thread, as per the UIKit
documentation:
根据UIKit文档,您必须调用以任何方式从主线程更新用户界面的方法:
For the most part, use UIKit classes only from your app’s main thread. This is particularly true for classes derived from UIResponder or that involve manipulating your app’s user interface in any way.
在大多数情况下,只能从应用程序的主线程中使用UIKit类。对于从UIResponder派生的类或者涉及以任何方式操纵应用程序的用户界面的类尤其如此。
I suggest you try to limit the number of callbacks you make to the main thread, so therefore you want to batch as much user interface updates together as you can.
我建议你尝试限制你对主线程的回调数量,因此你想要尽可能多地批量处理用户界面更新。
Then all you have to do, as you correctly say, is to use a dispatch_async
to callback to your main thread whenever you need to update the UI, from within your background processing.
然后,正如您所说的那样,您需要做的就是在需要更新UI时使用dispatch_async回调主线程,在后台处理中。
Because it's asynchronous, it won't interrupt your background processing, and should have a minimal interruption on the main thread itself as updating values on most UIKit
components is fairly cheap, they'll just update their value and trigger their setNeedsDisplay
so that they'll get re-drawn at the next run loop.
因为它是异步的,它不会中断你的后台处理,并且主线程本身应该有一个最小的中断,因为大多数UIKit组件的更新值相当便宜,它们只是更新它们的值并触发它们的setNeedsDisplay以便它们'将在下一个运行循环中重新绘制。
From your code, it looks like your issue is that you're calling this from the background thread:
从您的代码中,您的问题似乎是您从后台线程调用它:
if ([_usernameField.text length] < 4) {
[KVNProgress showErrorWithStatus:@"Username too short!"];
_passwordField.text = @"";
return;
}
This is 100% UI updating code, and should therefore take place on the main thread.
这是100%的UI更新代码,因此应该在主线程上进行。
Although, I have no idea about the thread safety of KVNProgress
, I assume it should also be called on the main thread as it's presenting an error to the user.
虽然,我不知道KVNProgress的线程安全性,但我认为它也应该在主线程上调用,因为它向用户呈现错误。
Your code therefore should look something like this (assuming it's taking place on the main thread to begin with):
因此,您的代码应该看起来像这样(假设它开始在主线程上发生):
[KVNProgress show];
//some error handling like:
if ([_usernameField.text length] < 4) {
[KVNProgress showErrorWithStatus:@"Username too short!"];
_passwordField.text = @"";
return;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Then I call login web service synchronously here:
result = [ServerRequests login];
dispatch_async(dispatch_get_main_queue(), ^{
if(!result) {
[KVNProgress showErrorWithStatus:@"problem!" completion:NULL];
_passwordField.text = @"";
} else if([result.successful boolValue]) {
[KVNProgress showSuccessWithStatus:result.message];
}
});
});
#1
0
You MUST call methods that update the user interface in any way from the main thread, as per the UIKit
documentation:
根据UIKit文档,您必须调用以任何方式从主线程更新用户界面的方法:
For the most part, use UIKit classes only from your app’s main thread. This is particularly true for classes derived from UIResponder or that involve manipulating your app’s user interface in any way.
在大多数情况下,只能从应用程序的主线程中使用UIKit类。对于从UIResponder派生的类或者涉及以任何方式操纵应用程序的用户界面的类尤其如此。
I suggest you try to limit the number of callbacks you make to the main thread, so therefore you want to batch as much user interface updates together as you can.
我建议你尝试限制你对主线程的回调数量,因此你想要尽可能多地批量处理用户界面更新。
Then all you have to do, as you correctly say, is to use a dispatch_async
to callback to your main thread whenever you need to update the UI, from within your background processing.
然后,正如您所说的那样,您需要做的就是在需要更新UI时使用dispatch_async回调主线程,在后台处理中。
Because it's asynchronous, it won't interrupt your background processing, and should have a minimal interruption on the main thread itself as updating values on most UIKit
components is fairly cheap, they'll just update their value and trigger their setNeedsDisplay
so that they'll get re-drawn at the next run loop.
因为它是异步的,它不会中断你的后台处理,并且主线程本身应该有一个最小的中断,因为大多数UIKit组件的更新值相当便宜,它们只是更新它们的值并触发它们的setNeedsDisplay以便它们'将在下一个运行循环中重新绘制。
From your code, it looks like your issue is that you're calling this from the background thread:
从您的代码中,您的问题似乎是您从后台线程调用它:
if ([_usernameField.text length] < 4) {
[KVNProgress showErrorWithStatus:@"Username too short!"];
_passwordField.text = @"";
return;
}
This is 100% UI updating code, and should therefore take place on the main thread.
这是100%的UI更新代码,因此应该在主线程上进行。
Although, I have no idea about the thread safety of KVNProgress
, I assume it should also be called on the main thread as it's presenting an error to the user.
虽然,我不知道KVNProgress的线程安全性,但我认为它也应该在主线程上调用,因为它向用户呈现错误。
Your code therefore should look something like this (assuming it's taking place on the main thread to begin with):
因此,您的代码应该看起来像这样(假设它开始在主线程上发生):
[KVNProgress show];
//some error handling like:
if ([_usernameField.text length] < 4) {
[KVNProgress showErrorWithStatus:@"Username too short!"];
_passwordField.text = @"";
return;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Then I call login web service synchronously here:
result = [ServerRequests login];
dispatch_async(dispatch_get_main_queue(), ^{
if(!result) {
[KVNProgress showErrorWithStatus:@"problem!" completion:NULL];
_passwordField.text = @"";
} else if([result.successful boolValue]) {
[KVNProgress showSuccessWithStatus:result.message];
}
});
});