"Extra argument" 使用 Combine 框架中的 CombineLatest 时出错
"Extra argument" error when using CombineLatest from the Combine framework
这个问题可以在下面的 playground 中看到。有四个已发布的值将被异步更新(一个图像和三个字符串)。当所有四个都已初始化或随后更改时, UI 将需要更新。当我尝试使用 CombineLatest4 捕获此数据流时,编译器立即反对第四个参数并显示消息 Extra argument in call
。 (注意:以下代码实际上没有做任何事情,因为它只有一个发布者,但足以在 Playground 中产生错误消息。
import Combine
import UIKit
struct CustomerUpdates
{
@Published var photo: UIImage!
@Published var firstName: String!
@Published var lastName: String!
@Published var id: String!
typealias customerTuple =
( photo: UIImage,
firstName: String,
lastName: String,
id: String )
var validatedCustomer: AnyPublisher< customerTuple, Never >
{
return Publishers.CombineLatest4( $photo,
$firstName,
$lastName,
$id )
{
photo, firstName, lastName, id in
if photo == nil
|| firstName == nil
|| lastName == nil
|| id == nil
{
return nil
}
return ( photo!, firstName!, lastName!, id! )
}
.compactMap
.return( on: RunLoop.main )
}
}
我的问题是,为什么编译器标记第四个参数("id")? Apple 的 CombineLatest4 通用结构文档说:
A publisher that receives and combines the latest elements from four
publishers.
问题是 CombineLatest
没有关闭,它只是在任何上游发出新值时发出从其所有上游发出的最新值。您的闭包应该提供给 compactMap
,这是一个运算符,它采用闭包 returning 一个 Optional
并且仅在 return 值不是 nil
.
struct CustomerUpdates {
@Published var photo: UIImage!
@Published var firstName: String!
@Published var lastName: String!
@Published var id: String!
typealias CustomerTuple = (photo: UIImage, firstName: String, lastName: String, id: String)
var validatedCustomer: AnyPublisher<CustomerTuple, Never> {
return Publishers.CombineLatest4($photo, $firstName, $lastName, $id)
.compactMap { photo, firstName, lastName, id in
guard let photo = photo, let firstName = firstName, let lastName = lastName, let id = id else { return nil }
return ( photo, firstName, lastName, id)
}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}
其他几个与您的问题无关的问题:没有这样的运算符 return(on:)
,您需要 receive(on:)
并且您想将 DispatchQueue.main
而不是 RunLoop.main
传递给能够直接将更新发布到您的 UI.
类型名称在 Swift 中应为 UpperCamelCase,因此请使用 CustomerTuple
而不是 customerTuple
。
此外,您的属性应该是 Optional
(var photo: UIImage?
),而不是隐式解包可选 (var photo: UIImage!
).
CombineLatest
类型(及其更大的变体,包括 CombineLatest4
)不采用转换闭包。但是 Publisher
有 combineLatest
operators 可以。所以如果你愿意,你可以这样说:
return $photo.combineLatest($firstName, $lastName, $id) {
guard
let photo = [=10=],
let firstName = ,
let lastName = ,
let id =
else { return nil }
return ([=10=], , , )
}
.compactMap { [=10=] }
.receive(on: RunLoop.main)
这个问题可以在下面的 playground 中看到。有四个已发布的值将被异步更新(一个图像和三个字符串)。当所有四个都已初始化或随后更改时, UI 将需要更新。当我尝试使用 CombineLatest4 捕获此数据流时,编译器立即反对第四个参数并显示消息 Extra argument in call
。 (注意:以下代码实际上没有做任何事情,因为它只有一个发布者,但足以在 Playground 中产生错误消息。
import Combine
import UIKit
struct CustomerUpdates
{
@Published var photo: UIImage!
@Published var firstName: String!
@Published var lastName: String!
@Published var id: String!
typealias customerTuple =
( photo: UIImage,
firstName: String,
lastName: String,
id: String )
var validatedCustomer: AnyPublisher< customerTuple, Never >
{
return Publishers.CombineLatest4( $photo,
$firstName,
$lastName,
$id )
{
photo, firstName, lastName, id in
if photo == nil
|| firstName == nil
|| lastName == nil
|| id == nil
{
return nil
}
return ( photo!, firstName!, lastName!, id! )
}
.compactMap
.return( on: RunLoop.main )
}
}
我的问题是,为什么编译器标记第四个参数("id")? Apple 的 CombineLatest4 通用结构文档说:
A publisher that receives and combines the latest elements from four publishers.
问题是 CombineLatest
没有关闭,它只是在任何上游发出新值时发出从其所有上游发出的最新值。您的闭包应该提供给 compactMap
,这是一个运算符,它采用闭包 returning 一个 Optional
并且仅在 return 值不是 nil
.
struct CustomerUpdates {
@Published var photo: UIImage!
@Published var firstName: String!
@Published var lastName: String!
@Published var id: String!
typealias CustomerTuple = (photo: UIImage, firstName: String, lastName: String, id: String)
var validatedCustomer: AnyPublisher<CustomerTuple, Never> {
return Publishers.CombineLatest4($photo, $firstName, $lastName, $id)
.compactMap { photo, firstName, lastName, id in
guard let photo = photo, let firstName = firstName, let lastName = lastName, let id = id else { return nil }
return ( photo, firstName, lastName, id)
}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}
其他几个与您的问题无关的问题:没有这样的运算符 return(on:)
,您需要 receive(on:)
并且您想将 DispatchQueue.main
而不是 RunLoop.main
传递给能够直接将更新发布到您的 UI.
类型名称在 Swift 中应为 UpperCamelCase,因此请使用 CustomerTuple
而不是 customerTuple
。
此外,您的属性应该是 Optional
(var photo: UIImage?
),而不是隐式解包可选 (var photo: UIImage!
).
CombineLatest
类型(及其更大的变体,包括 CombineLatest4
)不采用转换闭包。但是 Publisher
有 combineLatest
operators 可以。所以如果你愿意,你可以这样说:
return $photo.combineLatest($firstName, $lastName, $id) {
guard
let photo = [=10=],
let firstName = ,
let lastName = ,
let id =
else { return nil }
return ([=10=], , , )
}
.compactMap { [=10=] }
.receive(on: RunLoop.main)