gpt4 book ai didi

ios - Swift Combine compactMap 不起作用(Xcode 13)

转载 作者:行者123 更新时间:2023-12-04 12:27:37 25 4
gpt4 key购买 nike

使用Combine 的assign(to:) 得到了意想不到的结果直接在 compactMap 之后.这是代码,它在 Xcodes Playground, Xcode Version 13.0 (13A233) 中对我来说是 100% 可重现的。

import Combine
import Foundation

class Test {
@Published var current: String?
@Published var latest1: String?
@Published var latest2: String?
@Published var latest3: String?

init() {
// Broken? - compactMap passes nil downstream
self.$current
.compactMap { $0 }
.assign(to: &self.$latest1)

// Fixed by specifying the transform closure type explicitely
self.$current
.compactMap { value -> String? in value }
.assign(to: &self.$latest2)

// Fixed by an additional map inbetween
self.$current
.compactMap { $0 }
.map { $0 }
.assign(to: &self.$latest3)
}
}

let obj = Test()

obj.current = "success"

print("current: \(String(describing: obj.current))")
print("latest1: \(String(describing: obj.latest1))")
print("latest2: \(String(describing: obj.latest2))")
print("latest3: \(String(describing: obj.latest3))")
print("")

obj.current = nil

print("current: \(String(describing: obj.current))")
print("latest1: \(String(describing: obj.latest1))") // nil shouldn't arrive here
print("latest2: \(String(describing: obj.latest2))")
print("latest3: \(String(describing: obj.latest3))")

// Output:
//current: Optional("success")
//latest1: Optional("success")
//latest2: Optional("success")
//latest3: Optional("success")
//
//current: nil
//latest1: nil
//latest2: Optional("success")
//latest3: Optional("success")
也许我在这里错过了一些明显的东西?或者这可能是Combine中的一个错误?。感谢您的关注。

更新:我用更简洁的版本更新了示例代码

最佳答案

这里的问题是 Swift 的类型推断机制,Combine 中没有错误。让我解释一下原因。compactMap(transform:)映射一个 Value?T ,但是在您的情况下 T ( self.latest 的类型)实际上是 String? ,又名字符串可选。所以整个管道被重新路由到 String?输出,与您在屏幕上看到的相匹配。
当你不指定涉及的类型时,Swift 急于满足你的代码需求,所以当它看到 assign(to: &self.$latest) 时,即使 latestString? ,它会自动重新路由 compactMap来自 (String?) -> String(String?) -> String? .而且几乎不可能得到 nil这种转换的值(value):)
基本上,“有问题”的管道推断出以下类型:

self.$current
.compactMap { (val: String?) -> String? in return val }
.assign(to: &self.$latest)
,这是因为它在 Swift 中完全有效到 compactMap从一个可选到另一个可选。
试试写 @Published var latest: String = "" ,您将获得预期的行为。请注意,我说的是“预期”,而不是“正确”,因为“正确”取决于您的代码的外观。
另外,尝试将 compactMap 一分为二管道:
let pub = self.$current.compactMap { $0 }
pub.assign(to: &self.$latest) // error: Inout argument could be set to a value with a type other than 'Published<String?>.Publisher'; use a value declared as type 'Published<String>.Publisher' instead
基本上,通过分配一个可选属性,您可以决定整个管道的行为,如果一切顺利,并且没有类型不匹配,您最终可能会出现意外行为(不是错误行为,只是意外行为)。

关于ios - Swift Combine compactMap 不起作用(Xcode 13),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69403867/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com