我需要在变量值改变时执行一个函数。
我有一个包含名为labelChange
的共享变量的单例类。此变量的值取自另一个名为Model
的类。我有两个VC类,其中一个有按钮和一个标签,第二个只有一个按钮。
当按下第一个VC类中的按钮时,我正在用这个函数更新标签:
func updateLabel(){
self.label.text = SharingManager.sharedInstance.labelChange
}
但是每当labelChange
的值发生变化时,我想调用相同的方法。因此,在按钮单击中,我将仅更新labelChange
值,当这件事发生时,我想用labelChange
的新值更新标签。同样在第二个VC中,我可以更新labelChange
值,但是当更改此值时,我无法更新标签。
也许属性是解决方案,但任何人都可以告诉我如何这样做。
第二次编辑:
Singleton类:
class SharingManager {
func updateLabel() {
println(labelChange)
ViewController().label.text = SharingManager.sharedInstance.labelChange
}
var labelChange: String = Model().callElements() {
willSet {
updateLabel()
}
}
static let sharedInstance = SharingManager()
}
第一个VC:
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBAction func Button(sender: UIButton) {
SViewController().updateMessageAndDismiss()
}
}
第二个VC:
func updateMessageAndDismiss() {
SharingManager.sharedInstance.labelChange = modelFromS.callElements()
self.dismissViewControllerAnimated(true, completion: nil)
}
@IBAction func b2(sender: UIButton) {
updateMessageAndDismiss()
}
我做了一些改进但是我需要引用单例中第一个VC类的标签。因此,我将以单身形式更新VC的标签。
当我打印labelChange
的值时,值正在更新,一切都很好。但是当我尝试从singleton更新标签上的值时,我收到一个错误:
在解包可选值时意外发现nil
并且错误指向单身类的第4行。
答案 0 :(得分:32)
您可以简单地使用属性观察器作为变量labelChange
,并调用要在didSet
内调用的函数(或willSet
如果要在它之前调用它已设定):
class SharingManager {
var labelChange: String = Model().callElements() {
didSet {
updateLabel()
}
}
static let sharedInstance = SharingManager()
}
Property Observers中解释了这一点。
我不确定为什么当你尝试它时这不起作用,但是如果你遇到麻烦,因为你试图调用的函数(updateLabel
)在另一个类中,你可以添加一个SharingManager
类中的变量,用于存储调用didSet
时要调用的函数,在这种情况下,您将设置为updateLabel
。
的编辑:强>
因此,如果您想从ViewController编辑标签,您可能希望在ViewController类中使用updateLabel()函数来更新标签,但是将该函数存储在单例类中,以便它可以知道要调用哪个函数:
class SharingManager {
static let sharedInstance = SharingManager()
var updateLabel: (() -> Void)?
var labelChange: String = Model().callElements() {
didSet {
updateLabel?()
}
}
}
然后将它设置在您想要调用的函数的任何类中,例如(假设updateLabel是您要调用的函数):
SharingManager.sharedInstance.updateLabel = updateLabel
当然,您需要确保负责该函数的视图控制器仍然存在,因此单例类可以调用该函数。
如果您需要根据可见的视图控制器调用不同的函数,您可能需要考虑Key-Value Observing以便在某些变量的值发生更改时收到通知。
此外,您永远不想初始化这样的视图控制器,然后立即设置视图控制器的IBOutlets,因为IBOutlets在其视图实际加载之前不会被初始化。您需要以某种方式使用现有的视图控制器对象。
希望这有帮助。
答案 1 :(得分:7)
通过使用RxSwift还有另一种方法:
将RxSwift和RxCocoa pod添加到您的项目中
修改您的SharingManager
:
import RxSwift
class SharingManager {
static let sharedInstance = SharingManager()
private let _labelUpdate = PublishSubject<String>()
let onUpdateLabel: Observable<String>? // any object can subscribe to text change using this observable
// call this method whenever you need to change text
func triggerLabelUpdate(newValue: String) {
_labelUpdate.onNext(newValue)
}
init() {
onUpdateLabel = _labelUpdate.shareReplay(1)
}
}
在ViewController中,您可以通过两种方式订阅值更新:
一个。订阅更新,并手动更改标签文本
// add this ivar somewhere in ViewController
let disposeBag = DisposeBag()
// put this somewhere in viewDidLoad
SharingManager.sharedInstance.onUpdateLabel?
.observeOn(MainScheduler.instance) // make sure we're on main thread
.subscribeNext { [weak self] newValue in
// do whatever you need with this string here, like:
// self?.myLabel.text = newValue
}
.addDisposableTo(disposeBag) // for resource management
湾将更新直接绑定到UILabel
// add this ivar somewhere in ViewController
let disposeBag = DisposeBag()
// put this somewhere in viewDidLoad
SharingManager.sharedInstance.onUpdateLabel?
.distinctUntilChanged() // only if value has been changed since previous value
.observeOn(MainScheduler.instance) // do in main thread
.bindTo(myLabel.rx_text) // will setText: for that label when value changed
.addDisposableTo(disposeBag) // for resource management
并且不要忘记ViewController中的import RxCocoa
。
如需触发事件,请致电
SharingManager.sharedInstance.triggerLabelUpdate("whatever string here")
HERE你可以找到示例项目。只需执行pod update
并运行工作区文件。
答案 2 :(得分:7)
label.observe(\.text, changeHandler: { (label, change) in {
// text has changed
}
基本上就是这样,但是有一点收获。 “观察”返回您需要保存的NSKeyValueObservation对象! -释放后,您将不会再收到任何通知。为避免这种情况,我们可以将其分配给将保留的属性。
var observer:NSKeyValueObservation?
// then assign the return value of "observe" to it
observer = label.observe(\.text, changeHandler: { (label, change) in {
// text has changed,
}
您还可以观察该值是否已更改或首次设置
observer = label.observe(\.text, changeHandler: { (label, change) in {
// just check for the old value in "change" is not Nil
if let oldValue = change.oldValue {
print("\(label.text) has changed from \(oldValue) to \(label.text)")
} else {
print("\(label.text) is now set")
}
}
有关更多信息,请查阅Apple文档here
答案 3 :(得分:4)
Apple提供以下属性声明类型: -
<强> 1。计算属性: -
除了存储的属性,类,结构和枚举还可以定义计算属性,这些属性实际上不存储值。相反,它们提供了一个getter和一个可选的setter来间接检索和设置其他属性和值。
var otherBool:Bool = false
public var enable:Bool {
get{
print("i can do editional work when setter set value ")
return self.enable
}
set(newValue){
print("i can do editional work when setter set value ")
self.otherBool = newValue
}
}
<强> 2。只读计算属性: -
具有getter但没有setter的计算属性称为只读计算属性。只读计算属性始终返回一个值,可以通过点语法访问,但不能设置为其他值。
var volume: Double {
return volume
}
第3。财产观察员: -
您可以选择在属性上定义其中一个或两个观察者:
在存储值之前调用willSet 存储新值后立即调用 didSet 。
public var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
注意: - 有关详细信息,请访问专业链接 https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
答案 4 :(得分:1)
var item = "initial value" {
didSet { //called when item changes
print("changed")
}
willSet {
print("about to change")
}
}
item = "p"
答案 5 :(得分:0)
override var isHighlighted: Bool {
get { super.isHighlighted }
set {
super.isHighlighted = newValue
if newValue {
label.textColor = highlightedTextColor
contentView.backgroundColor = highlightedBackgroundColor
} else {
label.textColor = normalTextColor
contentView.backgroundColor = normalBackgroundColor
}
}
}