我在我的项目中使用MBPogressHUD,并且我已正确设置了所有库,导入等。但是,我遇到的崩溃似乎与选择器方法有关。我有一个名为“getInfo”的方法,它基本上连接到服务器。按下按钮即可触发HUD。在对崩溃进行一些研究后,人们说将初始化放在viewWillAppear中,因为一些初始化时间占用了实际执行任务并显示HUD所需的时间。
-(void)viewWillAppear:(BOOL)animated {
connectionHUD = [[MBProgressHUD alloc]initWithView:self.view];
[self.view addSubview:connectionHUD];
connectionHUD.labelText = @"Connecting";
connectionHUD.mode = MBProgressHUDModeAnnularDeterminate;
}
-(IBAction)connectButton:(id)sender {
[connectionHUD showWhileExecuting:@selector(getInfo) onTarget:self withObject:nil animated:YES];
}
崩溃:
Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
-(void)getInfo {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
UserPi *newPi = [[UserPi alloc]init];
newPi.passWord = self.passTextField.text;
[defaults setObject:self.passTextField.text forKey:@"password"];
newPi.userName = self.userTextField.text;
[defaults setObject:self.userTextField.text forKey:@"username"];
newPi.ipAddress = self.ipTextField.text;
[defaults setObject:self.ipTextField.text forKey:@"ip"];
[newPi connectToServer];
NSString* newAddress = [newPi returnIP];
self.connected = newPi.connected;
[self.delegate sendIP:newAddress];
[self.delegate isConnected:self.connected];
[defaults synchronize];
[self.navigationController popToRootViewControllerAnimated:YES];
}
完整错误:
bool _WebTryThreadLock(bool), 0x7327740: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
1 0x3a1ffe9 WebThreadLock
2 0x4ec8ff -[UITextRangeImpl isEmpty]
3 0x4ec4db -[UITextRange(UITextInputAdditions) _isCaret]
4 0x48e7b6 -[UITextSelectionView setCaretBlinks:]
5 0x328f79 -[UIKeyboardImpl setCaretBlinks:]
6 0x3185bc -[UIKeyboardImpl setDelegate:force:]
7 0x3184ae -[UIKeyboardImpl setDelegate:]
8 0x53ff65 -[UIPeripheralHost(UIKitInternal) _reloadInputViewsForResponder:]
9 0x29215b -[UINavigationController navigationTransitionView:didStartTransition:]
10 0x418961 -[UINavigationTransitionView transition:fromView:toView:]
11 0x418658 -[UINavigationTransitionView transition:toView:]
12 0x294651 -[UINavigationController _startTransition:fromViewController:toViewController:]
13 0x29489b -[UINavigationController _startDeferredTransitionIfNeeded:]
14 0x295dc6 _popViewControllerNormal
15 0x296065 -[UINavigationController _popViewControllerWithTransition:allowPoppingLast:]
16 0xe6124b0 -[UINavigationControllerAccessibility(SafeCategory) _popViewControllerWithTransition:allowPoppingLast:]
17 0x2961a8 -[UINavigationController popViewControllerWithTransition:]
18 0x2965b9 -[UINavigationController popToViewController:transition:]
19 0x296257 -[UINavigationController popToRootViewControllerWithTransition:]
20 0x2961de -[UINavigationController popToRootViewControllerAnimated:]
21 0x4868 -[ConnectionViewController getInfo]
22 0x126a6b0 -[NSObject performSelector:withObject:]
23 0x8657 -[MBProgressHUD launchExecution]
24 0xca1805 -[NSThread main]
25 0xca1764 __NSThread__main__
26 0x95108ed9 _pthread_start
27 0x9510c6de thread_start
答案 0 :(得分:1)
大多数UIKit框架方法都不是线程安全的,必须始终在主线程上调用。在您的情况下,getInfo
正在从后台线程调用UIKit API,-[UINavigationController popToRootViewControllerAnimated:]
MBProgressHUD会导致您在后台线程上调用getInfo
。请参阅方法showWhileExecuting:onTarget:withObject:animated:
。
尝试使用GCD在主线程上调度UIKit方法:
-(void)getInfo {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
UserPi *newPi = [[UserPi alloc]init];
newPi.passWord = self.passTextField.text;
[defaults setObject:self.passTextField.text forKey:@"password"];
newPi.userName = self.userTextField.text;
[defaults setObject:self.userTextField.text forKey:@"username"];
newPi.ipAddress = self.ipTextField.text;
[defaults setObject:self.ipTextField.text forKey:@"ip"];
[newPi connectToServer];
NSString* newAddress = [newPi returnIP];
self.connected = newPi.connected;
// **NOTE**
// PS: self.delegate methods should not call UIKit methods
// if they do, then move them into the main thread callback block
[self.delegate sendIP:newAddress];
[self.delegate isConnected:self.connected];
[defaults synchronize];
// Do UI work on main thread.
dispatch_async(dispatch_get_main_queue(), ^{
[self.navigationController popToRootViewControllerAnimated:YES];
});
}
答案 1 :(得分:1)
您是否在主线程上调用-getInfo
?必须在主线程上调用[self.navigationController popToRootViewControllerAnimated:YES];
。
答案 2 :(得分:0)
问题是您的getInfo
方法会调用UI,如下所示:
[self.navigationController popToRootViewControllerAnimated:YES];
...但你是在后台线程上运行它。
-showWhileExecuting: onTarget: withObject: animated:
的重点是它会在后台线程中自动运行您的代码。
因此,您需要以与在后台线程中手动运行时相同的方式保护事物。
因此,您的方法中的任何UI代码都需要使用performSelectorOnMainThread:
和朋友,或dispatch_async
或其他方法来执行相同操作。
在这种特殊情况下,您希望调度一个采用原始(BOOL
)参数的方法,这意味着您不能只使用-performSelectorOnMainThread: withObject:
。但是你也可能想要等到它完成,这意味着你不能只使用dispatch_async
。
你可以编写一个不带参数的包装器方法:
- (void)popNavigationControllerToRoot {
[self.navigationController popToRootViewControllerAnimated:YES];
}
......然后:
[self performSelectorOnMainThread:@selector(popNavigationControllerToRoot)
waitUntilDone:YES];
或者您可以使用NSInvocation
周围的包装,就像那些here:
[[self.navigationController dd_invokeOnMainThreadAndWaitUntilDone:YES]
popToRootViewControllerAnimated:YES];