【问题标题】:Cannot use mutating member on immutable value: 'self' is immutable不能对不可变值使用变异成员:'self' 是不可变的
【发布时间】:2018-08-01 00:15:49
【问题描述】:

我不明白为什么会出现此错误。 SomeController 是一个类,而不是一个结构,它不是不可变的。有解决办法吗?

class SomeController: APIFetchable {

    let baseUrl = "https://jsonplaceholder.typicode.com"
    let defaultSession =  URLSession(configuration: .default)
    var dataTask: URLSessionTask?

    func fetchDataFromAPI(atPath path: String, _ callback: ()-> Void){
        fetchDataAtPath(path) { data, error in  /*Error on this line -> "Cannot use mutating member on immutable value: 'self' is immutable"*/

        }
    }

}


protocol APIFetchable {
    var baseUrl: String {get}
    var defaultSession: URLSession {get}
    var dataTask: URLSessionTask? {get set}

    mutating func fetchDataAtPath(_ path: String,  _ callback: @escaping (Data?, Error?)-> Void)
}

extension APIFetchable {

    mutating func fetchDataAtPath(_ path: String,  _ callback: @escaping (Data?, Error?)-> Void){
        dataTask?.cancel()

        if var urlComponents = URLComponents(string: baseUrl) {
            urlComponents.path = path

            guard let url = urlComponents.url else {return}

            dataTask = defaultSession.dataTask(with: url) { data, response, error in
                defer {self.dataTask =  nil}

                if let error = error {
                    print("data task error \(error.localizedDescription)")
                    callback(nil, error)
                } else if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 {
                    callback(data, nil)
                }
            }
            dataTask?.resume()
        }
    }


}

【问题讨论】:

  • 您确定不是defer {self.dataTask = nil} 导致错误吗?
  • 如果您将协议更改为protocol APIFetchable: class 并删除mutating 的使用,所有错误都会消失。
  • 注释掉defer 语句没有任何效果。 @rmaddy,这行得通。所以我必须以一种只允许它被类遵守的方式定义协议?而不是结构?由于结构是一种值类型,它在写入时通过“let”复制,因此您无法更改它。我的理解正确吗?
  • 我刚刚注意到了仅限类的解决方案。希望一位 Swift 大师会发布一个适用于类和结构的适当解决方案。

标签: swift swift4 protocol-oriented


【解决方案1】:

看起来您有 2 个选项可以解决此问题(根据 this page)。

  1. SomeController 上实现fetchDataAtPath() 的非变异版本。
  2. APIFetchable 协议标记为仅类:protocol APIFetchable: class { ... },并删除变异的使用(正如@rmaddy 在 OP 上的 cmets 中提到的那样)

【讨论】:

  • 前两个有效,但将 SomeController 设为结构并不能解决错误
  • 对 #2 的附加说明,从 Swift 4+ 开始,APIFetchable: AnyObject { ... } 是首选。
猜你喜欢
  • 2020-07-27
  • 2020-01-28
  • 1970-01-01
  • 1970-01-01
  • 2020-10-23
  • 2019-12-10
  • 1970-01-01
  • 2020-08-08
  • 2019-01-06
相关资源
最近更新 更多