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

时间:2023-01-15 18:34:09

I am starting to learn Swift, and have been following the very good Stanford University video lectures on YouTube. Here is a link if you are interested or it helps (although it isn't required to understand my problem):

我开始学习斯威夫特,并且一直在YouTube上关注斯坦福大学的视频讲座。如果你感兴趣或者有帮助的话,这里有一个链接(虽然不需要理解我的问题):

Developing iOS 8 Apps with Swift - 2. More Xcode and Swift, MVC

使用Swift - 2开发iOS 8应用。更多的Xcode和Swift MVC

While following the lectures I got to a point where (as far as I could tell) my code was identical to the code in the video but on my system I got a compiler error. After a lot of trial and error I have managed to reduce my code to two examples, one of which generates an error, the other or which doesn't, but I have no idea what is actually causing the error or how to resolve it.

课程结束后,我发现(就我所知)我的代码和视频中的代码是一样的,但是在我的系统中,我得到了一个编译错误。经过大量的尝试和错误之后,我成功地将我的代码减少到两个示例,其中一个生成错误,另一个或不产生错误,但是我不知道到底是什么导致了错误或者如何解决它。

The code which creates the error is:

产生错误的代码是:

import UIKit

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

    func perform(operation: (Double, Double) -> Double) {
    }
}

This creates the following compiler error:

这会产生以下编译错误:

Method 'perform' with Objective-C selector 'perform: ' conflicts with previous declaration with the same Objective-C selector

方法“执行”与Objective-C选择器“执行:”与之前的声明与相同的Objective-C选择器冲突

By simply removing the sub-classing of UIViewController the code compiles:

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

import UIKit

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

    func perform(operation: (Double, Double) -> Double) {
    }
}

Some other information which may or may not be relevant:

其他可能或不相关的资料:

  • I have recently upgraded to Yosemite.
  • 我最近升级到约塞米蒂。
  • When I installed Xcode, I ended up with a Beta version (Version 6.3 (6D543q)) because (if I remember correctly) this was the version I needed to run on my version of OS X.
  • 当我安装Xcode时,我最终得到了一个Beta版本(版本6.3 (6D543q)),因为(如果我没记错的话)这是我需要在OS X版本上运行的版本。

I am half hoping this is a bug in the compiler because otherwise this doesn't make any sense to me. Any help very gratefully received!

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

6 个解决方案

#1


138  

Objective-C does not support method overloading, you have to use a different method name. When you inherited UIViewController you inherited NSObject and made the class interopable to Obj-C. Swift on the other hand does support overloading, that's why it works when you remove the inheritance.

Objective-C不支持方法重载,必须使用不同的方法名。当您继承了UIViewController时,您继承了NSObject,并使类可以访问object - c。另一方面,Swift支持重载,这就是它在删除继承时起作用的原因。

#2


236  

I myself am also taking the Standford course and I got stuck here for a long time too, but after some searching, I found something from here: Xcode release notes and it mentioned something below:

我自己也参加了斯坦福大学的课程,我也在这里呆了很长一段时间,但经过一番搜索之后,我发现了一些东西:Xcode发布笔记,上面提到了以下内容:

Swift 1.2 is strict about checking type-based overloading of @objc methods and initializers, something not supported by Objective-C.

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))
}

This code would work when invoked from Swift, but could easily crash if invoked from Objective-C. To solve this problem, use a type that is not supported by Objective-C to prevent the Swift compiler from exposing the member to the Objective-C runtime:

这段代码在从Swift调用时可以工作,但是如果从Objective-C调用时很容易崩溃。要解决这个问题,使用Objective-C不支持的类型来防止Swift编译器将成员暴露给Objective-C运行时:

  • If it makes sense, mark the member as private to disable inference of @objc.
  • 如果有意义,请将成员标记为private,以禁用@objc的推断。
  • Otherwise, use a dummy parameter with a default value, for example: _ nonobjc: () = (). (19826275)
  • 否则,使用具有默认值的哑参数,例如:_ nonobjc:() =()。(19826275)

Overrides of methods exposed to Objective-C in private subclasses are not inferred to be @objc, causing the Swift compiler to crash. Explicitly add the @objc attribute to any such overriding methods. (19935352)

在私有子类中公开给Objective-C的方法的重写不会被推断为@objc,这会导致Swift编译器崩溃。显式地向任何此类重写方法添加@objc属性。(19935352)

