Swift 1.2'de bir bildirim hem 'son' hem de 'dinamik' hata olamaz


123

Beyanı valueaşağıda

import Foundation

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

aşağıdaki derleme hatasına neden olur

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

Bu neden oluyor ve bununla nasıl başa çıkabilirim?

Swift 1.2 kullanıyorum (Xcode 6.3.1 6D1002 ile gönderilen sürüm)


func test2Deklarasyon Xcode 7.3.1 itibariyle, hataya neden gerekli değildir.
rob mayoff


Bu statik değişkeni daha iyi bir adlandırma
yapısına koyun

Yanıtlar:


224

Bu sorun, sınıfın miras aldığı için Swift'in Obj-C uyumluluğu için statik özellik için dinamik bir erişimci oluşturmaya çalışmasından kaynaklanmaktadır NSObject.

Projeniz yalnızca Swift'deyse, bir varerişimci kullanmak yerine @nonobjc, Swift 2.0'daki öznitelik yoluyla sorunu önleyebilirsiniz :

import Foundation

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

Projemde bazı Objective-C dosyaları var, ancak bu kodların hiçbiri bu sınıfın örnekleriyle etkileşime girmiyor ( AAAburada), bu yüzden sanırım açıkta mıyım?
Nicolas Miari

Saf bir Swift kod tabanı kullanıyorsanız, seçilen cevap bu olmalıdır.
idzski

Bir NSManagedObjectalt sınıfa statik (sınıf) değişkenler eklemeye çalışıyordum . Bu onu düzeltti!
Nicolas Miari

Xcode 7.3 için SourceKitService'i tamamen mahvetmek için bu düzeltmeyi bulan tek kişi ben miyim?
NoodleOfDeath

57

Sınıfınız bu koşulları yerine getirirse bu hatayı alırsınız.

  • Alt sınıf NSObject.
  • Bir Has static letalanı.
  • Alana bir örnek yönteminden aracılığıyla erişir dynamicType.

Bunun neden olduğunu bilmiyorum ama bu geçici çözümü deneyebilirsiniz.

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

Veya daha kısa formda.

static var value: Int {
    return 111
}

static var { get }Bunun yerine kullanın static let.


Mülk alıcı ve arama maliyeti, yukarıdaki örnekte LLVM iyileştirici tarafından büyük olasılıkla ortadan kaldırılsa da, bundan açıkça kaçınmak isteyebilirsiniz.

Bu tür bir değer hesaplama maliyeti konusunda endişeleriniz varsa, bir kez oluşturabilir ve bu şekilde önbelleğe alabilirsiniz.

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

Veya önbelleğin varlığını tamamen gizlemek istiyorsanız bunun gibi.

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

5
Bu, her erişimde yeniden hesaplanacak hesaplanmış bir özellik üretir. Bu durum için çok önemli olmayabilir, ancak kimsenin daha büyük nesneler için bu geçici çözümü kullanmaması için bahsetmeye değer olduğunu düşünüyorum.
Nick Podratz

@NickPodratz bu da hesaplanan bir özellik olur mu? private static let _value: Int = 111 static var value: Int { return _value }It does not have get {kullandığım ama eğer derleyici bilgisayarlı özelliği hakkında bir şey söz varyerinelet
hashier

1
@hashier öyle. Küme parantezlerinin içinde bir kapanış yaratırsınız, getbu durumda örtüktür. Bunun yerine ne olabilir kapatma sadece bir kez çağrılması için değişkene kapanması sonucu atama geçerli: let value: Int = { return 111 }(). Sondaki parantezler kapanışı çağırır. Ancak bunun yine depolanmış bir özellik olduğunu ve bu nedenle uzantılarda kullanılamayacağını unutmayın.
Nick Podratz

@NickPodratz'ın değerlendirmesine katılıyorum. Bu, OP'nin bahsettiği hatayı çözerken ve bu nedenle bunu okunaklı bir cevap haline getirirken, değişkeninizin gerçekten statik olmasını istiyorsanız (ki bu nokta gibi görünüyor) herhangi bir fayda sağlamaz. Alex'in cevabı bu durumda daha iyi (saf Swift olduğunu varsayarsak)
Matt Long

18

Ben de bu hatayı aldım.

Benim sorunum, hızlı bir uzantıdaki statik bir değişkendi .

extension NotificationsViewController: UITableViewDataSource , UITableViewDelegate {

    static var timeIntervalFormatter = NSDateComponentsFormatter()

}

Bunu sınıf uygulamasına taşımak sorunu benim için çözdü.


7

Aynı konuyu farklı bir nedenden ötürü tökezledim ve aynı işe yaramaz hata mesajını yaşayan diğer insanlar için buraya göndermek istiyorum.

Bir uzantıda tanımlanan hesaplanmış bir değişkeni geçersiz kılan son bir sınıf da bu hataya neden olur. Yine de işlevler için çalışır ve bu nedenle bir derleyici hatası gibi görünür.

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

Statik bildirimi uzantıda tanımladığım yeni yapıya taşıyarak bu sorunu çözdüm.

Yani bunun yerine:

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

Bu bende var:

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

0

Bu hatayı önlemek için özel olarak işaretleyebilirsiniz. Eğer ifşa etmek istiyorsanız, onu herkese açık bir fonksiyona sarabilirsiniz:

extension AAA {

    private static let value = 111

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

Benim durumumda, mülke yalnızca uzantının kendisinde başvurdum, bu yüzden onu ifşa etmeye gerek yoktu.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.