Swift代理模式传值报错:CoinManager与ViewController代理配置问题
问题解决:代理模式实现中的类型不匹配与实例调用错误
你的两个错误根源都在于CoinManager中delegate的定义错误,把协议实例的存储写成了协议类型的引用,导致赋值和方法调用都出现类型不匹配问题。以下是具体修正方案:
错误原因拆解
Cannot assign value of type 'ViewController' to type '(any CoinManagerDelegate)?.Type':你在CoinManager里把delegate定义成了CoinManagerDelegate?.self,这是协议的元类型(Type),而self(ViewController实例)是协议的实例对象,类型完全不匹配,所以无法赋值。Type '(any CoinManagerDelegate)?' has no member 'didUpdatePrice':因为delegate是元类型,不是实例,元类型本身没有didUpdatePrice这个实例方法,自然调用失败。
修正步骤
1. 将CoinManager从struct改为class
因为weak修饰符只能用于类实例(值类型struct无法使用weak),而代理模式中为了避免循环引用,必须用weak修饰delegate。
2. 修正delegate的定义
把元类型的定义改成弱引用的可选协议实例。
3. 安全调用delegate方法
调用前先判断delegate是否存在,避免空值崩溃。
修改后的完整CoinManager代码
import Foundation protocol CoinManagerDelegate: NSObjectProtocol { func didUpdatePrice(price: String, currency: String) } // 把struct改为class class CoinManager { // 修正delegate定义:弱引用的可选协议实例 weak var delegate: CoinManagerDelegate? let baseURL = "https://rest.coinapi.io/v1/exchangerate/BTC" let apiKey = "#API_KEY" let currencyArray = ["AUD", "BRL","CAD","CNY","EUR","GBP","HKD","IDR","ILS","INR","JPY","MXN","NOK","NZD","PLN","RON","RUB","SEK","SGD","USD","ZAR"] func getCoinPrice(for currency: String){ let urlString = "\(baseURL)/\(currency)?apikey=\(apiKey)" if let url = URL(string: urlString) { let session = URLSession(configuration: .default) let task = session.dataTask(with: url) { [weak self] data, response, error in guard let self = self else { return } if error != nil { print("error") return } if let safeData = data { guard let rate = self.parseJSON(safeData) else { print("Failed to parse data") return } let dataString = String(format: "%.2f", rate) // 可选绑定后安全调用delegate方法 self.delegate?.didUpdatePrice(price: dataString, currency: currency) } } task.resume() } } func parseJSON(_ data: Data) -> Double? { let decoder = JSONDecoder() do{ let decodedData = try decoder.decode(CoinData.self, from: data) return decodedData.rate } catch { print("Parsing error: \(error)") return nil } } }
额外优化点
- 在网络请求的闭包中添加
[weak self]避免循环引用(闭包会捕获self) - 对
parseJSON的返回值添加guard判断,处理解析失败的情况 - 打印具体的解析错误,方便调试
ViewController的代码不需要修改,现在coinManager.delegate = self可以正常赋值,didUpdatePrice方法也能被正确调用。
内容的提问来源于stack exchange,提问作者seanka
相关产品推荐
相关产品推荐