Symbols from SDKs are not available when using Open Quickly in a project or workspace that uses Swift. (20349540)

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

what i did was just adding "private" in front of the override method like this:

我所做的就是在覆盖方法前面加上"private"就像这样

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

#3


102  

As it has already been answered, ObjC doesn't support method overloading (two methods with the same name) and In swift 2 under Xcode 7 there are two options to solve this kind of problems. One option is to rename the method using the attribute: @objc(newNameMethod:)

如前所述,ObjC不支持方法重载(两个同名的方法),在Xcode 7下的swift 2中有两个选项可以解决这类问题。一个选项是使用属性@objc重命名方法(newNameMethod:)

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

@objc(methodTwo:)
func methodOne(par1) {...}

another option to solve this problem in Xcode 7+ is by applying @nonobjc attribute to any method, subscript or initialiser

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

func methodOne() {...}

@nonobjc
func methodOne() {...}

#4


15  

The problem is UIViewController is an @objc class. When inheriting from UIViewController, BugViewController is also a @objc class.

问题是UIViewController是一个@objc类。当继承UIViewController时,BugViewController也是一个@objc类。

This means it must conform to the rules of Objective-C selectors (the name of a method). The methods func perform(operation: (Double) -> Double) and func perform(operation: (Double, Double) -> Double) both have the same selector @selector(perform:). This is not allowed.

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

To resolve this, use different names: like func perform1(operation: (Double) -> Double) and func perform2(operation: (Double, Double) -> Double).

要解决这个问题,请使用不同的名称:例如func perform1(操作:(Double) -> Double)和func perform2(操作:(Double, Double) -> Double)。


I think the best way to handle this is to give your perform() methods more descriptive names. What do these methods do? How do they change the state of the view controller? Look at the other UIViewController methods to get a feel for the style of method naming, or read Method Names Should Be Expressive and Unique Within a Class

我认为处理这个问题的最好方法是给执行()方法更多的描述性名称。这些方法是做什么的?它们如何改变视图控制器的状态?查看其他的UIViewController方法,以了解方法命名的风格,或者读取方法名称在类中应该具有表达性和惟一性

#5


5  

From https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html under "Xcode 6.3 Release Notes" -> "Swift Language Changes" you find

从https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html下的“Xcode 6.3发布说明”->“Swift语言的变化”你可以找到

Swift now detects discrepancies between overloading and overriding in the Swift type system and the effective behavior seen via the Objective-C runtime.

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

#6


2  

I got the same error due to having having two methods with the same Obj-C signature:

由于有两种方法具有相同的object - c签名,我得到了相同的错误:

static func prepareForUpSyncing(obj : NSManagedObject!) -> Bool
static func prepareForUpSyncing(objs : [NSManagedObject]!) -> Bool

I didn't want to mark one of them as @nonobjc due to possibility of unforseen consequences at runtime. (Someone can correct me if there is no possibility)

我不想把其中一个标记为@nonobjc,因为在运行时可能产生不可预见的后果。(如果没有可能,有人可以纠正我)

Resolved it by using Swift's external parameter name feature (I made external name same as local name) to the second method, which effectively changes the Obj-c method signature:

通过使用Swift的外部参数名称特性(我将外部名称与本地名称相同)与第二种方法进行了解决,从而有效地改变了objc方法的签名:

static func prepareForUpSyncing(objs objs : [NSManagedObject]!) -> Bool {

#1


138  

Objective-C does not support method overloading, you have to use a different method name. When you inherited UIViewController you inherited NSObject and made the class interopable to Obj-C. Swift on the other hand does support overloading, that's why it works when you remove the inheritance.

Objective-C不支持方法重载,必须使用不同的方法名。当您继承了UIViewController时,您继承了NSObject,并使类可以访问object - c。另一方面,Swift支持重载,这就是它在删除继承时起作用的原因。

#2


236  

I myself am also taking the Standford course and I got stuck here for a long time too, but after some searching, I found something from here: Xcode release notes and it mentioned something below:

我自己也参加了斯坦福大学的课程,我也在这里呆了很长一段时间,但经过一番搜索之后,我发现了一些东西:Xcode发布笔记,上面提到了以下内容:

Swift 1.2 is strict about checking type-based overloading of @objc methods and initializers, something not supported by Objective-C.

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))
}

This code would work when invoked from Swift, but could easily crash if invoked from Objective-C. To solve this problem, use a type that is not supported by Objective-C to prevent the Swift compiler from exposing the member to the Objective-C runtime:

