【问题标题】:performSelectorOnMainThread results in "unrecognized selector sent to instance"performSelectorOnMainThread 导致“发送到实例的选择器无法识别”
【发布时间】:2011-09-06 13:42:03
【问题描述】:

首先感谢您抽出宝贵的时间来研究这个问题。

我正在尝试创建一个非常简单的 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;
}

在我的视图 controller.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'

我确定它有些愚蠢,我错了,但我看不到它!

【问题讨论】:

    标签: iphone objective-c uitableview nsoperationqueue


    【解决方案1】:

    大写很重要。

    [self performSelectorOnMainThread:@selector(reloadMyData)
                           withObject:nil
                        WaitUntilDone:YES];
    

    WaitUntilDone: 应该是 waitUntilDone:

    [self performSelectorOnMainThread:@selector(reloadMyData)
                           withObject:nil
                        waitUntilDone:YES];
    

    【讨论】:

      【解决方案2】:

      使用@selector 尝试以下行:

      [self performSelectorOnMainThread:@selector(reloadMyData:) withObject:nil WaitUntilDone:YES];
      

      【讨论】:

      • NSGod 的答案看起来是正确的。也 reloadMyData 不带任何数据。
      • 话虽如此,如果您确实设置了 withObject 来发送数据,而忘记了冒号,您将得到相同的“无法识别的选择器”错误。虽然它没有帮助提问者,但它确实帮助了我。
      猜你喜欢
      • 2017-01-26
      • 1970-01-01
      • 1970-01-01
      • 2019-08-28
      • 2012-07-24
      相关资源
      最近更新 更多