意外无法分配给 属性 'self' 是不可变的编译时错误 IN CLASS

Unexpected Cannot assign to property 'self' is immutable compile time error IN CLASS

现在这是 Swift 编译器的一个奇怪行为。我在 class 中遇到 Cannot assign to property 'self' is immutable 编译时错误。这是最小的游乐场代码:

import UIKit

open class TextInputTraitsWrapper: NSObject {
    private var wrapped: UITextInputTraits
    
    public init(wrapped: UITextDocumentProxy) {
        self.wrapped = wrapped
        super.init()
    }
    
    open var keyboardAppearance: UIKeyboardAppearance {
        get {
            return wrapped.keyboardAppearance ?? UIKeyboardAppearance.default
        }
        set {
            wrapped.keyboardAppearance = newValue // ERROR ON THIS LINE
        }
    }
}

这是我得到的错误(这是完整的程序):

作为旁注协议 UITextInputTraits 定义 keyboardAppearance 如下:optional var keyboardType: UIKeyboardType { get set }.

为什么我会在 class 中出现这种错误??

该错误与您创建的 class 无关。它与您的变量“包装”的底层协议有关。不能直接修改keyboardAppearance 属性.

相反,您需要在源代码处对其进行修改。那是用户输入的 textfield/search 栏。

要做到这一点,只需访问您的 UITextField /UISearchBar 并在那里更改 keyboardAppearance 属性。

textField.keyboardAppearance = UIKeyboardAppearance.dark

这是一个错误,但不是您可能认为的错误(错误消息根本没有帮助)。这是一个 known bug,因为 UITextInputTraits 协议的 keyboardAppearance 属性 是一个 optional 属性(这意味着它可能无法实现)。这是一个 Objective C 功能,而不是 Swift 功能,错误是这些属性不能直接在 Swift 中设置,即使它们被标记为 {get set}.

为了看到这一点,让我们为自己模拟相同的模式:

@objc public protocol P {
    @objc optional var keyboardAppearance : NSString {get set}
}

open class C : NSObject {
    private var wrapped: P
    public init(wrapped: P) {
        self.wrapped = wrapped
        super.init()
    }
    open var keyboardAppearance : NSString {
        get {
            wrapped.keyboardAppearance ?? "" as NSString
        }
        set {
            wrapped.keyboardAppearance = newValue
        }
    }
}

我们得到同样的错误。但是,如果删除关键字 optional,错误就会消失。这证明 optional 是导致问题的原因。但是在你的情况下你不能删除 optional,因为那个协议不属于你。

解决方法与原始错误相同 — 使用密钥路径:

let kp = \C.wrapped.keyboardAppearance
self[keyPath:kp] = newValue