컴파일러 오류 : Objective-C 선택기가있는 메소드가 동일한 Objective-C 선택기가있는 이전 선언과 충돌합니다.


209

Swift를 배우기 시작했고 YouTube에서 훌륭한 Stanford University 비디오 강의를 따르고 있습니다. 관심이 있거나 도움이되는 링크는 다음과 같습니다 (내 문제를 이해할 필요는 없지만).

Swift로 iOS 8 앱 개발-2. 더 많은 Xcode 및 Swift, MVC

강의를 따르는 동안 내 코드가 비디오의 코드와 동일하지만 시스템에서 컴파일러 오류가 발생하는 지점에 도달했습니다. 많은 시행 착오 끝에 코드를 두 가지 예로 축소했습니다. 하나는 오류를 생성하거나 다른 하나는 오류를 발생시키지 않지만 실제로 오류의 원인 또는 오류를 해결하는 방법을 모릅니다.

오류를 생성하는 코드는 다음과 같습니다.

import UIKit

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

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

다음과 같은 컴파일러 오류가 발생합니다.

Objective-C 선택기와 함께 'perform'메소드 'perform :'은 동일한 Objective-C 선택기로 이전 선언과 충돌합니다.

UIViewController의 하위 클래스를 제거하면 코드가 다음과 같이 컴파일됩니다.

import UIKit

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

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

관련이 있거나 관련이없는 기타 정보 :

  • 최근에 요세미티로 업그레이드했습니다.
  • Xcode를 설치할 때 베타 버전 (버전 6.3 (6D543q))으로 끝났습니다 (정확하게 기억한다면) 이것이 OS X 버전에서 실행하는 데 필요한 버전이기 때문입니다.

그렇지 않으면 이것이 나에게 의미가 없기 때문에 컴파일러의 버그라고 생각합니다. 어떤 도움도 대단히 감사합니다!


3
Yosemite에서 Xcode 6.2를 실행할 수 있습니다. 앱 스토어에서 다운로드 할 수 있으며 베타 버전으로 시스템에 설치할 수 있습니다. 이 시점에서 Stanford 클래스에 Xcode 6.3을 사용하는 것은 권장하지 않습니다. 베타 버전이며 Swift 1.2가 포함되어 있기 때문에 Swift의 이전 버전과 비디오가 다릅니다.
vacawama

2
4 월 5 일의 사용자 (2 월)의 (현재 승인 된) 답변은 더 이상 최고의 답변이 아닙니다. 대신 4 월 16 일의 (James Zhang)의 답변이 더 구체적이고 정확합니다.
phlebotinum

답변:


144

Objective-C는 메소드 오버로드를 지원하지 않으므로 다른 메소드 이름을 사용해야합니다. UIViewController를 상속하면 NSObject를 상속하고 클래스를 Obj-C와 상호 운용 가능하게 만들었습니다. 반면에 스위프트는 오버로드를 지원하므로 상속을 제거 할 때 작동합니다.


2
Objective-C SUPPORTS 메소드 재정의 (이미 구현 된 과부하에 대해 알려주는 (압축 가능한) 컴파일러 경고로 인해) Apple은 프레임 워크가 과부하되지 않도록하기를 원하지 않습니다. 나는 UIFont매일 그러한 과부하를 사용 하고 있습니다.
Michi

@ 아래 polarwar의 대답은 스위프트 2에 가장 적합한 하나입니다 stackoverflow.com/a/31500740/144088
Crashalot

237

나 자신도 Standford 과정을 수강하고 있으며 오랫동안 여기에 붙어 있지만 검색 한 후에 Xcode 릴리스 노트 와 아래 에서 뭔가를 발견 했습니다.

Swift 1.2는 Objective-C에서 지원하지 않는 @objc 메소드 및 이니셜 라이저의 유형 기반 과부하를 검사하는 데 엄격합니다.

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

이 코드는 Swift에서 호출 될 때 작동하지만 Objective-C에서 호출되면 쉽게 충돌 할 수 있습니다. 이 문제를 해결하려면 Objective-C에서 지원하지 않는 유형을 사용하여 Swift 컴파일러가 멤버를 Objective-C 런타임에 노출하지 못하게하십시오.

  • 의미가 있다면 @objc의 추론을 비활성화하기 위해 멤버를 private으로 표시하십시오.
  • 그렇지 않으면 기본값으로 더미 매개 변수를 사용하십시오 (예 : _ nonobjc : () = ()). (19826275)

프라이빗 서브 클래스에서 Objective-C에 노출 된 메소드의 대체는 @objc로 유추되지 않으므로 Swift 컴파일러가 중단됩니다. 이러한 대체 메소드에 @objc 속성을 명시 적으로 추가하십시오. (19935352)

