Swift Combine数组映射报错:闭包传入不接受闭包的KeyPath参数
Combine中数组映射的编译错误解决
问题代码
Provider类代码
func getUserPosts(userID: String) -> AnyPublisher<[PostDTO], NetworkErrors> { let url = URL(string: "https://jsonplaceholder.typicode.com/posts?userId=\(userID)") return AF.request(url!,method: .get) .publishDecodable(type: [PostDTO].self) .value() .mapError { _ in NetworkErrors.decoderError } .eraseToAnyPublisher() }
Interactor类映射代码(存在错误)
func getUserPosts(userID: String) -> AnyPublisher<[Post], NetworkErrors> { postListRemoteProvider.getUserPosts(userID: userID).map { Post(id: $0.id, title: $0.title, detail: $0.body, isFavorite: false) }.eraseToAnyPublisher() }
错误信息
Trailing closure passed to parameter of type 'KeyPath<[PostDTO], [Post]>' that does not accept a closure
错误原因
上游Publisher输出的是[PostDTO]数组类型,当前代码直接在Combine的map闭包里尝试用整个数组($0)初始化单个Post,属于类型不匹配。同时Swift为集合类型的map提供了KeyPath重载,编译器误以为你要传入KeyPath而非闭包,因此抛出该错误。
解决方案
需要在Combine的map操作中,对上游输出的数组执行Swift数组的map遍历,将每个PostDTO转换为Post实例:
修正后的代码
func getUserPosts(userID: String) -> AnyPublisher<[Post], NetworkErrors> { postListRemoteProvider.getUserPosts(userID: userID) .map { postDTOs in postDTOs.map { dto in Post(id: dto.id, title: dto.title, detail: dto.body, isFavorite: false) } } .eraseToAnyPublisher() }
简化写法
func getUserPosts(userID: String) -> AnyPublisher<[Post], NetworkErrors> { postListRemoteProvider.getUserPosts(userID: userID) .map { $0.map { Post(id: $0.id, title: $0.title, detail: $0.body, isFavorite: false) } } .eraseToAnyPublisher() }
外层的map是Combine Publisher的操作,负责接收上游的[PostDTO]数组;内层的map是Swift数组的遍历方法,负责将数组中的每个PostDTO转换为Post,最终得到[Post]数组作为新的Publisher输出。
内容的提问来源于stack exchange,提问作者mars_dev
相关产品推荐
相关产品推荐

