iOS Combine Framework - Publisher 只发布一次,然后不再发布
iOS Combine Framework - Publisher Only Publishes Once and Then Never Again
我正在尝试将 iOS 13 Combine 框架与一些 UIKit 控件结合使用。我想设置一个 viewcontroller,其中包含一个开关,只要切换开关 on/off,它就会 enables/disables 一个按钮。根据 Apple 的文档,UIKit 控件 built-in 支持 Combine 发布者等,因此这应该是可能的。
我有一个 viewcontroller,其中包含一个 UISwitch 和一个 UIButton,如下所示:
link to screenshot of my viewcontroller
这是我的代码:
import Combine
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var mySwitch: UISwitch!
@IBOutlet weak var myButton: UIButton!
var myCancellable: AnyCancellable?
override func viewDidLoad() {
super.viewDidLoad()
mySwitch.isOn = true // Set initial state of switch
myButton.setTitle("Enabled", for: .normal)
myButton.setTitle("Disabled", for: .disabled)
myCancellable = mySwitch.publisher(for: \.isOn)
.subscribe(on: RunLoop.main)
.assign(to: \.isEnabled, on: myButton)
}
}
只要 属性 发生变化,上面的代码应该(或者我认为)发出开关 .isOn
属性 的值,并将该值分配给按钮的 .isEnabled
属性。如果它是 运行 我期望的方式,这意味着当开关切换到 ON 时,按钮标题应该显示为 "Enabled" 并且按钮应该被启用。当 UISwitch 切换为 OFF 时,按钮标题应显示为 "Disabled" 并且按钮应被禁用。
但它的行为并不像我期望的那样。当首次在 viewDidLoad()
中设置发布者时,开关发布者的值仅发出一次。当点击开关以打开或关闭它时,它永远不会再发出一个值。我可以说它至少发出一次值,因为如果我将开关的初始状态更改为打开或关闭,则在加载 viewcontroller 时按钮将设置为预期状态。
通常你应该保留对发布者的强引用,否则 publisher/subscriber 将立即终止,所以这就是为什么我持有 myCancellable
变量的引用。但这并不能解决问题,点击开关时仍然不会发出值。
有没有人知道如何解决这个问题?这似乎应该是一个使用 Combine 的简单 "Hello World" 类型的示例,我不知道我在这里遗漏了什么。
一个常见的错误是认为 UISwitch
的 isOn
属性 是 KVO 兼容的。 Sadly, it isn't.你不能用publisher(for:)
观察它。
在您的 ViewController
中创建一个 @IBAction
,并将开关的 Value Changed 事件连接到它。
我正在尝试将 iOS 13 Combine 框架与一些 UIKit 控件结合使用。我想设置一个 viewcontroller,其中包含一个开关,只要切换开关 on/off,它就会 enables/disables 一个按钮。根据 Apple 的文档,UIKit 控件 built-in 支持 Combine 发布者等,因此这应该是可能的。
我有一个 viewcontroller,其中包含一个 UISwitch 和一个 UIButton,如下所示:
link to screenshot of my viewcontroller
这是我的代码:
import Combine
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var mySwitch: UISwitch!
@IBOutlet weak var myButton: UIButton!
var myCancellable: AnyCancellable?
override func viewDidLoad() {
super.viewDidLoad()
mySwitch.isOn = true // Set initial state of switch
myButton.setTitle("Enabled", for: .normal)
myButton.setTitle("Disabled", for: .disabled)
myCancellable = mySwitch.publisher(for: \.isOn)
.subscribe(on: RunLoop.main)
.assign(to: \.isEnabled, on: myButton)
}
}
只要 属性 发生变化,上面的代码应该(或者我认为)发出开关 .isOn
属性 的值,并将该值分配给按钮的 .isEnabled
属性。如果它是 运行 我期望的方式,这意味着当开关切换到 ON 时,按钮标题应该显示为 "Enabled" 并且按钮应该被启用。当 UISwitch 切换为 OFF 时,按钮标题应显示为 "Disabled" 并且按钮应被禁用。
但它的行为并不像我期望的那样。当首次在 viewDidLoad()
中设置发布者时,开关发布者的值仅发出一次。当点击开关以打开或关闭它时,它永远不会再发出一个值。我可以说它至少发出一次值,因为如果我将开关的初始状态更改为打开或关闭,则在加载 viewcontroller 时按钮将设置为预期状态。
通常你应该保留对发布者的强引用,否则 publisher/subscriber 将立即终止,所以这就是为什么我持有 myCancellable
变量的引用。但这并不能解决问题,点击开关时仍然不会发出值。
有没有人知道如何解决这个问题?这似乎应该是一个使用 Combine 的简单 "Hello World" 类型的示例,我不知道我在这里遗漏了什么。
一个常见的错误是认为 UISwitch
的 isOn
属性 是 KVO 兼容的。 Sadly, it isn't.你不能用publisher(for:)
观察它。
在您的 ViewController
中创建一个 @IBAction
,并将开关的 Value Changed 事件连接到它。