Swift를 사용하는 프로젝트 또는 작업 공간에서 빨리 열기를 사용할 때는 SDK의 기호를 사용할 수 없습니다. (20349540)

내가 한 것은 다음과 같이 재정의 방법 앞에 "비공개"를 추가하는 것입니다.

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

3
이 완전히 의미는 개인이 방법을 설정할 수 있습니다으로이 솔루션은 가장 실행 가능한 I 찾기 이럴입니다
demental

38
Objective-C 런타임에서 메소드를 제외하는 데 사용할 수있는 @nonobjc 속성도 있습니다.
Erik J

2
나는 @ErikJ의 의견과 polarwar의 대답을 아래에서 두 번째로 봅니다. 이것은 Swift 2 및 xcode 7을 사용하는 가장 좋은 대답 인 것 같습니다. 아직 업데이트하지 않은 경우 강력히 권장합니다.
오스틴 A

@ 아래 polarwar의 대답은 스위프트 2에 가장 적합한 하나입니다 stackoverflow.com/a/31500740/144088
Crashalot

111

이미 대답했듯이 ObjC는 메소드 오버로드 (동일한 이름을 가진 두 가지 메소드)를 지원하지 않으며 Xcode 7의 swift 2에는 이러한 종류의 문제를 해결할 수있는 두 가지 옵션이 있습니다. 한 가지 옵션은 속성을 사용하여 메소드의 이름을 바꾸는 것입니다.@objc(newNameMethod:)

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

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

Xcode 7+에서이 문제를 해결하는 또 다른 옵션은 @nonobjc모든 메소드, 첨자 또는 이니셜 라이저에 속성을 적용하는 것입니다.

func methodOne() {...}

@nonobjc
func methodOne() {...}

6
이렇게하면 신속한 2 (및 이상)의 문제가 해결됩니다. 가장 정답으로 업데이트해야합니다. 타이.
Maxim Veksler

2
Swift 2와 Xcode 7 +를 사용하는 사람이라면 이것이 polarwar에 동의하는 정답입니다
TerNovi

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메소드 이름 지정 스타일에 대한 느낌을 얻으려면 다른 메소드를 보거나 클래스 내에서 표현적이고 고유해야하는 메소드 이름을 읽으 십시오.


감사합니다-이것은 내 질문에 완벽하게 답변하며 처음이되었으므로 이것을 올바른 것으로 표시합니다.
Auspice

내가 컴파일하지 않은 코드가했던 일을 확신하면서 강의 코드가 왜 작동했는지 여전히 이해하지 못한다고 말했습니다! 이봐 호-나는 다시 가서 다시 확인합니다. 다른 것이 있어야합니다.
원조

2
@Auspice 비디오에 사용했던 Xcode 버전에서 오류가 발생하지 않았을 수도 있지만 여전히 문제였습니다. Xcode 6.3까지는 컴파일러가이를 감지하여 경고 할 수 없었습니다.
Mick MacCallum

3
Paul Hegarty는 여기서 'overloading'함수 (동일한 이름을 가진 두 개의 함수, 다른 인수 집합)를 보여주기를 원하므로 동일한 메소드 이름을 의도적으로 사용합니다! 오버로드는 Objective-C가 아닌 Swift에서만 허용됩니다. 그렇기 때문에 솔루션이 상속 양식 UIViewController (Objective-C 클래스)를 제거하거나 private 메소드를 선언해야합니다. 두 솔루션 모두 다른 답변에 자세히 설명되어 있습니다.
Ronny Webers

실제로 나는 함수 앞에 개인 키워드를 사용했습니다. like, private func performOperation (operation : Double-> Double) {} 및 private func performOperation (operation : (Double, Double)-> Double) {} 여기서 PRIVATE의 도움으로 오버로드 된 메소드를 달성했습니다. ViewController.Swift에서만 두 가지를 모두 사용했기 때문입니다. 왜 컴파일러가 오류를 말하지 않습니까?
iTag


2

동일한 Obj-C 서명으로 두 가지 방법을 사용했기 때문에 동일한 오류가 발생했습니다.

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

런타임에 예기치 않은 결과가 발생할 수 있기 때문에 그중 하나를 @nonobjc로 표시하고 싶지 않았습니다. (가능성이 없으면 누군가 나를 교정 할 수 있습니다)

Swift의 외부 매개 변수 이름 기능 (로컬 이름과 외부 이름을 동일하게 함)을 사용하여 Obj-c 메서드 서명을 효과적으로 변경하여이를 해결했습니다.

static func prepareForUpSyncing(objs objs : [NSManagedObject]!) -> Bool {
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.