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)
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
}
Vous obtiendrez cette erreur si votre classe remplit ces conditions.
NSObject
.static let
champ.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
}
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.
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 }
}
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
}()
}
}
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 }
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.