You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift代理模式传值报错:CoinManager与ViewController代理配置问题

问题解决:代理模式实现中的类型不匹配与实例调用错误

你的两个错误根源都在于CoinManager中delegate的定义错误,把协议实例的存储写成了协议类型的引用,导致赋值和方法调用都出现类型不匹配问题。以下是具体修正方案:

错误原因拆解

  1. Cannot assign value of type 'ViewController' to type '(any CoinManagerDelegate)?.Type':你在CoinManager里把delegate定义成了CoinManagerDelegate?.self,这是协议的元类型(Type),而self(ViewController实例)是协议的实例对象,类型完全不匹配,所以无法赋值。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:01:44