Декларація не може бути як "остаточною", так і "динамічною" помилками в 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Декларації не потрібно , щоб викликати помилку, так як з Xcode 7.3.1.
грабувати майофф


Просто помістіть цю статичну змінну в іншу структуру кращого іменування
onmyway133

Відповіді:


224

Ця проблема виникає тому, що Swift намагається генерувати динамічний аксесуар для статичної властивості для сумісності Obj-C, оскільки клас успадковує від NSObject.

Якщо ваш проект працює лише в Swift, замість використання varаксесуара, ви можете уникнути проблеми через @nonobjcатрибут Swift 2.0:

import Foundation

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

У моєму проекті є кілька файлів Objective-C, але жоден із цього коду не взаємодіє з екземплярами цього класу ( AAAтут), тож я думаю, я зрозумів?
Ніколас Міарі

Це має бути обрана відповідь, якщо використовується чиста база даних Swift.
idzski

Я намагався додати до NSManagedObjectпідкласу статичні (клас) vars . Це це виправило!
Nicolas Miari

Я єдиний, хто знайшов це виправлення, щоб повністю викрутити SourceKitService для Xcode 7.3?
NoodleOfDeath

57

Ви отримаєте цю помилку, якщо ваш клас задовольняє цим умовам.

  • Підкласи від NSObject.
  • Має static letполе.
  • Доступ до поля з методу екземпляра через dynamicType.

Я не знаю, чому це відбувається, але ви можете спробувати це вирішити.

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

Або в коротшій формі.

static var value: Int {
    return 111
}

Використовуйте static var { get }замість static let.


Хоча отримувач власності та вартість його дзвінків дуже імовірно усунені оптимізатором 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
Це створює обчислюване властивість, яке буде перераховано при кожному доступі. У цьому випадку це може не мати великого значення, але я думаю, що це варто згадати, щоб ніхто не використовував це рішення для великих об'єктів.
Нік Подратц

@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 }(). Кронштейни в кінці викликають закриття. Але майте на увазі, що це знову зберігається властивість і тому недоступне у розширеннях.
Нік Подратц

Погодьтеся з оцінкою @NickPodratz. Хоча це усуває помилку, про яку згадує ОП, і тому робить це законною відповіддю, це не приносить користі, якщо ви хочете, щоб ваша змінна фактично була статичною (що здається суттєвим). Відповідь Алекса в цьому випадку краща (припускаючи чистого Свіфта)
Метт Лонг

18

У мене була і ця помилка.

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

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

У моєму випадку я посилався лише на властивість у самому розширенні, тому не було потреби його виставляти.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.