Swift 1.2에서 선언은 '최종'및 '동적'오류가 될 수 없습니다.


123

value아래 의 선언

import Foundation

class AAA: NSObject {
    func test2() {
        self.dynamicType
    }
}
extension AAA {
    static let value    =   111
}

다음 컴파일 오류가 발생합니다.

A declaration cannot be both 'final' and 'dynamic'

왜 이런 일이 발생하며 어떻게 처리 할 수 ​​있습니까?

Swift 1.2 (Xcode 6.3.1 6D1002에 포함 된 버전)를 사용하고 있습니다.


func test2선언은 엑스 코드 7.3.1의로, 오류를 실행하는 데 필요하지 않습니다.
rob mayoff


정적 변수를 다른 더 나은 이름 지정 구조체에
넣으십시오

답변:


224

이 문제는 Swift가 Obj-C 호환성을위한 정적 속성에 대한 동적 접근자를 생성하려고하기 때문에 발생합니다 NSObject.

프로젝트가 Swift에만있는 경우 var접근 자를 사용하는 대신 @nonobjcSwift 2.0 의 속성을 통해 문제를 피할 수 있습니다 .

import Foundation

class AAA: NSObject {}
extension AAA {
    @nonobjc static let value = 111
}

내 프로젝트에는 Objective-C 파일이 있지만 해당 코드 중 어느 것도이 클래스의 인스턴스 ( AAA여기) 와 상호 작용하지 않으므로 명확하다고 생각합니까?
Nicolas Miari

순수한 Swift 코드베이스를 사용하는 경우 선택해야합니다.
idzski

정적 (클래스) vars를 NSManagedObject하위 클래스에 추가하려고했습니다 . 이 문제가 해결되었습니다!
Nicolas Miari

Xcode 7.3에 대한 SourceKitService를 완전히 망칠 수있는이 수정을 찾은 유일한 사람입니까?
NoodleOfDeath 2016

57

클래스가 이러한 조건을 충족하면이 오류가 발생합니다.

  • 에서 서브 클래스 NSObject.
  • 가지고 static let필드.
  • 를 통해 인스턴스 메서드에서 필드에 액세스합니다 dynamicType.

왜 이런 일이 발생하는지 모르겠지만이 해결 방법을 시도해 볼 수 있습니다.

static var value: Int {
    get {
        return 111
    }
}

또는 더 짧은 형식입니다.

static var value: Int {
    return 111
}

사용 static var { get }대신에 static let.


속성 getter 및 호출 비용은 위의 예에서 LLVM 옵티 마이저에 의해 제거 될 가능성이 매우 높지만 명시 적으로 피하는 것이 좋습니다.

이러한 가치 계산 비용이 걱정된다면 한 번 생성하고 이와 같이 캐시 할 수 있습니다.

static var value: Int {
    return cache
}
private let cache = getTheNumber()

또는 캐시의 존재를 완전히 숨기려면 이와 같이하십시오.

static var value: Int {
    struct Local {
        static let cache = getTheNumber()
    }
    return Local.cache
}

5
이렇게하면 모든 액세스에서 다시 계산되는 계산 된 속성이 생성됩니다. 이 경우에는 그다지 중요하지 않을 수 있지만 더 큰 개체에 대해 아무도이 해결 방법을 사용하지 않도록 언급 할 가치가 있다고 생각합니다.
Nick Podratz 2015 년

@NickPodratz이 역시 계산 된 속성일까요? private static let _value: Int = 111 static var value: Int { return _value }그것은 가지고 있지 않지만 get {내가 var대신 사용하면 컴파일러는 계산 된 속성에 대해 뭔가를 언급합니다let
hashier

1
@hashier입니다. 중괄호 안에 클로저를 만들면 get이 경우 암시 적입니다. 대신 할 수있는 일은 클로저가 한 번만 호출되도록 클로저 결과를 변수에 할당하는 것입니다 let value: Int = { return 111 }(). 끝에있는 브래킷은 클로저라고합니다. 그러나 이것은 다시 저장된 속성이므로 확장에서 사용할 수 없습니다.
Nick Podratz

@NickPodratz의 평가에 동의하십시오. 이렇게하면 OP가 언급하는 오류가 해결되어이를 합법적 인 답변으로 만들 수 있지만 변수가 실제로 정적 (요점처럼 보임)이기를 원하는 경우에는 어떤 이점도 제공하지 않습니다. 이 경우 Alex의 대답이 더 좋습니다 (순수 Swift 가정)
Matt Long

18

나도이 오류가 있었다.

내 문제는 신속한 확장 의 정적 변수 였습니다.

extension NotificationsViewController: UITableViewDataSource , UITableViewDelegate {

    static var timeIntervalFormatter = NSDateComponentsFormatter()

}

클래스 구현으로 이동하면 문제가 해결되었습니다.


7

나는 다른 원인으로 동일한 문제를 우연히 발견했으며 동일한 쓸모없는 오류 메시지를 경험하는 다른 사람들을 위해 여기에 게시하고 싶습니다.

확장에 정의 된 계산 된 변수를 재정의하는 최종 클래스도이 오류를 발생시킵니다. 그러나 함수에 대해 작동하므로 컴파일러 버그처럼 보입니다.

// at line 0: a declaration cannot be both 'final' and 'dynamic'

import UIKit

extension UIViewController {
    var test: Int { return 0 }
}

final class TestController: UIViewController {
    override var test: Int { return 1 }
}

7

정적 선언을 확장에서 정의한 새 구조체로 이동하여이 문제를 해결했습니다.

그래서이 대신 :

extension NSOperationQueue {
    static var parsingQueue : NSOperationQueue = {
        let queue = NSOperationQueue()
        queue.maxConcurrentOperationCount = 1
        return queue
        }()
}

나는 이것을 가지고있다:

extension NSOperationQueue {        
    struct Shared {
        static var parsingQueue : NSOperationQueue = {
            let queue = NSOperationQueue()
            queue.maxConcurrentOperationCount = 1
            return queue                
            }()
    }
}

0

이 오류를 방지하기 위해 비공개로 표시 할 수 있습니다. 노출하려면 공용 함수로 래핑 할 수 있습니다.

extension AAA {

    private static let value = 111

    public func getDatValue() -> Int {
        return AAA.value
    }    
}

제 경우에는 확장 자체의 속성 만 참조했기 때문에 노출 할 필요가 없었습니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.