Xcode14中Combine调用.store(in: &subscrptions)出现表达式类型歧义错误
.store(in: &subscriptions)出现类型歧义错误的排查(仅Xcode14出现) 在使用Combine框架时,调用.store(in: &subscriptions)弹出错误提示:“Type of expression is ambiguous without more context”,相关代码如下:
// MARK: - Combine /// First Image let firstImage = UnsplashAPI.randomeImage() .flatMap { RandomImageResponse in ImageDownloader.download(url: RandomImageResponse.urls.regular) } /// Second Image let secondImage = UnsplashAPI.randomeImage() .flatMap { RandomImageResponse in ImageDownloader.download(url: RandomImageResponse.urls.regular) } firstImage.zip(secondImage) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { [unowned self ] completion in switch completion { case .finished: break case .failure(): self.gameState = .stop } }, receiveValue: { [unowned self] first, second in self.gameImages = [first, second, second, second].shuffled() self.gameScoreLabel.text = "Score: \(self.gameScore)" // TODO: Handling game score self.stopLoaders() self.setImages() }) .store(in: &subscriptions)
已定义变量:var subscriptions: Set<AnyCancellable> = [],且该错误仅在Xcode14中出现,可能的原因及解决办法如下:
可能的原因
错误分支未捕获错误参数,导致类型推断失败
Xcode14对应的Swift 5.7对Combine闭包的类型推断逻辑更严格。代码中sink的failure分支写的是case .failure():,没有接收错误参数,编译器无法明确上游Publisher的错误类型,进而无法确定整个链返回的AnyCancellable类型,最终在调用store时触发类型歧义错误。Swift 5.7对Combine类型推断的校验升级
旧版本Xcode的Swift编译器会宽松地推断Combine Publisher的类型,但Xcode14的Swift 5.7要求更明确的类型信息。如果上游Publisher的输出/错误类型没有明确标注,且闭包中没有足够的类型提示,编译器就无法完成类型推导。上游Publisher错误类型不统一
如果UnsplashAPI.randomeImage()和ImageDownloader.download()抛出的错误类型不一致,且没有通过mapError做统一转换,Xcode14的编译器无法自动推断出兼容的错误类型,也会导致整个链的类型模糊。
解决办法
补全错误分支的参数
把case .failure():改为case .failure(_):(即使不需要使用错误变量,也要保留占位符),或者显式捕获错误:case .failure(let error): print("Error: \(error)") self.gameState = .stop显式标注Publisher类型
给firstImage和secondImage加上明确的类型标注,帮助编译器推导:// 替换成你实际的图片类型和错误类型 let firstImage: AnyPublisher<UIImage, APIError> = UnsplashAPI.randomeImage() .flatMap { randomImageResponse in ImageDownloader.download(url: randomImageResponse.urls.regular) }统一上游错误类型
如果两个Publisher的错误类型不同,用mapError转换为统一类型:let firstImage = UnsplashAPI.randomeImage() .mapError { $0 as APIError } .flatMap { randomImageResponse in ImageDownloader.download(url: randomImageResponse.urls.regular) .mapError { $0 as APIError } }
内容的提问来源于stack exchange,提问作者Zabeeh Qayumi

