Deklarasi tidak bisa berupa error 'final' dan 'dynamic' di Swift 1.2

123

Deklarasi di valuebawah ini

import Foundation

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

menyebabkan kesalahan kompilasi berikut

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

Mengapa ini terjadi, dan bagaimana saya mengatasinya?

Saya menggunakan Swift 1.2 (versi dikirimkan dalam Xcode 6.3.1 6D1002)

eonil
sumber
The func test2deklarasi tidak diperlukan untuk memicu kesalahan, karena dari Xcode 7.3.1.
merampok mayoff
1
Bug cepat SR-993
merampok mayoff
Masukkan

Jawaban:

224

Masalah ini muncul karena Swift mencoba membuat pengakses dinamis untuk properti statis untuk kompatibilitas Obj-C, karena kelas mewarisi dari NSObject.

Jika proyek Anda hanya di Swift, daripada menggunakan varpengakses, Anda dapat menghindari masalah melalui @nonobjcatribut di Swift 2.0:

import Foundation

class AAA: NSObject {}
extension AAA {
    @nonobjc static let value = 111
}
Alex Pretzlav
sumber
Proyek saya memiliki beberapa file Objective-C, tetapi tidak satupun dari kode itu berinteraksi dengan instance dari kelas ini (di AAAsini), jadi saya rasa saya jelas?
Nicolas Miari
Ini harus menjadi jawaban yang dipilih jika menggunakan basis kode Swift murni.
idzski
Saya mencoba menambahkan vars (kelas) statis ke NSManagedObjectsubkelas. Ini memperbaikinya!
Nicolas Miari
Apakah saya satu-satunya yang menemukan perbaikan ini benar-benar mengacaukan SourceKitService untuk Xcode 7.3?
NoodleOfDeath
57

Anda akan mendapatkan kesalahan ini jika kelas Anda memenuhi ketentuan ini.

  • Disubkelas dari NSObject.
  • Memiliki static letlapangan.
  • Mengakses bidang dari metode contoh melalui dynamicType.

Saya tidak tahu mengapa ini terjadi, tetapi Anda dapat mencoba solusi ini.

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

Atau dalam bentuk yang lebih pendek.

static var value: Int {
    return 111
}

Gunakan static var { get }sebagai ganti static let.


Meskipun pengambil properti dan biaya panggilannya sangat mungkin dihilangkan oleh pengoptimal LLVM dalam contoh di atas, Anda mungkin ingin menghindarinya secara eksplisit.

Jika Anda khawatir tentang biaya kalkulasi nilai tersebut, Anda dapat membuatnya sekali dan menyimpan cache seperti ini.

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

Atau seperti ini jika ingin menyembunyikan keberadaan cache sepenuhnya.

static var value: Int {
    struct Local {
        static let cache = getTheNumber()
    }
    return Local.cache
}
eonil
sumber
5
Ini menghasilkan properti yang dihitung, yang akan dihitung ulang di setiap akses. Untuk kasus ini mungkin tidak terlalu menjadi masalah, tapi saya pikir itu layak disebutkan sehingga tidak ada yang menggunakan solusi ini untuk objek yang lebih besar.
Nick Podratz
@NickPodratz, apakah ini akan menjadi properti yang dihitung juga? private static let _value: Int = 111 static var value: Int { return _value }itu tidak memiliki get {tetapi kompiler menyebutkan sesuatu tentang properti yang dihitung jika saya gunakan varsebagai gantilet
hashier
1
@hashier itu. Di dalam kurung kurawal Anda membuat penutupan, getdalam hal ini implisit. Apa yang dapat Anda lakukan malah menetapkan hasil penutupan ke variabel sehingga penutupan disebut hanya sekali: let value: Int = { return 111 }(). Tanda kurung di bagian akhir memanggil penutupan. Tetapi ketahuilah bahwa ini adalah properti yang disimpan lagi dan oleh karena itu tidak tersedia dalam ekstensi.
Nick Podratz
Setuju dengan penilaian @NickPodratz. Meskipun ini menyelesaikan kesalahan yang disebutkan OP dan oleh karena itu menjadikan ini jawaban yang sah, itu tidak memberikan manfaat apa pun jika Anda ingin variabel Anda benar-benar statis (yang sepertinya intinya). Jawaban Alex lebih baik dalam hal itu (dengan asumsi Swift murni)
Matt Long
18

Saya mengalami kesalahan ini juga.

Masalah saya hanyalah var statis dalam ekstensi cepat.

extension NotificationsViewController: UITableViewDataSource , UITableViewDelegate {

    static var timeIntervalFormatter = NSDateComponentsFormatter()

}

Memindahkannya ke implementasi kelas menyelesaikan masalah bagi saya.

JulianM
sumber
7

Saya baru saja tersandung masalah yang sama dengan penyebab yang berbeda dan ingin mempostingnya di sini untuk orang lain yang mengalami pesan kesalahan tidak berguna yang sama.

Kelas terakhir yang menimpa variabel terhitung yang ditentukan dalam ekstensi juga menyebabkan kesalahan ini. Ia bekerja untuk fungsi dan dengan demikian terlihat seperti bug kompilator.

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

Saya memecahkan masalah ini dengan memindahkan deklarasi statis ke dalam struct baru yang saya tetapkan di ekstensi.

Jadi, alih-alih ini:

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

Aku punya ini:

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

Anda dapat menandainya sebagai pribadi untuk mencegah kesalahan ini. Jika Anda ingin mengeksposnya, Anda dapat membungkusnya dalam fungsi publik:

extension AAA {

    private static let value = 111

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

Dalam kasus saya, saya hanya mereferensikan properti di ekstensi itu sendiri, jadi tidak perlu mengungkapkannya.

pulse4life
sumber
0

Sebagai sedikit perbaikan atas jawaban @ Eonil , yang gettidak perlu:

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