SwiftUI转义闭包捕获可变'self'参数 在init()中调用接口报错如何解决
报错原因
这个编译错误的核心逻辑是:你当前使用的是值类型(绝大多数场景是SwiftUI的struct类型View),URLSession.shared.dataTask的尾随闭包属于逃逸闭包,Swift默认禁止逃逸闭包捕获可变的值类型self。你把getActivity()放在init()方法中调用时,当前实例还处于未完成初始化的可变状态,被逃逸闭包捕获就会触发这个报错。
可落地的解决方法
方案1(最符合SwiftUI规范):把网络请求的调用时机从
init()移到View的onAppear修饰符中
SwiftUI的View初始化仅用来做轻量的属性赋值,异步网络请求本身就不适合放在init里执行。你可以直接删除init中的getActivity()调用,改为在View的结构末尾加onAppear触发:struct YourView: View { @State private var activity: [ResponseActivity] = [ResponseActivity()] // 其他属性、getActivity方法不变 var body: some View { // 你的原有视图代码 } .onAppear { getActivity { result in if let result = result { activity = result } } } }方案2:提前捕获需要的值,不在逃逸闭包中引用
self
如果你确实需要在初始化阶段就触发请求,可以在构造请求前把需要用到的userInfo.login提前存到局部变量,不要在闭包里引用self,修改getActivity里的URL构造部分即可:func getActivity(completion: @escaping ([ResponseActivity]?) -> ()){ var userInfo: [ResponseActivity] = [ResponseActivity()] // 提前把需要的值取出来,后续不再引用self let login = self.userInfo.login let url = URL(string: "https://api.github.com/users/\(login)/received_events")! let urlRequest = URLRequest(url: url) print("self.userInfo.login", login) let task = URLSession.shared.dataTask(with: urlRequest) { data, urlResponse, error in guard let content = data else { print("Error getting data from API.") return } do { userInfo = try JSONDecoder().decode([ResponseActivity].self, from: content) } catch { print("Error parsing URL from data Activity.") return } completion(userInfo) } task.resume() }方案3:将网络请求逻辑抽离到
ObservableObject类中
对于复杂度稍高的网络请求,更推荐把请求逻辑、状态都放到独立的类中管理,类属于引用类型,不存在逃逸闭包捕获可变self的问题:class ActivityViewModel: ObservableObject { @Published var activity: [ResponseActivity] = [ResponseActivity()] let userInfo: UserInfo // 替换为你实际的userInfo类型 init(userInfo: UserInfo) { self.userInfo = userInfo getActivity() } func getActivity() { var userInfo: [ResponseActivity] = [ResponseActivity()] let url = URL(string: "https://api.github.com/users/\(self.userInfo.login)/received_events")! let urlRequest = URLRequest(url: url) let task = URLSession.shared.dataTask(with: urlRequest) { [weak self] data, urlResponse, error in guard let content = data else { print("Error getting data from API.") return } do { let result = try JSONDecoder().decode([ResponseActivity].self, from: content) DispatchQueue.main.async { self?.activity = result } } catch { print("Error parsing URL from data Activity.") } } task.resume() } }在View中用
@StateObject持有这个ViewModel即可。

内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

