web-dev-qa-db-fra.com

Une déclaration ne peut pas être à la fois une erreur "finale" et "dynamique" dans Swift 1.2

La déclaration de value ci-dessous

import Foundation

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

provoque l'erreur de compilation suivante

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

Pourquoi cela se produit-il et comment puis-je gérer cela?

J'utilise Swift 1.2 (la version fournie avec Xcode 6.3.1 6D1002)

123
Eonil

Ce problème se pose car Swift tente de générer un accesseur dynamique pour la propriété statique assurant la compatibilité Obj-C, car la classe hérite de NSObject.

Si votre projet est dans Swift uniquement, plutôt que d'utiliser un accesseur var, vous pouvez éviter le problème via le @nonobjc attribut dans Swift 2.0:

import Foundation

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

Vous obtiendrez cette erreur si votre classe remplit ces conditions.

  • Sous-classé de NSObject.
  • A un static let champ.
  • Accède au champ à partir d'une méthode d'instance via dynamicType.

Je ne sais pas pourquoi cela se produit, mais vous pouvez essayer cette solution de contournement.

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

Ou sous une forme plus courte.

static var value: Int {
    return 111
}

Utilisation static var { get } au lieu de static let.


Bien que, dans l'exemple ci-dessus, l'optimiseur LLVM élimine très probablement la fermeture du getter de propriété et son coût d'appel, vous souhaiterez peut-être l'éviter explicitement.

Si ce coût de calcul de la valeur vous préoccupe, vous pouvez le créer une seule fois et le mettre en cache de cette manière.

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

Ou comme ceci si vous voulez cacher le cache complètement.

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

J'ai aussi eu cette erreur.

Mon problème était juste un var statique dans une extension Swift.

extension NotificationsViewController: UITableViewDataSource , UITableViewDelegate {

    static var timeIntervalFormatter = NSDateComponentsFormatter()

}

Le déplacer vers la mise en œuvre de la classe a résolu le problème pour moi.

18
JulianM

Je suis tombé par hasard sur le même problème avec une cause différente et voudrais l'afficher ici pour que d'autres personnes rencontrent le même message d'erreur inutile.

Une dernière classe qui remplace une variable calculée définie dans une extension provoque également cette erreur. Cela fonctionne pour les fonctions bien et ressemble donc à un bogue du compilateur.

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

J'ai résolu ce problème en déplaçant la déclaration statique dans la nouvelle structure que j'ai définie dans l'extension.

Donc au lieu de cela:

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

J'ai ceci:

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

Comme une légère amélioration par rapport à @ Eonil's answer , le get n'est pas nécessaire:

static var value: Int { return  111 }
0
Yuchen Zhong

Vous pouvez le marquer comme privé pour éviter cette erreur. Si vous souhaitez l'exposer, vous pouvez l'envelopper dans une fonction publique:

extension AAA {

    private static let value = 111

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

Dans mon cas, je n'ai fait référence qu'à la propriété dans l'extension elle-même, il n'était donc pas nécessaire de l'exposer.

0
pulse4life