Một tuyên bố không thể là cả lỗi 'cuối cùng' và 'động' trong Swift 1.2


123

Tuyên bố valuedưới đây

import Foundation

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

gây ra lỗi biên dịch sau

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

Tại sao điều này xảy ra, và làm thế nào tôi có thể đối phó với điều này?

Tôi đang sử dụng Swift 1.2 (phiên bản được gửi trong Xcode 6.3.1 6D1002)


Các func test2tuyên bố là không cần thiết để kích hoạt lỗi, tính đến Xcode 7.3.1.
cướp mayoff


Chỉ cần đặt biến tĩnh đó vào một cấu trúc đặt tên khác tốt hơn
onmyway133

Câu trả lời:


224

Vấn đề này phát sinh do Swift đang cố gắng tạo một trình truy cập động cho thuộc tính tĩnh để tương thích Obj-C, do lớp kế thừa từ đó NSObject.

Nếu dự án của bạn chỉ ở Swift, thay vì sử dụng trình truy cập, varbạn có thể tránh sự cố thông qua @nonobjcthuộc tính trong Swift 2.0:

import Foundation

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

Dự án của tôi có một số tệp Objective-C, nhưng không có mã nào tương tác với các thể hiện của lớp này ( AAAở đây), vì vậy tôi đoán tôi đang rõ ràng?
Nicolas Miari

Đây phải là câu trả lời được chọn nếu sử dụng một cơ sở mã Swift thuần túy.
idzski

Tôi đã cố gắng thêm các vars tĩnh (lớp) vào một NSManagedObjectlớp con. Cái này đã sửa rồi!
Nicolas Miari

Tôi có phải là người duy nhất đã tìm thấy bản sửa lỗi này để hoàn toàn làm hỏng SourceKitService cho Xcode 7.3 không?
NoodleOfDeath

57

Bạn sẽ nhận được lỗi này nếu lớp của bạn thỏa mãn các điều kiện này.

  • Phân lớp từ NSObject.
  • Có một static letlĩnh vực.
  • Truy cập trường từ một phương thức thể hiện thông qua dynamicType.

Tôi không biết tại sao điều này xảy ra, nhưng bạn có thể thử cách giải quyết này.

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

Hoặc ở dạng ngắn hơn.

static var value: Int {
    return 111
}

Sử dụng static var { get }thay vì static let.


Mặc dù getter property và chi phí gọi của nó rất có thể bị loại bỏ bởi trình tối ưu hóa LLVM trong ví dụ trên, bạn có thể muốn tránh nó một cách rõ ràng.

Nếu bạn lo ngại về chi phí tính toán giá trị như vậy, bạn có thể tạo nó một lần và lưu trữ như thế này.

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

Hoặc như thế này nếu bạn muốn ẩn hoàn toàn sự tồn tại của bộ đệm.

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

5
Điều này tạo ra một thuộc tính được tính toán, sẽ được tính toán lại ở mỗi lần truy cập. Trong trường hợp này, nó có thể không quá quan trọng, nhưng tôi nghĩ rằng nó đáng được đề cập để không ai sử dụng cách giải quyết này cho các đối tượng lớn hơn.
Nick Podratz

@NickPodratz đây có phải là một tài sản được tính toán không? private static let _value: Int = 111 static var value: Int { return _value }nó không có get {nhưng trình biên dịch đề cập vài thứ về thuộc tính được tính nếu tôi sử dụng varthay vìlet
hashier 17/8/2016

1
@hashier là vậy. Bên trong các dấu ngoặc nhọn bạn tạo ra một bao đóng, gettrong trường hợp này là ẩn. Thay vào đó, những gì bạn có thể làm là gán kết quả của bao đóng cho biến để đóng được gọi chỉ một lần : let value: Int = { return 111 }(). Các dấu ngoặc ở cuối gọi đóng cửa. Nhưng hãy lưu ý rằng đây là một thuộc tính được lưu trữ lại và do đó không có sẵn trong các tiện ích mở rộng.
Nick Podratz 17/8/2016

Đồng ý với đánh giá của @NickPodratz. Mặc dù điều này giải quyết lỗi mà OP đề cập và do đó biến điều này thành một câu trả lời hợp pháp, nhưng nó không mang lại bất kỳ lợi ích nào nếu bạn muốn biến của mình thực sự tĩnh (có vẻ như là điểm). Câu trả lời của Alex tốt hơn trong trường hợp đó (giả sử Swift thuần túy)
Matt Long

18

Tôi cũng có lỗi này.

Vấn đề của tôi chỉ là một var tĩnh trong một phần mở rộng nhanh chóng.

extension NotificationsViewController: UITableViewDataSource , UITableViewDelegate {

    static var timeIntervalFormatter = NSDateComponentsFormatter()

}

Chuyển nó đến lớp thực hiện đã giải quyết vấn đề cho tôi.


7

Tôi chỉ vấp phải vấn đề tương tự với một nguyên nhân khác và muốn đăng nó ở đây cho những người khác gặp cùng một thông báo lỗi vô dụng.

Một lớp cuối cùng ghi đè lên một biến được tính toán được xác định trong một phần mở rộng cũng gây ra lỗi này. Nó hoạt động cho các chức năng mặc dù và do đó trông giống như một lỗi trình biên dịch.

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

Tôi đã giải quyết vấn đề này bằng cách di chuyển khai báo tĩnh vào cấu trúc mới mà tôi đã xác định trong phần mở rộng.

Vì vậy, thay vì điều này:

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

Tôi có cái này:

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

0

Bạn có thể đánh dấu nó là riêng tư để ngăn chặn lỗi này. Nếu bạn muốn phơi bày nó, bạn có thể gói nó trong một chức năng công khai:

extension AAA {

    private static let value = 111

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

Trong trường hợp của tôi, tôi chỉ tham chiếu tài sản trong phần mở rộng, vì vậy không cần phải phơi bày.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.