问题描述
当我尝试在SwiftUI中调用dataTask方法下载数据后,使用DownloadCryptocurrencyImages()方法在dataTask方法中缓存图片时,发现如下报错:
Call to method 'DownloadCryptocurrencyImages' in closure requires explicit use of 'self' to make capture semantics explicit

报错代码:
func fetchCryptoData(context: NSManagedObjectContext) {
let task = URLSession.shared.dataTask(with: apiURL) { data, response, error in // URLSession方法闭包
// 检查响应数据
if let data = data {
// 下载加密货币的图片
DownloadCryptocurrencyImages(imageURL: coin.image, imageName: coin.symbol) // 报错代码
}
}
task.resume() // 启动任务
}
问题原因
问题原因在于报错代码DownloadCryptocurrencyImages是一个实例方法,当在闭包(URLSession下载)或异步上下文中调用时,Swift会要求显式加上self,这是强调引用实例自身的方法。
这是Swift的语法规范,避免在闭包中捕获self,导致内部泄漏。
在Swift中,普通的方法:
func DownloadCryptocurrencyImages(imageURL: URL, imageName: String) {
// 逻辑不重要
}
如果实在类中定义的:
class MyViewModel {
func DownloadCryptocurrencyImages(...) {
...
}
}
这就不是普通的方法,而是实例方法,调用它时其实等价于:
self.DownloadCryptocurrencyImages(...)
在Swift的闭包中使用 self.属性 或者 self.方法 ,Swift会强制要求显式写出self,避免无意识的捕获self,从而造成内存泄漏。
解决方案
这个问题的解决方案很简单,点击Xcode提示的fix按钮:
Reference 'self.' explicitly
Capture 'self' explicitly to enable implicit 'self' in this closure
在报错方法前面添加self:
// 下载加密货币的图片
self.DownloadCryptocurrencyImages(imageURL: coin.image, imageName: coin.symbol)
或者在闭包中开启弱引用:
func fetchCryptoData(context: NSManagedObjectContext) {
let task = URLSession.shared.dataTask(with: apiURL) { [self] data, response, error in // 添加[self]以捕获self引用
// 检查响应数据
if let data = data {
// 下载加密货币的图片
DownloadCryptocurrencyImages(imageURL: coin.image, imageName: coin.symbol) // 报错代码
}
}
task.resume() // 启动任务
}
如果不想用self,可以定义为static方法(类方法,不依赖self)。
class MyViewModel {
static func DownloadCryptocurrencyImages(...) {
...
}
}
也可以写在类的外卖,变成自由函数(全局函数)。
func DownloadCryptocurrencyImages(...) {
...
}
这样就可以在任何地方调用它,并且不用写self。
总结
只要定义在类(或结构体)内的方法,都是实例方法,在闭包中调用时必须使用.self。