Swift 1.2では、宣言を「最終」エラーと「動的」エラーの両方にすることはできません


123

value以下の宣言

import Foundation

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

次のコンパイルエラーが発生します

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

なぜこれが起こるのですか、どうすればこれに対処できますか?

Swift 1.2(Xcode 6.3.1 6D1002に同梱されているバージョン)を使用しています


func test2宣言は、Xcodeの7.3.1のように、エラーをトリガする必要はありません。
rob mayoff 2016年


その静的変数を別のより良いネーミング構造体に入れてください
onmyway133

回答:


224

この問題は、クラスがから継承するため、SwiftがObj-C互換性のために静的プロパティの動的アクセサーを生成しようとしているために発生しNSObjectます。

プロジェクトがSwiftのみの場合、varアクセサーを使用するのではなく@nonobjc、Swift 2.0の属性を使用して問題を回避できます。

import Foundation

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

私のプロジェクトにはいくつかのObjective-Cファイルがありますが、そのコードはこのクラス(AAAここ)のインスタンスと相互作用しません。そのため、私ははっきりしていると思いますか?
Nicolas Miari、2015年

純粋なSwiftコードベースを使用する場合は、これが選択された答えになるはずです。
idzski、2015年

静的(クラス)変数をNSManagedObjectサブクラスに追加しようとしました。これで解決しました!
Nicolas Miari、2016

Xcode 7.3のSourceKitServiceを完全に台無しにするこの修正を見つけたのは私だけですか?
NoodleOfDeath

57

クラスがこれらの条件を満たす場合、このエラーが発生します。

  • からサブクラス化 NSObject
  • があります static letフィールドます。
  • を介してインスタンスメソッドからフィールドにアクセスしますdynamicType

これがなぜ発生するのかはわかりませんが、この回避策を試すことができます。

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

または短い形式で。

static var value: Int {
    return 111
}

static var { get }代わりに使用しますstatic let


上記の例では、プロパティゲッターとその呼び出しコストはLLVMオプティマイザーによって排除される可能性が非常に高いですが、明示的に回避することをお勧めします。

このような値の計算コストが心配な場合は、一度作成して、このようにキャッシュできます。

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

または、キャッシュの存在を完全に隠したい場合は、このようにします。

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

5
これにより、計算されたプロパティが生成され、アクセスのたびに再計算されます。この場合はそれほど重要ではないかもしれませんが、大きなオブジェクトにこの回避策を使用しないように、言及する価値があると思います。
Nick Podratz 2015年

@NickPodratzこれも計算されたプロパティでしょうか?private static let _value: Int = 111 static var value: Int { return _value }それは持っていませんが、代わりget {に使用する場合、コンパイラは計算されたプロパティについて何か言及していますvarlet
ハシエ

1
@hashierです。中かっこ内でクロージャを作成するgetと、この場合は暗黙的です。代わりに、クロージャの結果を変数に割り当てて、クロージャが1回だけ呼び出されるようにすることができますlet value: Int = { return 111 }()。最後の括弧はクロージャを呼び出します。ただし、これは格納されたプロパティであるため、拡張機能では使用できないことに注意してください。
Nick Podratz 2016

@NickPodratzの評価に同意します。これはOPが言及するエラーを解決し、したがってこれを正当な答えにしますが、変数を実際に静的にしたい場合(これは要点のように思われます)、メリットはありません。その場合、アレックスの回答の方が優れています(純粋なSwiftを想定)
Matt Long

18

私にもこのエラーがありました。

私の問題は、迅速な拡張機能の静的変数でした。

extension NotificationsViewController: UITableViewDataSource , UITableViewDelegate {

    static var timeIntervalFormatter = NSDateComponentsFormatter()

}

クラスの実装に移動すると、問題が解決しました。


7

同じ問題を別の原因で偶然見つけたので、同じ役に立たないエラーメッセージが表示される他の人のためにここに投稿したいと思います。

エクステンションで定義された計算された変数をオーバーライドする最後のクラスもこのエラーを引き起こします。ただし、関数に対しては機能するため、コンパイラのバグのように見えます。

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

この問題を解決するには、静的宣言を拡張機能で定義した新しい構造体に移動しました。

これの代わりに:

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

私はこれを持っています:

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

0

このエラーを防ぐために、プライベートとしてマークできます。それを公開したい場合は、パブリック関数でラップできます。

extension AAA {

    private static let value = 111

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

私の場合、エクステンション自体でプロパティを参照するだけなので、公開する必要はありませんでした。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.