PerformSelectorOnMainThread 导致“无法识别的选择器发送到实例”
首先,提前感谢您抽出时间查看这个问题。
我正在尝试创建一个非常简单的 UIViewController 示例,其中我在线程中加载数据。该线程正在被调用,但从该线程中,我无法返回主线程。 下面的测试用例非常简单,我在 XCode 中创建一个基于视图的应用程序,然后添加了 NSOperationQueue 代码。希望有人能很快发现我的小学生错误:)
委托非常简单,.h 是:
#import<UIKit/UIKit.h>
@class ViewbasedViewController;
@interface ViewbasedAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
ViewbasedViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet ViewbasedViewController *viewController;
@end
.m 同样简单:
#import "ViewbasedAppDelegate.h"
#import "ViewbasedViewController.h"
@implementation ViewbasedAppDelegate
@synthesize window;
@synthesize viewController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Set the view controller as the window's root view controller and display.
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
现在回答问题。我想在加载视图时运行一个线程。 我在 viewcontroller.h 文件中定义了一个 NSOperationQueue:
@interface ViewbasedViewController : UIViewController {
NSOperationQueue *folderQueue;
}
在我的 viewcontroller.m 中,我想在加载视图后在线程中运行一些代码。因此,在 viewDidLoad 中,我向队列添加了一个操作:
- (void)viewDidLoad {
[super viewDidLoad];
// create a thread and run it
folderQueue = [[NSOperationQueue alloc] init];
folderQueue.maxConcurrentOperationCount = 1;
NSLog(@"about to run thread");
[folderQueue addOperation:[[[NSInvocationOperation alloc]
initWithTarget:self selector:@selector(MyThreadedCode)
object:nil] autorelease]];
}
函数“MyThreadedCode”被调用,我可以在控制台中看到调试。
-(void)MyThreadedCode
{
NSLog(@"Start of thread");
[self performSelectorOnMainThread:@selector(reloadMyData) withObject:nil WaitUntilDone:YES];
// [self reloadMyData];
NSLog(@"CALLED REFRESH");
}
-(void)reloadMyData
{
NSLog(@"Request to reloadData");
}
但是...如果从我的线程中尝试调用主线程上的选择器(例如我可能想在表视图中重新加载数据),我会得到一个异常。只有当我使用 PerformanceSelectorOnMainThread 运行它时我才会得到这个。 如果我运行
[self reloadMyData];
控制台看起来不错:
[Session started at 2011-09-06 13:56:50 +0100.]
2011-09-06 13:56:52.258 Viewbased[1618:207] about to run thread
2011-09-06 13:56:52.266 Viewbased[1618:5d03] Start of thread
2011-09-06 13:56:52.270 Viewbased[1618:5d03] Request to reloadData
2011-09-06 13:56:52.272 Viewbased[1618:5d03] CALLED REFRESH
如果我使用
[self performSelectorOnMainThread:@selector(reloadMyData) withObject:nil WaitUntilDone:YES];
我会得到一个无法识别的选择器:
[Session started at 2011-09-06 13:29:14 +0100.]
2011-09-06 13:29:26.216 Viewbased[1581:207] about to run thread
2011-09-06 13:29:26.224 Viewbased[1581:5d03] Start of thread
2011-09-06 13:29:26.228 Viewbased[1581:5d03] -[ViewbasedViewController performSelectorOnMainThread:withObject:WaitUntilDone:]: unrecognized selector sent to instance 0x4e43060
2011-09-06 13:29:26.235 Viewbased[1581:5d03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ViewbasedViewController performSelectorOnMainThread:withObject:WaitUntilDone:]: unrecognized selector sent to instance 0x4e43060'
*** Call stack at first throw:
(
0 CoreFoundation 0x00eab5a9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x00cda313 objc_exception_throw + 44
2 CoreFoundation 0x00ead0bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00e1c966 ___forwarding___ + 966
4 CoreFoundation 0x00e1c522 _CF_forwarding_prep_0 + 50
5 Viewbased 0x000024c3 -[ViewbasedViewController MyThreadedCode] + 78
6 CoreFoundation 0x00e1bc7d __invoking___ + 29
7 CoreFoundation 0x00e1bb51 -[NSInvocation invoke] + 145
8 Foundation 0x000d9495 -[NSInvocationOperation main] + 51
9 Foundation 0x00047b76 -[__NSOperationInternal start] + 747
10 Foundation 0x000477ca ____startOperations_block_invoke_2 + 106
11 libdispatch_sim.dylib 0x01628289 _dispatch_call_block_and_release + 16
12 libdispatch_sim.dylib 0x0162b58a _dispatch_worker_thread2 + 252
13 libSystem.B.dylib 0x9557e781 _pthread_wqthread + 390
14 libSystem.B.dylib 0x9557e5c6 start_wqthread + 30
)
terminate called after throwing an instance of 'NSException'
我确信它是一些愚蠢的东西我错了但我看不到它!
Firstly thanks in advance for your time looking at this question.
I'm trying to create a very simple UIViewController example, where I load the data in a thread. The thread is getting called but from that thread, I can't get back to the main thread.
The test case below is extremely simple, I create a View based application in XCode and just added the NSOperationQueue code. Hopefully someone can quickly spot my schoolboy error :)
The delegate is very simple, .h is:
#import<UIKit/UIKit.h>
@class ViewbasedViewController;
@interface ViewbasedAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
ViewbasedViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet ViewbasedViewController *viewController;
@end
And the .m is equally simple:
#import "ViewbasedAppDelegate.h"
#import "ViewbasedViewController.h"
@implementation ViewbasedAppDelegate
@synthesize window;
@synthesize viewController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Set the view controller as the window's root view controller and display.
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Now to the question. I want to run a thread when the view is loaded.
I've defined an NSOperationQueue in my viewcontroller.h file:
@interface ViewbasedViewController : UIViewController {
NSOperationQueue *folderQueue;
}
And in my view controller.m, I want to run some code in a thread once the view is loaded. So inside viewDidLoad I add an operation to a queue:
- (void)viewDidLoad {
[super viewDidLoad];
// create a thread and run it
folderQueue = [[NSOperationQueue alloc] init];
folderQueue.maxConcurrentOperationCount = 1;
NSLog(@"about to run thread");
[folderQueue addOperation:[[[NSInvocationOperation alloc]
initWithTarget:self selector:@selector(MyThreadedCode)
object:nil] autorelease]];
}
The function "MyThreadedCode" gets called ok, I can see the debug in the console.
-(void)MyThreadedCode
{
NSLog(@"Start of thread");
[self performSelectorOnMainThread:@selector(reloadMyData) withObject:nil WaitUntilDone:YES];
// [self reloadMyData];
NSLog(@"CALLED REFRESH");
}
-(void)reloadMyData
{
NSLog(@"Request to reloadData");
}
BUT...if, from my thread, I try and call a selector on the main thread (for instance I may want to reload data in a tableview), I get an exception. I only get this if I run it using performanceSelectorOnMainThread.
If I run
[self reloadMyData];
The console looks good:
[Session started at 2011-09-06 13:56:50 +0100.]
2011-09-06 13:56:52.258 Viewbased[1618:207] about to run thread
2011-09-06 13:56:52.266 Viewbased[1618:5d03] Start of thread
2011-09-06 13:56:52.270 Viewbased[1618:5d03] Request to reloadData
2011-09-06 13:56:52.272 Viewbased[1618:5d03] CALLED REFRESH
If I use
[self performSelectorOnMainThread:@selector(reloadMyData) withObject:nil WaitUntilDone:YES];
I get an unrecognized selector:
[Session started at 2011-09-06 13:29:14 +0100.]
2011-09-06 13:29:26.216 Viewbased[1581:207] about to run thread
2011-09-06 13:29:26.224 Viewbased[1581:5d03] Start of thread
2011-09-06 13:29:26.228 Viewbased[1581:5d03] -[ViewbasedViewController performSelectorOnMainThread:withObject:WaitUntilDone:]: unrecognized selector sent to instance 0x4e43060
2011-09-06 13:29:26.235 Viewbased[1581:5d03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ViewbasedViewController performSelectorOnMainThread:withObject:WaitUntilDone:]: unrecognized selector sent to instance 0x4e43060'
*** Call stack at first throw:
(
0 CoreFoundation 0x00eab5a9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x00cda313 objc_exception_throw + 44
2 CoreFoundation 0x00ead0bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00e1c966 ___forwarding___ + 966
4 CoreFoundation 0x00e1c522 _CF_forwarding_prep_0 + 50
5 Viewbased 0x000024c3 -[ViewbasedViewController MyThreadedCode] + 78
6 CoreFoundation 0x00e1bc7d __invoking___ + 29
7 CoreFoundation 0x00e1bb51 -[NSInvocation invoke] + 145
8 Foundation 0x000d9495 -[NSInvocationOperation main] + 51
9 Foundation 0x00047b76 -[__NSOperationInternal start] + 747
10 Foundation 0x000477ca ____startOperations_block_invoke_2 + 106
11 libdispatch_sim.dylib 0x01628289 _dispatch_call_block_and_release + 16
12 libdispatch_sim.dylib 0x0162b58a _dispatch_worker_thread2 + 252
13 libSystem.B.dylib 0x9557e781 _pthread_wqthread + 390
14 libSystem.B.dylib 0x9557e5c6 start_wqthread + 30
)
terminate called after throwing an instance of 'NSException'
I'm sure its something stupid I've got wrong but I can't see it for looking!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
大写字母很重要。
WaitUntilDone:
应该是waitUntilDone:
:Capitalization is important.
WaitUntilDone:
should bewaitUntilDone:
:尝试使用@selector 在下面一行:
Try below line with @selector: