在Swift中变量值发生变化时执行方法

Ili*_*uda 34 singleton properties ios swift

我需要在变量值改变时执行一个函数.

我有一个包含一个名为的共享变量的单例类labelChange.此变量的值取自另一个名为的类Model.我有两个VC类,其中一个有按钮和标签,第二个只有一个按钮.

当按下第一个VC类中的按钮时,我正在用这个func更新标签:

func updateLabel(){
    self.label.text = SharingManager.sharedInstance.labelChange
}
Run Code Online (Sandbox Code Playgroud)

但是每当labelChange更改值时我想调用相同的方法.因此,在按钮单击中,我将只更新labelChange值,当这件事发生时,我想用新的值更新标签labelChange.同样在第二个VC中,我可以更新labelChange值,但是当更改此值时,我无法更新标签.

也许属性是解决方案,但任何人都可以告诉我如何这样做.

第二次编辑:

单身人士课程:

class SharingManager {
    func updateLabel() {
        println(labelChange)
        ViewController().label.text = SharingManager.sharedInstance.labelChange     
    }
    var labelChange: String = Model().callElements() {
        willSet {
            updateLabel()
        }
    }
    static let sharedInstance = SharingManager()
}
Run Code Online (Sandbox Code Playgroud)

第一个VC:

class ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!
    @IBAction func Button(sender: UIButton) {    
       SViewController().updateMessageAndDismiss()
    }
}
Run Code Online (Sandbox Code Playgroud)

第二个VC:

func updateMessageAndDismiss() {
        SharingManager.sharedInstance.labelChange = modelFromS.callElements()
        self.dismissViewControllerAnimated(true, completion: nil)
    }
@IBAction func b2(sender: UIButton) { 
        updateMessageAndDismiss()
}
Run Code Online (Sandbox Code Playgroud)

我做了一些改进,但我需要引用单例中第一个VC类的标签.因此,我将以单身形式更新VC的标签.

当我打印时,值labelChange的值正在更新,一切都很好.但是当我尝试从singleton更新标签上的值时,我收到一个错误:

在展开Optional值时意外地发现了nil

并且错误指向单行类的第4行.

Den*_*nis 36

您可以简单地使用属性观察器来获取变量,labelChange并调用要在其中调用的函数didSet(或者willSet如果要在设置之前调用它):

class SharingManager {
    var labelChange: String = Model().callElements() {
        didSet {
            updateLabel()
        }
    }
    static let sharedInstance = SharingManager()
}
Run Code Online (Sandbox Code Playgroud)

财产观察员对此进行了解释.

我不确定为什么当你尝试它时它不起作用,但如果你遇到麻烦,因为你试图调用的函数(updateLabel)在另一个类中,你可以在SharingManager类中添加一个变量来存储函数调用何时didSet调用,updateLabel在这种情况下你将设置.


编辑:

因此,如果您想要从ViewController编辑标签,您可能希望在ViewController类中使用该updateLabel()函数来更新标签,但是将该函数存储在单例类中,以便它可以知道要调用的函数:

class SharingManager {
    static let sharedInstance = SharingManager()
    var updateLabel: (() -> Void)?
    var labelChange: String = Model().callElements() {
        didSet {
            updateLabel?()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将它设置在您想要调用的函数的任何类中,例如(假设updateLabel是您要调用的函数):

SharingManager.sharedInstance.updateLabel = updateLabel
Run Code Online (Sandbox Code Playgroud)

当然,您需要确保负责该函数的视图控制器仍然存在,因此单例类可以调​​用该函数.

如果需要根据哪个视图控制器可见来调用不同的函数,您可能需要考虑键值观察,以便在某些变量的值发生更改时获取通知.

此外,您永远不想初始化这样的视图控制器,然后立即设置视图控制器的IBOutlets,因为IBOutlets在其视图实际加载之前不会被初始化.您需要以某种方式使用现有的视图控制器对象.

希望这可以帮助.


And*_*ndy 9

在Swift 4中,您可以使用键值观察.

label.observe(\.text, changeHandler: { (label, change) in {
    // text has changed
}
Run Code Online (Sandbox Code Playgroud)

这基本上是它,但有一点点."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,
}
Run Code Online (Sandbox Code Playgroud)

您还可以观察该值是否已更改或是否已第一次设置

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")
    }

}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅此处的 Apples文档


Val*_*der 6

通过使用RxSwift还有另一种方法:

  1. 将RxSwift和RxCocoa pod添加到项目中

  2. 修改你的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)
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在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
    
    Run Code Online (Sandbox Code Playgroud)

    湾 将更新直接绑定到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
    
    Run Code Online (Sandbox Code Playgroud)

并且不要忘记import RxCocoa在ViewController中.

对于触发事件只需调用

SharingManager.sharedInstance.triggerLabelUpdate("whatever string here")
Run Code Online (Sandbox Code Playgroud)

在这里你可以找到示例项目.只需执行pod update并运行工作区文件.


Abh*_*ore 5

苹果提供这些属性声明类型:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

2.只读计算属性:

具有getter但没有setter的计算属性称为只读计算属性。只读的计算属性始终返回一个值,并且可以通过点语法进行访问,但不能将其设置为其他值。

var volume: Double {
    return volume
}
Run Code Online (Sandbox Code Playgroud)

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")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:- 有关更多信息,请访问专业链接 https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html