Objective-C 中的“无法识别的选择器发送到实例”错误
Posted
技术标签:
【中文标题】Objective-C 中的“无法识别的选择器发送到实例”错误【英文标题】:"unrecognized selector sent to instance" error in Objective-C 【发布时间】:2011-01-28 03:35:29 【问题描述】:我创建了一个按钮并为它添加了一个动作,但是一旦它被调用,我就得到了这个错误:
-[NSCFDictionary numberButtonClick:]: unrecognized selector sent to instance
0x3d03ac0 2010-03-16 22:23:58.811
Money[8056:207] *** Terminating app
due to uncaught exception
'NSInvalidArgumentException', reason:'*** -[NSCFDictionary numberButtonClick:]: unrecognized selector sent to instance 0x3d03ac0'
这是我的代码:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
UIButton *numberButton = [UIButton buttonWithType:UIButtonTypeCustom];
numberButton.frame = CGRectMake(10, 435, 46, 38);
[numberButton setImage:[UIImage imageNamed:@"one.png"] forState:UIControlStateNormal];
[numberButton addTarget:self action:@selector(numberButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview: numberButton];
return self;
-(IBAction)numberButtonClick:(id)sender
NSLog(@"---");
【问题讨论】:
How can I debug 'unrecognized selector sent to instance' error的可能重复 【参考方案1】:看起来您没有正确管理视图控制器的内存并且它在某个时候被释放 - 这导致 numberButtonClicked:
方法被发送到另一个对象,该对象现在占用视图控制器之前的内存占领……
确保您正确地保留/释放您的视图控制器。
【讨论】:
这是一个非常精明的诊断,只需几行代码。 好的,问题已经确定了……但是“请确保您正确地保留/释放您的视图控制器。”是建议,而不是解决方案。 @alex gray,什么?视图控制器上的适当内存管理解决了这个问题......我不明白这不是一个解决方案吗? 正确。虽然这似乎是“修复”..我可能是少数,(尽管我仍然设法存在),但问题和解决方案之间的联系并不是立即显而易见的。例如,我遇到了-[NSWindow end]: unrecognized selector sent to instance 0x100523e80
,虽然我意识到与 OP 的相似之处,甚至可能是您的回答中出现问题的原因,但修复的实施并不是很明显
显而易见。您的 NSWindow 内存管理沿线某处不正确。完成它的生命周期并纠正它。【参考方案2】:
对于那些像我一样通过 Google 来到这里的人,这可能更多地与 Xcode 4.2+/ios 5+ 相关,与 ARC 有什么关系。我遇到了同样的错误“无法识别的选择器发送到实例”。在我的情况下,我设置了一个 UIButton 的目标操作以将其自身作为 sender 参数传递,但后来意识到我不需要它并在代码中将其删除。所以,像:
- (IBAction)buttonPressed:(UIButton *)sender
改为:
- (IBAction)buttonPressed
右键单击有问题的 UIButton 表明 Touch Up Inside 事件与视图控制器 buttonPressed: 方法相关联。删除它并将其重新分配给修改后的方法是一种享受。
【讨论】:
这很有帮助,尽管我认为它自己的问题和回答会更容易找到。 @LeonardChallis 如果未将其作为参数传递,您如何在 buttonPressed 中引用发件人? 非常有帮助的回复。我刚刚遇到了这个确切的问题,您的解决方案是完全正确的。发生这种情况时,正在关注 iTunesU 上的斯坦福 iOS 课程。再次感谢您的回答! @LeonardChalis 谢谢。我为你的回答添加了一个免费的答案。 我只是在为类似的问题而苦苦挣扎,从选择器函数中删除了 sender 参数,然后想知道如何获取 sender。在我的情况下,我收到错误是因为我忘记在选择器回调后放置一个冒号,从而导致调用序列不匹配。使用冒号,我可以保留 sender 参数。【参考方案3】:这是此问题的最佳 Google 答案,但我有不同的原因/结果 - 我想我会加两分钱,以防其他人偶然发现这个问题。
今天早上我遇到了类似的问题。我发现如果你右键单击给出问题的 UI 项,你可以看到已经创建了哪些连接。在我的情况下,我有一个连接两个动作的按钮。我从右键菜单中删除了操作并重新连接它们,我的问题得到了解决。
所以请确保你的操作是正确的。
【讨论】:
这是我的问题。我重命名了一个函数并更改了我的代码,但没有更改 xib 文件中的连接。 谢谢!原来我有三个我删除的方法仍然被引用。困扰我一个星期!【参考方案4】:好的,我必须在这里筹码。 OP 动态创建了按钮。我有一个类似的问题,答案(经过几个小时的狩猎)非常简单,让我感到恶心。
使用时:
action:@selector(xxxButtonClick:)
or (as in my case)
action:NSSelectorFromString([[NSString alloc] initWithFormat:@"%@BtnTui:", name.lowercaseString])
如果您在字符串末尾放置一个冒号 - 它将通过发送者。如果你不把冒号放在字符串的末尾,它就不会,如果接收器需要一个,它将得到一个错误。如果是动态创建事件名称,很容易漏掉冒号。
接收器代码选项如下所示:
- (void)doneBtnTui:(id)sender
NSLog(@"Done Button - with sender");
or
- (void)doneBtnTui
NSLog(@"Done Button - no sender");
像往常一样,总是错过明显的答案。
【讨论】:
非常感谢!这是我的问题(没有在选择器名称的末尾加上冒号“:”)。为什么几乎总是最愚蠢的简单事情让我们这些极客在凌晨 3 点用头撞墙?非常感谢!【参考方案5】:在我的情况下,该函数不需要参数,但按钮被配置为发送一个导致错误的参数。为了解决这个问题,我不得不重新连接事件处理程序。
这是我的功能:
注意它不包含任何参数。
这是我的按钮配置图(右击按钮查看):
请注意,有 3 个事件处理程序。
为了解决这个问题,我必须删除每个事件项,因为其中一个正在向 enterPressed 函数发送对自身的引用。要删除这些项目,我单击每个项目名称旁边的小 x 图标,直到没有显示任何项目。
接下来我必须将按钮重新连接到事件。为此,请按住 Control 键,然后将一条线从按钮拖到操作。它应该说“连接操作”。注意:出于某种原因,我必须重新启动 XCode 才能正常工作;否则它只会让我在函数上方或下方插入动作(也就是创建新动作)。
您现在应该有一个连接到不传递参数的按钮事件的事件处理程序:
此答案补充了@Leonard Challis 的答案,您也应该阅读该答案。
【讨论】:
【参考方案6】:如果您没有在界面构建器中设置视图的“类”,也会发生这种情况。
【讨论】:
啊,谢谢!这导致我的应用程序在 segue 上崩溃,只是忘记设置控制器的类。 为什么需要知道类?我正在尝试将 UITableViewSection 用作 UIView,因此出现此错误。编译器说 UITableViewSection 不存在,所以我假设它是 UIKit 内部的。【参考方案7】:就我而言,我使用的是 NSNotificationCenter 并尝试使用不带参数但添加冒号的选择器。删除冒号解决了这个问题。
使用选择器名称时,如果没有参数,请勿使用尾随冒号。如果有一个参数,请使用一个尾随冒号。如果有多个参数,则必须为每个参数命名,并在后面加上一个冒号。
在此处查看 Adam Rosenfield 的答案:Selectors in Objective-C?
【讨论】:
【参考方案8】:我在动态创建按钮的 Swift 项目中遇到了这个问题。问题代码:
var trashBarButtonItem: UIBarButtonItem
return UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "newButtonClicked")
func newButtonClicked(barButtonItem: UIBarButtonItem)
NSLog("A bar button item on the default toolbar was clicked: \(barButtonItem).")
解决方案是在操作后添加一个完整的冒号“:”:例如
var trashBarButtonItem: UIBarButtonItem
return UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "newButtonClicked:")
func newButtonClicked(barButtonItem: UIBarButtonItem)
NSLog("A bar button item on the default toolbar was clicked: \(barButtonItem).")
此处为完整示例:https://developer.apple.com/library/content/samplecode/UICatalog/Listings/Swift_UIKitCatalog_DefaultToolbarViewController_swift.html
【讨论】:
在遵循教程并阅读了关于这个完全相同问题的提示之后 - 我爱上了它:D【参考方案9】:最明显的原因(包括完整性)是不正确地转换指针并调用错误类的方法。
NSArray* array = [[NSArray alloc] init];
[(NSDictionary*)array objectForKey: key]; // array is not a dictionary, hence exception
【讨论】:
这是一个很好的提示 - 不子类化视图或数据对象(例如,未能添加子类名称)是发生这种情况的另一种方式【参考方案10】:我也遇到了同样的问题。
我删除了情节提要中的 uibutton 并重新创建了它.. 现在一切正常。
【讨论】:
【参考方案11】:我遇到了类似的问题,但对我来说解决方案略有不同。就我而言,我使用 Category 来扩展现有类(UIImage 用于一些调整大小的功能 - 如果您有兴趣,请参阅此 howto)并忘记将 *.m 文件添加到构建目标。愚蠢的错误,但当它发生在哪里看时并不总是很明显。我觉得值得分享...
【讨论】:
【参考方案12】:另一种可能的解决方案:将“-ObjC”添加到链接器参数中。
完整的解释在这里:Objective-C categories in static library
我认为要点是:如果类别是在您静态链接的库中定义的,则链接器不够聪明,无法链接类别方法。上面的标志使链接器链接到所有目标 C 类和类别中,而不仅仅是它认为基于分析您的源代码需要的链接器链接。 (请随意调整或更正该答案。我知道链接语言,所以我只是在这里鹦鹉学舌)。
【讨论】:
【参考方案13】:这发生在我身上,因为不小心删除了 UIViewcontroller 类代码中的“@IBAction func...”,所以在 Storyboard 中创建了 Reference Outlet,但在运行时有任何函数可以处理它。
解决方案是删除属性检查器中的 Outlet 引用,然后使用命令键将其拖动到类代码中重新创建。
希望对你有帮助!
【讨论】:
同样,当按钮引用一个不再存在的函数时,我也发生了这种情况。【参考方案14】:我认为您应该在返回类型中使用 void,而不是 IBAction。因为您以编程方式定义了一个按钮。
【讨论】:
【参考方案15】:我遇到了同样的错误,我发现了以下问题:
当你使用代码时
[self.refreshControl addTarget:self action:@selector(yourRefreshMethod:) forControlEvents:UIControlEventValueChanged];
你可能认为它在寻找选择器:
- (void)yourRefreshMethod
(your code here)
但它实际上是在寻找选择器:
- (void)yourRefreshMethod:(id)sender
(your code here)
那个选择器不存在,所以你会崩溃。
您可以将选择器更改为接收 (id)sender 以解决错误。
但是,如果您有其他调用刷新函数的函数 没有提供发送者呢?您需要一种对两者都适用的功能。简单的解决方案是添加另一个功能:
- (void)yourRefreshMethodWithSender:(id)sender
[self yourRefreshMethod];
然后修改刷新下拉代码以调用该选择器:
[self.refreshControl addTarget:self action:@selector(yourRefreshMethodWithSender:) forControlEvents:UIControlEventValueChanged];
我还在一台无法升级到最新版 Mac OSX 的旧 Mac 上学习斯坦福 iOS 课程。所以我仍在为 iOS 6.1 构建,这解决了我的问题。
【讨论】:
【参考方案16】:就我而言,我在 2 小时后解决了问题:
发件人(tabBar 项)没有任何引用出口。所以它没有指向任何地方。
Juste创建一个与您的功能相对应的引用出口。
希望对大家有所帮助。
【讨论】:
只是补充一下,就我而言,我忘记将IBAction
移植到Swift。所以它抱怨它想调用那个函数,但是找不到。【参考方案17】:
如何调试“无法识别的选择器发送到实例”
在大多数情况下,Xcode 不会将我们带到发生此问题的确切位置。当应用程序崩溃时,您将看不到导致这种情况的代码行,而是将您带到 App 委托类,错误输出如下:
[UITableViewCellContentView image]: unrecognized selector sent to instance
或
[__NSDictionaryI objectAtIndex:] unrecognized selector sent to instance
或
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TestApp.MyViewController viewDidLoad:]: unrecognized selector sent to instance 0xDABCDD'
如何找到导致此问题的代码行:
转到断点导航器。单击“+”选项。单击“异常断点”。将出现一个新的小部件,如下所示。
添加以下条件块:
-[NSObject(NSObject) doesNotRecognizeSelector:]
你也可以为所有异常设置断点。 现在再次运行您的代码。这一次,当这个异常发生时会触发断点。
作者:Prafulla Singh
完整解释:https://prafullkumar77.medium.com/how-to-debug-unrecognized-selector-send-to-instance-402473bc23d
【讨论】:
【参考方案18】:我目前正在学习 iOS 开发,并正在阅读 aPress 的“Beginning iOS6 Development”一书。我在第 10 章:故事板中遇到了同样的错误。
我花了两天时间才弄明白,但发现我不应该将 TableView 单元格的标签设置为 1。对于其他正在读这本书并收到类似错误的人,我希望这会有所帮助。
我真的希望我的代码中的未来错误更容易找到!哈哈哈。调试错误并没有让我朝着正确的方向去解决它(或者至少我太新了,无法理解调试器,哈哈)。
【讨论】:
【参考方案19】:就我而言,我使用的是 UIWebView,并且在第二个参数中传递了 NSString 而不是 NSURL。所以我怀疑传递给函数的错误类类型会导致这个错误。
【讨论】:
【参考方案20】:..现在是我的
我将按钮链接到一个方法,该方法访问另一个按钮的参数并且效果很好,但是当我尝试对按钮本身做一些事情时,我遇到了崩溃。编译的时候没有报错。。解决办法?
我未能将按钮链接到文件的所有者。所以如果这里有人像我一样愚蠢,试试这个:)
【讨论】:
【参考方案21】:又一个略有不同的解决方案/案例。
我正在使用 Xamarin 和 MvvmCross,并且试图将 UIButton 绑定到 ViewModel。我将 UIButton 连接到 Outlet 和 TouchUpInside。
装订时我只使用插座:
set.Bind (somethingOutlet).For ("TouchUpInside").To(vm => vm.Something);
我所要做的就是删除 XCode 中的操作 (TouchUpInside) 连接,然后就解决了。
附: 我想这与以前的答案有关,尤其是与@Chris Kaminski 有关,但我希望这对某人有所帮助...
干杯。
【讨论】:
【参考方案22】:我遇到了同样的问题。对我来说,问题是一个按钮有两个 Action 方法。我所做的是为我的按钮创建第一个操作方法,然后在视图控制器中将其删除,但忘记在连接检查器中断开主情节提要中的连接。所以当我添加第二个动作方法时,现在一个按钮有两个动作方法,这导致了错误。
【讨论】:
【参考方案23】:对我来说,这是在 interfacebuilder bij ctrl-dragging 中创建的剩余连接。断开连接的名称在错误日志中
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[NameOfYourApp.NameOfYourClass nameOfCorruptConnection:]:
unrecognized selector sent to instance 0x7f97a48bb000'
我有一个链接到按钮的操作。按下按钮使应用程序崩溃,因为我的代码中不再存在 Outlet。 在日志中搜索名称导致我在情节提要中找到它。删除它,崩溃消失了!
【讨论】:
【参考方案24】:我正在回复 Leonard Challis,因为我也参加了斯坦福 iOS 课程 C193P,用户“oli206”也是如此
“由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:”
问题是我将计算器上的“Enter”按钮连接了两次,一位朋友指出,当我检查 Storyboard 中的按钮时,发现有 2 个条目位于“Touch Up Inside”属性上右键单击“Enter”按钮。删除两个“Touch Up Inside”“已发送事件”之一解决了这个问题。
这表明问题被触发(对于作业 1 的计算器演练中的 C193P 视频类)作为 2 个已发送事件,其中一个导致了异常。
【讨论】:
我有 3 个条目。 :)【参考方案25】:当您没有将 ViewController 分配给 ViewControllerScene 时,可能会发生这种情况 界面生成器。所以 ViewController.m 没有连接到任何场景。
【讨论】:
【参考方案26】:包括我的份额。我被困了一段时间,直到我意识到我已经创建了一个禁用ARC(Automatic counting reference) 的项目。在该选项上快速设置为 YES 解决了我的问题。
【讨论】:
【参考方案27】:另一个非常愚蠢的原因是在接口(.h)中定义了选择器,但在实现(.m)中没有定义(p.e.错字)
【讨论】:
【参考方案28】:添加到列表的另一个原因/解决方案。这是由 iOS6.0(和/或糟糕的编程)引起的。在旧版本中,如果参数类型匹配,则选择器将匹配,但在 iOS 6.0 中,我在以前工作的代码中遇到了崩溃,其中参数名称不正确。
我正在做类似的事情
[objectName methodName:@"somestring" lat:latValue lng:lngValue];
但在定义中(.h 和 .m)我有
(viod) methodName:(NSString *) latitude:(double)latitude longitude:(double)longitude;
这在 iOS5 上运行良好,但在 6 上运行良好,即使是完全相同的构建部署到不同的设备。
我不明白为什么编译器不能告诉我这个,无论如何 - 问题已解决。
【讨论】:
【参考方案29】:当您想将 ControllerA 中的属性设置为自定义 ControllerB 类中的公共属性并且您尚未在情节提要的身份检查器中设置“自定义类”时,也可能发生这种情况。
【讨论】:
【参考方案30】:我的问题和解决方案不同,我想我应该把它贴在这里,这样未来的读者就可以免于碰壁。
我为同一个 UIVIewController 分配了不同的 xib,即使在到处搜索之后我也找不到如何更正它。然后我检查了我调用initWithNibName
的AppDelegate,可以看到在复制代码时,我更改了xib 名称,但忘记更改UIViewController
类。因此,如果没有一个解决方案适合您,请检查您的 initWithNibName
方法。
【讨论】:
以上是关于Objective-C 中的“无法识别的选择器发送到实例”错误的主要内容,如果未能解决你的问题,请参考以下文章
NSNotification 无法识别的选择器发送到 Swift 中的实例