簡體   English   中英

當變量值在 Swift 中發生變化時執行一個方法

[英]Execute a method when a variable value changes in Swift

當變量值發生變化時,我需要執行一個函數。

我有一個單例類,其中包含一個名為labelChange的共享變量。 此變量的值取自另一個名為Model類。 我有兩個 VC 類,其中一個有一個按鈕和一個標簽,第二個只有一個按鈕。

當按下第一個 VC 類中的按鈕時,我正在使用此功能更新標簽:

func updateLabel(){
    self.label.text = SharingManager.sharedInstance.labelChange
}

但是每當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()
}

第一個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的值時,該值正在更新並且一切正常。 但是當我嘗試從單例更新標簽上的值時,我收到一個錯誤:

在解開 Optional 值時意外發現 nil

並且錯誤指向單例類的第 4 行。

您可以簡單地對變量labelChange使用屬性觀察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

當然,您需要確保負責該函數的視圖控制器仍然存在,以便單例類可以調​​用該函數。

如果您需要根據可見的視圖控制器調用不同的函數,您可能需要考慮鍵值觀察以在某些變量的值發生變化時獲得通知。

此外,您永遠不想像那樣初始化視圖控制器,然后立即設置視圖控制器的 IBOutlets,因為 IBOutlets 在其視圖實際加載之前不會被初始化。 您需要以某種方式使用現有的視圖控制器對象。

希望這可以幫助。

在 Swift 4 中,您可以使用鍵值觀察。

label.observe(\.text, changeHandler: { (label, change) in
    // text has changed
})

基本上就是這樣,但有一點問題。 “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,
})

您還可以觀察該值是否已更改或已首次設置

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

})

有關更多信息,請在此處查閱 Apples 文檔

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

還有另一種方法,通過使用 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) } }
  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

    將更新直接綁定到 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")

在這里你可以找到示例項目。 只需執行pod update並運行工作區文件即可。

var item = "initial value" {
    didSet { //called when item changes
        print("changed")
    }
    willSet {
        print("about to change")
    }
}
item = "p"
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
            }
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM