Una dichiarazione non può essere sia errore "finale" che errore "dinamico" in Swift 1.2


123

La dichiarazione di valueseguito

import Foundation

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

provoca il seguente errore di compilazione

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

Perché succede e come posso affrontarlo?

Sto usando Swift 1.2 (la versione fornita con Xcode 6.3.1 6D1002)


La func test2dichiarazione non è necessaria per attivare l'errore, a partire da Xcode 7.3.1.
rob mayoff


Basta inserire quella variabile statica in un'altra struttura di denominazione migliore
onmyway133

Risposte:


224

Questo problema si verifica perché Swift sta tentando di generare una funzione di accesso dinamico per la proprietà statica per la compatibilità Obj-C, poiché la classe eredita da NSObject.

Se il tuo progetto è solo in Swift, invece di utilizzare una funzione di varaccesso, puoi evitare il problema tramite l' @nonobjcattributo in Swift 2.0:

import Foundation

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

Il mio progetto ha alcuni file Objective-C, ma nessuno di quel codice interagisce con le istanze di questa classe ( AAAqui), quindi immagino di essere in chiaro?
Nicolas Miari

Questa dovrebbe essere la risposta selezionata se si utilizza una base di codice Swift pura.
idzski

Stavo cercando di aggiungere variabili statiche (classe) a una NSManagedObjectsottoclasse. Questo l'ha risolto!
Nicolas Miari

Sono l'unico che ha trovato questa correzione per rovinare completamente SourceKitService per Xcode 7.3?
NoodleOfDeath

57

Riceverai questo errore se la tua classe soddisfa queste condizioni.

  • Sottoclasse da NSObject.
  • Ha un static letcampo.
  • Accede al campo da un metodo di istanza tramite dynamicType.

Non so perché questo accada, ma puoi provare questa soluzione alternativa.

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

O in forma più breve.

static var value: Int {
    return 111
}

Usa static var { get }invece di static let.


Sebbene sia molto probabile che il getter di proprietà e il suo costo di chiamata vengano eliminati dall'ottimizzatore LLVM nell'esempio precedente, potresti volerlo evitare esplicitamente.

Se sei preoccupato per tale costo di calcolo del valore, puoi crearlo una volta e memorizzare nella cache in questo modo.

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

O come questo se vuoi nascondere completamente l'esistenza della cache.

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

5
Questo produce una proprietà calcolata, che verrà ricalcolata ad ogni accesso. In questo caso potrebbe non essere troppo importante, ma penso che valga la pena menzionarlo in modo che nessuno usi questa soluzione alternativa per oggetti più grandi.
Nick Podratz

@ NickPodratz sarebbe anche questa una proprietà calcolata? private static let _value: Int = 111 static var value: Int { return _value }non ha get {ma il compilatore menziona qualcosa sulla proprietà calcolata se uso varinvece dilet
hashier

1
@hashier lo è. All'interno delle parentesi graffe si crea una chiusura, getin questo caso implicita. Che cosa si può fare, invece è assegnare il risultato della chiusura alla variabile in modo che la chiusura è chiamato solo una volta: let value: Int = { return 111 }(). Le parentesi alla fine chiamano la chiusura. Ma tieni presente che questa è di nuovo una proprietà memorizzata e quindi non disponibile nelle estensioni.
Nick Podratz

D'accordo con la valutazione di @NickPodratz. Sebbene questo risolva l'errore menzionato dall'OP e quindi la rende una risposta legittima, non fornisce alcun vantaggio se desideri che la tua variabile sia effettivamente statica (che sembra il punto). La risposta di Alex è migliore in quel caso (assumendo Swift puro)
Matt Long

18

Anch'io ho avuto questo errore.

Il mio problema era solo una variabile statica in un'estensione rapida.

extension NotificationsViewController: UITableViewDataSource , UITableViewDelegate {

    static var timeIntervalFormatter = NSDateComponentsFormatter()

}

Spostarlo nell'implementazione della classe ha risolto il problema per me.


7

Mi sono appena imbattuto nello stesso problema con una causa diversa e vorrei pubblicarlo qui per altre persone che sperimentano lo stesso messaggio di errore inutile.

Anche una classe finale che sovrascrive una variabile calcolata definita in un'estensione causa questo errore. Funziona per le funzioni e quindi sembra un bug del compilatore.

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

Ho risolto questo problema spostando la dichiarazione statica nella nuova struttura che ho definito nell'estensione.

Quindi, invece di questo:

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

Ho questo:

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

0

Puoi contrassegnarlo come privato per evitare questo errore. Se vuoi esporlo, puoi avvolgerlo in una funzione pubblica:

extension AAA {

    private static let value = 111

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

Nel mio caso, ho fatto riferimento alla proprietà solo nell'estensione stessa, quindi non c'era bisogno di esporla.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.