这段代码在从Swift调用时可以工作,但是如果从Objective-C调用时很容易崩溃。要解决这个问题,使用Objective-C不支持的类型来防止Swift编译器将成员暴露给Objective-C运行时:

  • If it makes sense, mark the member as private to disable inference of @objc.
  • 如果有意义,请将成员标记为private,以禁用@objc的推断。
  • Otherwise, use a dummy parameter with a default value, for example: _ nonobjc: () = (). (19826275)
  • 否则,使用具有默认值的哑参数,例如:_ nonobjc:() =()。(19826275)

Overrides of methods exposed to Objective-C in private subclasses are not inferred to be @objc, causing the Swift compiler to crash. Explicitly add the @objc attribute to any such overriding methods. (19935352)

在私有子类中公开给Objective-C的方法的重写不会被推断为@objc,这会导致Swift编译器崩溃。显式地向任何此类重写方法添加@objc属性。(19935352)

Symbols from SDKs are not available when using Open Quickly in a project or workspace that uses Swift. (20349540)

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

what i did was just adding "private" in front of the override method like this:

我所做的就是在覆盖方法前面加上"private"就像这样

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

#3


102  

As it has already been answered, ObjC doesn't support method overloading (two methods with the same name) and In swift 2 under Xcode 7 there are two options to solve this kind of problems. One option is to rename the method using the attribute: @objc(newNameMethod:)

如前所述,ObjC不支持方法重载(两个同名的方法),在Xcode 7下的swift 2中有两个选项可以解决这类问题。一个选项是使用属性@objc重命名方法(newNameMethod:)

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

@objc(methodTwo:)
func methodOne(par1) {...}

another option to solve this problem in Xcode 7+ is by applying @nonobjc attribute to any method, subscript or initialiser

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

func methodOne() {...}

@nonobjc
func methodOne() {...}

#4


15  

The problem is UIViewController is an @objc class. When inheriting from UIViewController, BugViewController is also a @objc class.

问题是UIViewController是一个@objc类。当继承UIViewController时,BugViewController也是一个@objc类。

This means it must conform to the rules of Objective-C selectors (the name of a method). The methods func perform(operation: (Double) -> Double) and func perform(operation: (Double, Double) -> Double) both have the same selector @selector(perform:). This is not allowed.

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

To resolve this, use different names: like func perform1(operation: (Double) -> Double) and func perform2(operation: (Double, Double) -> Double).

要解决这个问题,请使用不同的名称:例如func perform1(操作:(Double) -> Double)和func perform2(操作:(Double, Double) -> Double)。


I think the best way to handle this is to give your perform() methods more descriptive names. What do these methods do? How do they change the state of the view controller? Look at the other UIViewController methods to get a feel for the style of method naming, or read Method Names Should Be Expressive and Unique Within a Class

我认为处理这个问题的最好方法是给执行()方法更多的描述性名称。这些方法是做什么的?它们如何改变视图控制器的状态?查看其他的UIViewController方法,以了解方法命名的风格,或者读取方法名称在类中应该具有表达性和惟一性

#5


5  

From https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html under "Xcode 6.3 Release Notes" -> "Swift Language Changes" you find

从https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html下的“Xcode 6.3发布说明”->“Swift语言的变化”你可以找到

Swift now detects discrepancies between overloading and overriding in the Swift type system and the effective behavior seen via the Objective-C runtime.

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

#6


2  

I got the same error due to having having two methods with the same Obj-C signature:

由于有两种方法具有相同的object - c签名,我得到了相同的错误:

static func prepareForUpSyncing(obj : NSManagedObject!) -> Bool
static func prepareForUpSyncing(objs : [NSManagedObject]!) -> Bool

I didn't want to mark one of them as @nonobjc due to possibility of unforseen consequences at runtime. (Someone can correct me if there is no possibility)

我不想把其中一个标记为@nonobjc,因为在运行时可能产生不可预见的后果。(如果没有可能,有人可以纠正我)

Resolved it by using Swift's external parameter name feature (I made external name same as local name) to the second method, which effectively changes the Obj-c method signature:

通过使用Swift的外部参数名称特性(我将外部名称与本地名称相同)与第二种方法进行了解决,从而有效地改变了objc方法的签名:

static func prepareForUpSyncing(objs objs : [NSManagedObject]!) -> Bool {