编译器错误:使用Objective-C选择器的方法与先前使用相同Objective-C选择器的声明冲突

Aus*_*ice 207 swift

我开始学习Swift,并一直关注YouTube上非常好的斯坦福大学视频讲座.如果您感兴趣或有帮助,这里有一个链接(虽然不需要了解我的问题):

使用Swift开发iOS 8应用程序 - 2.更多Xcode和Swift,MVC

在讲课之后,我得到了一点(据我所知)我的代码与视频中的代码相同,但在我的系统上,我遇到了编译错误.经过大量的试验和错误后,我设法将我的代码减少到两个例子,其中一个产生错误,另一个或不产生错误,但我不知道究竟是什么原因导致错误或如何解决它.

创建错误的代码是:

import UIKit

class BugViewController: UIViewController
{
    func perform(operation: (Double) -> Double) {
    }

    func perform(operation: (Double, Double) -> Double) {
    }
}
Run Code Online (Sandbox Code Playgroud)

这会产生以下编译器错误:

方法'执行'与Objective-C选择器'执行:'与使用相同的Objective-C选择器的先前声明冲突

通过简单地删除UIViewController的子类,代码编译:

import UIKit

class BugViewController
{
    func perform(operation: (Double) -> Double) {
    }

    func perform(operation: (Double, Double) -> Double) {
    }
}
Run Code Online (Sandbox Code Playgroud)

其他一些可能相关或不相关的信息:

  • 我最近升级到约塞米蒂.
  • 当我安装Xcode时,我最终得到了Beta版本(版本6.3(6D543q)),因为(如果我没记错的话)这是我需要在我的OS X版本上运行的版本.

我一半希望这是编译器中的一个错误,否则这对我没有任何意义.非常感谢任何帮助!

小智 237

我自己也参加了斯坦福大学的课程,我也被困在这里很长一段时间,但经过一番搜索后,我发现了一些东西:Xcode发行说明,它提到了以下内容:

Swift 1.2严格要求检查基于类型的@objc方法和初始化器的重载,这是Objective-C不支持的.

// Has the Objective-C selector "performOperation:".
func performOperation(op: NSOperation) { /* do something */ }
// Also has the selector "performOperation:".
func performOperation(fn: () -> Void) {
    self.performOperation(NSBlockOperation(block: fn))
}
Run Code Online (Sandbox Code Playgroud)

从Swift调用时,此代码可以正常工作,但如果从Objective-C调用,则很容易崩溃.要解决此问题,请使用Objective-C不支持的类型以防止Swift编译器将成员公开给Objective-C运行时:

  • 如果有意义,请将该成员标记为私有,以禁用@objc的推断.
  • 否则,请使用具有默认值的虚拟参数,例如:_ nonobjc:()=().(19826275)

在私有子类中暴露给Objective-C的方法的覆盖不被推断为@objc,导致Swift编译器崩溃.将@objc属性显式添加到任何此类重写方法.(19935352)

在使用Swift的项目或工作区中快速使用Open Quickly时,SDK中的符号不​​可用.(20349540)

我所做的只是在覆盖方法前面添加"private",如下所示:

    private func performOperation(operation: Double -> Double) {
    if operandStack.count >= 1 {
        displayValue = operation(operandStack.removeLast())
        enter()
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,现在还有一个@nonobjc属性,可用于从Objective-C运行时中排除方法. (35认同)
  • 这个解决方案是我发现的最可行的解决方案,因为将此方法设置为私有是完全有意义的 (3认同)
  • 我的第二个@ErikJ的评论和极地战争的回答如下.这似乎是使用Swift 2和xcode 7的最佳答案.如果您还没有更新,我强烈推荐它. (2认同)

小智 142

Objective-C不支持方法重载,您必须使用不同的方法名称.当您继承UIViewController时,您继承了NSObject并使该类可以与Obj-C互操作.另一方面,Swift确实支持重载,这就是为什么它在删除继承时有效.

  • Objective-C SUPPORTS方法覆盖(带有(可抑制的)编译器警告,通知你已经实现的超载),Apple只是不希望你这样做以防止它们的框架过载.我每天都在使用```UIFont```这样的重载. (2认同)

pol*_*war 109

正如已经回答的那样,ObjC不支持方法重载(两个具有相同名称的方法),而在Xcode 7下的swift 2中,有两种方法可以解决这类问题.一种选择是使用属性重命名方法:@objc(newNameMethod:)

func methodOne(par1, par2) {...}

@objc(methodTwo:)
func methodOne(par1) {...}
Run Code Online (Sandbox Code Playgroud)

在Xcode 7+中解决此问题的另一个选择是将 @nonobjc属性应用于任何方法,下标或初始化

func methodOne() {...}

@nonobjc
func methodOne() {...}
Run Code Online (Sandbox Code Playgroud)

  • 这解决了swift 2(及以上)的问题.应该更新为最正确的答案.TY. (6认同)
  • 对于任何使用Swift 2和Xcode 7 +的人来说,这是我同意polarwar的正确答案 (2认同)

Jef*_*mas 17

问题UIViewController是一@objc堂课.从继承时UIViewController,BugViewController也是一个@objc类.

这意味着它必须符合Objective-C选择器的规则(方法的名称).方法func perform(operation: (Double) -> Double)func perform(operation: (Double, Double) -> Double)两者都有相同的选择器@selector(perform:).这是不允许的.

要解决此问题,请使用不同的名称:like func perform1(operation: (Double) -> Double)func perform2(operation: (Double, Double) -> Double).


我认为处理此问题的最佳方法是为您的perform()方法提供更具描述性的名称.这些方法有什么作用?他们如何改变视图控制器的状态?查看其他UIViewController方法以了解方法命名的样式,或者读取方法名称应该在类中具有表达力和独特性

  • Paul Hegarty想要在这里演示函数'重载'(2个函数具有相同的名称,但参数集不同),所以他确实使用相同的方法名称!仅在Swift中允许重载,而不是在Objective-C中.这就是为什么解决方案要么从UIViewController(它是一个Objective-C类)中删除继承,要么声明该方法是私有的.这里的其他答案都详细解释了这两种解决方案. (3认同)
  • @Auspice它可能没有产生他们用于视频的Xcode版本的错误,但它仍然是一个问题.直到Xcode 6.3,编译器才能检测到这一点并发出警告. (2认同)

小智 5

来自"Xcode 6.3发行说明" - >"Swift语言更改"下的https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html

Swift现在可以检测Swift类型系统中的重载和覆盖之间的差异以及通过Objective-C运行时看到的有效行为.