Swift中返回Result<T>枚举的函数出现‘Type 'Void' has no member’错误排查
解决Swift中
Type 'Void' has no member错误(返回Result枚举的异步函数场景) 我来帮你排查这个问题!首先,你遇到的这个错误,本质是异步网络请求的闭包返回类型和函数声明的返回类型不匹配导致的,结合你的代码场景,我来一步步拆解原因和解决方案:
错误根源分析
你的getJsonFromServer函数声明要返回Result<String>,但网络请求(比如URLSession.dataTask)是异步操作——这类操作的回调闭包返回类型是Void(也就是没有返回值)。如果你在闭包里直接写return .success(xxx)或者return .error(xxx),编译器会误以为你想访问Void类型的成员(比如.success),自然就会抛出Type 'Void' has no member 'success'这类错误。
另外,顺便提一句:你的Result枚举里的succes拼写错了,应该是success,虽然这不是当前错误的直接原因,但后续调用时会引发其他问题,建议先修正这个拼写。
解决方案
根据你的项目iOS版本,推荐两种常用的解决方式:
方案1:使用闭包回调(兼容旧版本iOS)
修改函数,去掉同步返回的Result<String>,改用一个completion闭包来传递异步结果:
enum ApiConstans { static let baseUrl = "http://myname.pl" // 建议常量名用小驼峰,符合Swift命名规范 static let iosPath = "/pub/ios/" static let jsonPath = "json.php" static var fullPath: String { return baseUrl + iosPath + jsonPath } } struct Connect { enum Result<T> { case success(T) // 修正拼写错误 case error(String) } // 修改函数:添加completion闭包,返回Void func getJsonFromServer(parameters: String, completion: @escaping (Result<String>) -> Void) { let fullUrlString = ApiConstans.fullPath + parameters guard let url = URL(string: fullUrlString) else { completion(.error("Error 100: Problem with URL construction")) return } // 示例异步网络请求逻辑 let task = URLSession.shared.dataTask(with: url) { data, response, error in // 处理错误 if let error = error { completion(.error("Error 200: \(error.localizedDescription)")) return } // 解析数据 guard let data = data, let jsonString = String(data: data, encoding: .utf8) else { completion(.error("Error 300: Failed to parse response data")) return } // 返回成功结果 completion(.success(jsonString)) } task.resume() } } // 调用方式 let connect = Connect() connect.getJsonFromServer(parameters: "?id=123") { result in switch result { case .success(let json): print("Got JSON: \(json)") case .error(let msg): print("Error: \(msg)") } }
方案2:使用async/await(iOS 15+/macOS 12+及以上推荐)
如果你的项目支持Swift 5.5+(对应iOS 15及以上版本),用异步函数会更简洁,不需要闭包:
enum ApiConstans { static let baseUrl = "http://myname.pl" static let iosPath = "/pub/ios/" static let jsonPath = "json.php" static var fullPath: String { return baseUrl + iosPath + jsonPath } } struct Connect { enum Result<T> { case success(T) // 修正拼写错误 case error(String) } // 标记为async函数,直接返回Result<String> func getJsonFromServer(parameters: String) async -> Result<String> { let fullUrlString = ApiConstans.fullPath + parameters guard let url = URL(string: fullUrlString) else { return .error("Error 100: Problem with URL construction") } do { // 使用await等待异步请求结果 let (data, response) = try await URLSession.shared.data(from: url) // 验证HTTP响应状态 guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { return .error("Error 200: Invalid HTTP response status") } // 解析数据为字符串 guard let jsonString = String(data: data, encoding: .utf8) else { return .error("Error 300: Failed to parse response data") } return .success(jsonString) } catch { return .error("Error 400: \(error.localizedDescription)") } } } // 调用方式(必须在async上下文中执行,比如Task里) Task { let connect = Connect() let result = await connect.getJsonFromServer(parameters: "?id=123") switch result { case .success(let json): print("Got JSON: \(json)") case .error(let msg): print("Error: \(msg)") } }
额外提示
- 遵循Swift命名规范:常量名推荐用小驼峰(比如
baseUrl而不是BaseUrl),提升代码可读性。 - 网络请求记得处理HTTP响应状态码,不要只判断数据是否存在,避免接收错误的响应。
内容的提问来源于stack exchange,提问作者Łukasz Betta
相关产品推荐
相关产品推荐

