ios 当变量值在 Swift 中发生变化时执行一个方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30625122/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Execute a method when a variable value changes in Swift
提问by Ilir V. Gruda
I need to execute a function when a variable value changes.
当变量值发生变化时,我需要执行一个函数。
I have a singleton class containing a shared variable called labelChange
. Values of this variable are taken from another class called Model
. I have two VC classes, one of them has a button and a label and the second only a button.
我有一个单例类,其中包含一个名为labelChange
. 此变量的值取自另一个名为Model
. 我有两个 VC 类,其中一个有一个按钮和一个标签,第二个只有一个按钮。
When the button in the first VC class is pressed I am updating the label with this func:
当按下第一个 VC 类中的按钮时,我正在使用此功能更新标签:
func updateLabel(){
self.label.text = SharingManager.sharedInstance.labelChange
}
But I want to call the same method whenever the value of the labelChange
is changed. So in button click I will only update the labelChange
value and when this thing happen I want to update the label with the new value of the labelChange
. Also in the second VC I am able to update the labelChange
value but I am not able to update the label when this value is changed.
但是每当 的值labelChange
发生变化时,我都想调用相同的方法。因此,在单击按钮时,我只会更新labelChange
值,当发生这种情况时,我想用labelChange
. 同样在第二个 VC 中,我能够更新该labelChange
值,但在更改该值时我无法更新标签。
Maybe properties are the solution but can anyone show me how to do so.
也许属性是解决方案,但谁能告诉我如何做到这一点。
Edited second time:
第二次修改:
Singleton Class:
单例类:
class SharingManager {
func updateLabel() {
println(labelChange)
ViewController().label.text = SharingManager.sharedInstance.labelChange
}
var labelChange: String = Model().callElements() {
willSet {
updateLabel()
}
}
static let sharedInstance = SharingManager()
}
First VC:
第一个VC:
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBAction func Button(sender: UIButton) {
SViewController().updateMessageAndDismiss()
}
}
Second VC:
第二个VC:
func updateMessageAndDismiss() {
SharingManager.sharedInstance.labelChange = modelFromS.callElements()
self.dismissViewControllerAnimated(true, completion: nil)
}
@IBAction func b2(sender: UIButton) {
updateMessageAndDismiss()
}
I made some improvements but I need to reference a label from the first VC class in singleton. Therefore I will update that label of VC in singleton.
我做了一些改进,但我需要引用单例中第一个 VC 类的标签。因此,我将在单例中更新 VC 的标签。
When I print the value of labelChange
the value is being updated and everything is fine. But when I try to update that value on label from singleton I receive an error:
当我打印值labelChange
的值正在更新时,一切都很好。但是当我尝试从单例更新标签上的值时,我收到一个错误:
unexpectedly found nil while unwrapping an Optional value
在解开 Optional 值时意外发现 nil
and the error is pointing in 4th line of singleton class.
并且错误指向单例类的第 4 行。
回答by Dennis
You can simply use a property observer for the variable, labelChange
, and call the function that you want to call inside didSet
(or willSet
if you want to call it before it has been set):
您可以简单地对变量使用属性观察器labelChange
,并调用您想在内部调用的函数didSet
(或者willSet
如果您想在设置之前调用它):
class SharingManager {
var labelChange: String = Model().callElements() {
didSet {
updateLabel()
}
}
static let sharedInstance = SharingManager()
}
This is explained in Property Observers.
这在Property Observers 中有解释。
I'm not sure why this didn't work when you tried it, but if you are having trouble because the function you are trying to call (updateLabel
) is in a different class, you could add a variable in the SharingManager
class to store the function to call when didSet
has been called, which you would set to updateLabel
in this case.
我不确定为什么这在您尝试时不起作用,但是如果您因为尝试调用的函数 ( updateLabel
) 在不同的类中而遇到问题,您可以在SharingManager
类中添加一个变量来存储该函数在被调用时didSet
调用,updateLabel
在这种情况下您将设置为调用。
Edited:
编辑:
So if you want to edit a label from the ViewController, you would want to have that updateLabel() function in the ViewController class to update the label, but store that function in the singleton class so it can know which function to call:
因此,如果您想从 ViewController 编辑标签,您需要在 ViewController 类中使用 updateLabel() 函数来更新标签,但将该函数存储在单例类中,以便它知道要调用哪个函数:
class SharingManager {
static let sharedInstance = SharingManager()
var updateLabel: (() -> Void)?
var labelChange: String = Model().callElements() {
didSet {
updateLabel?()
}
}
}
and then set it in whichever class that you have the function that you want to be called, like (assuming updateLabel is the function that you want to call):
然后将它设置在您拥有要调用的函数的任何类中,例如(假设 updateLabel 是您要调用的函数):
SharingManager.sharedInstance.updateLabel = updateLabel
Of course, you will want to make sure that the view controller that is responsible for that function still exists, so the singleton class can call the function.
当然,您需要确保负责该函数的视图控制器仍然存在,以便单例类可以调用该函数。
If you need to call different functions depending on which view controller is visible, you might want to consider Key-Value Observingto get notifications whenever the value for certain variables change.
如果您需要根据可见的视图控制器调用不同的函数,您可能需要考虑键值观察以在某些变量的值发生变化时获得通知。
Also, you never want to initialize a view controller like that and then immediately set the IBOutlets of the view controller, since IBOutlets don't get initialized until the its view actually get loaded. You need to use an existing view controller object in some way.
此外,您永远不想像那样初始化视图控制器,然后立即设置视图控制器的 IBOutlets,因为 IBOutlets 在其视图实际加载之前不会被初始化。您需要以某种方式使用现有的视图控制器对象。
Hope this helps.
希望这可以帮助。
回答by Andy
In Swift 4 you can use Key-Value Observation.
在 Swift 4 中,您可以使用键值观察。
label.observe(\.text, changeHandler: { (label, change) in
// text has changed
})
This is basically it, but there is a little catch. "observe" returns an NSKeyValueObservation object that you need to hold! - when it is deallocated, you'll receive no more notifications. To avoid that we can assign it to a property which will be retained.
基本上就是这样,但有一点问题。“observe” 返回一个你需要持有的 NSKeyValueObservation 对象!- 解除分配后,您将不再收到通知。为了避免这种情况,我们可以将其分配给将保留的属性。
var observer:NSKeyValueObservation?
// then assign the return value of "observe" to it
observer = label.observe(\.text, changeHandler: { (label, change) in
// text has changed,
})
You can also observe if the the value has changed or has been set for the first time
您还可以观察该值是否已更改或已首次设置
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")
}
})
For More Information please consult Apples documentation here
有关更多信息,请在此处查阅 Apples 文档
回答by Valerii Lider
There is another way of doing so, by using RxSwift:
还有另一种方法,通过使用 RxSwift:
Add RxSwift and RxCocoa pods into your project
Modify your
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) } }
In your ViewController you can subscribe to value update in two ways:
a. subscribe to updates, and change label text manually
// 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
b. bind updates directly to 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
将 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
And don't forget to import RxCocoa
in ViewController.
并且不要忘记import RxCocoa
在 ViewController 中。
For triggering event just call
触发事件只需调用
SharingManager.sharedInstance.triggerLabelUpdate("whatever string here")
HEREyou can find example project. Just do pod update
and run workspace file.
在这里你可以找到示例项目。只需执行pod update
并运行工作区文件即可。
回答by Abhimanyu Rathore
Apple provide these property declaration type :-
Apple 提供这些属性声明类型:-
1. Computed Properties:-
1. 计算属性:-
In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.
除了存储的属性之外,类、结构和枚举还可以定义计算属性,这些属性实际上并不存储值。相反,它们提供了一个 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. Read-Only Computed Properties:-
2. 只读计算属性:-
A computed property with a getter but no setter is known as a read-only computed property. A read-only computed property always returns a value, and can be accessed through dot syntax, but cannot be set to a different value.
具有 getter 但没有 setter 的计算属性称为只读计算属性。只读计算属性总是返回一个值,可以通过点语法访问,但不能设置为不同的值。
var volume: Double {
return volume
}
3. Property Observers:-
3. 物业观察员:-
You have the option to define either or both of these observers on a property:
您可以选择在属性上定义这些观察者中的一个或两个:
willSetis called just before the value is stored.
didSetis called immediately after the new value is stored.
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")
}
}
}
NOTE:-For More Information go on professional linkhttps://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
注意:-有关更多信息,请访问专业链接https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
回答by msk_sureshkumar
var item = "initial value" {
didSet { //called when item changes
print("changed")
}
willSet {
print("about to change")
}
}
item = "p"