Объявление не может быть как "финальной", так и "динамической" ошибкой в ​​Swift 1.2

Объявление 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)

Ответ 1

Эта проблема возникает из-за того, что Swift пытается создать динамический аксессуар для статического свойства для совместимости с Obj-C, поскольку класс наследует от NSObject.

Если ваш проект работает только в Swift, а не с помощью var accessor, вы можете избежать проблемы с помощью атрибута @nonobjc в Swift 2.0:

import Foundation

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

Ответ 2

Вы получите эту ошибку, если ваш класс удовлетворяет этим условиям.

  • Подклассифицировано из 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
}

Ответ 3

У меня тоже была эта ошибка.

Моя проблема была просто статическим var в быстром расширении.

extension NotificationsViewController: UITableViewDataSource , UITableViewDelegate {

    static var timeIntervalFormatter = NSDateComponentsFormatter()

}

Перемещение его в реализацию класса разрешило проблему для меня.

Ответ 4

Я просто наткнулся на одну и ту же проблему по другой причине и хотел бы опубликовать ее здесь, чтобы другие люди столкнулись с одним и тем же бесполезным сообщением об ошибке.

Заключительный класс, который переопределяет вычисленную переменную, определенную в расширении, также вызывает эту ошибку. Он работает для функций, хотя и, следовательно, выглядит как ошибка компилятора.

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

Ответ 5

Я решил эту проблему, перемещая статическое объявление в новую структуру I, определенную в расширении.

Итак, вместо этого:

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

Ответ 6

Вы можете пометить ее как конфиденциальную, чтобы предотвратить эту ошибку. Если вы хотите открыть его, вы можете обернуть его в открытую функцию:

extension AAA {

    private static let value = 111

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

В моем случае я ссылался только на свойство в самом расширении, поэтому нет необходимости его раскрывать.

Ответ 7

Как небольшое улучшение по сравнению с @Eonil answer, get не нужно:

static var value: Int { return  111 }