将 Swift 中的属性绑定到 NSTextFields

Bind properties in Swift to NSTextFields

我正在开发一个用 Swift 编写的单位转换器,它会在适当的 NSTextField 秒内自动显示更新后的单位。对于此示例,如果用户在 minutesField 中输入分钟,secondsFieldhoursField 应自动更新以显示属性的转换值。下面是我的视图控制器中的代码示例:

import Cocoa

class ViewController: NSViewController {

    @IBOutlet weak var secondsField: NSTextField!
    @IBOutlet weak var minutesField: NSTextField!
    @IBOutlet weak var hoursField: NSTextField!

    var sec: Double = 1
    var min: Double = 1
    var hr: Double = 1

    let conv = [[1,     0.0166666666666667, 0.000277777777777778],
                [60,    1,                  0.0166666666666667],
                [3600,  60,                 1]]

    func updateTextFields() {
        secondsField.stringValue = "\(sec)"
        minutesField.stringValue = "\(min)"
        hoursField.stringValue = "\(hr)"
    }
}

extension ViewController: NSTextFieldDelegate {

    override func controlTextDidChange(obj: NSNotification) {

        let tag = obj.object?.tag() ?? 0
        let text = obj.object?.stringValue ?? "1"
        let value = Double(text) ?? 1.0

        switch tag {
        case 0:
            // base unit = seconds
            sec = value
            min = value * conv[0][1]
            hr = value * conv[0][2]
        case 1:
            // base unit = minutes
            sec = value * conv[1][0]
            min = value
            hr = value * conv[1][2]
        case 2:
            // base unit = hours
            sec = value * conv[2][0]
            min = value * conv[2][1]
            hr = value
        default:
            "none"
        }
        updateTextFields()
    }    
}

上面的代码更新了文本字段,但输入的活动字段在第一次击键后冻结。例如,如果您尝试在秒字段中输入 60,则下一次击键不会执行任何操作。数字 6.0 出现在第一次击键之后(见下图)。这可能是由于更新属性后调用的函数。属性根据活动文本字段的标签更新。

是否可以有一个功能来更新当前活动字段以外的所有其他文本字段?

您需要将文本字段值的设置从 viewDidLoad() 移到单独的方法中。从 viewDidLoad() 以及您 seconds 属性.

上的 didSet 属性 观察者调用该方法

您还需要为秒、分或小时字段更改时创建操作方法。在秒字段的操作方法中,将 seconds 属性 设置为 secondsField.floatValue。其他两个字段也类似。在 NIB/storyboard 中,将文本字段的操作连接到视图控制器上相应的操作方法。

Is it possible to have a function that will update all the other text fields other than the currently active field?

是的。您可以将所有文本字段连接到同一操作。

首先将所有文本字段相应地连接到视图控制器:

@IBOutlet weak var hourField: NSTextField!
@IBOutlet weak var minuteField: NSTextField!
@IBOutlet weak var secondField: NSTextField!

其次创建一个单独的变量来表示您的时间间隔。您还可以添加一个 setter / getter 以将其自动存储到 USerDefaults:

var timeInterval: TimeInterval {
    get {
        return UserDefaults.standard.double(forKey: "timeInterval")
    }
    set {
        UserDefaults.standard.set(newValue, forKey: "timeInterval")
    }
}

第三次创建一个 TimeInterval 扩展,将时间从秒转换为 hour/minute

extension TimeInterval {
    var second: Double { return self }
    var minute: Double { return self / 60 }
    var hour:   Double { return self / 3600 }
    var hourToMinute:   Double { return self * 60 }
    var hourToSecond:   Double { return self * 3600 }
    var minuteToHour:   Double { return self / 60 }
    var minuteToSecond: Double { return self * 60 }
}

第四次创建将更新其他文本字段的操作:

@IBAction func timeAction(sender: NSTextField) {
    // use guard to convert the field string to Double
    guard let time = Double(sender.stringValue) else { return }
    // switch the field  
    switch sender {
    case hourField:
        // convert / update secondary fields
        minuteField.stringValue = time.hourToMinute.description
        secondField.stringValue = time.hourToSecond.description
        // make it persist through launches
        timeInterval = time * 3600
    case minuteField:
        hourField.stringValue = time.minuteToHour.description
        secondField.stringValue = time.minuteToSecond.description
        timeInterval = time * 60
    default:
        hourField.stringValue = time.hour.description
        minuteField.stringValue = time.minute.description
        timeInterval = time
    }
}

最后但并非最不重要的一点是确保在下次显示视图时加载这些值:

override func viewWillAppear() {
    hourField.stringValue = timeInterval.hour.description
    minuteField.stringValue = timeInterval.minute.description
    secondField.stringValue = timeInterval.second.description
}

Sample Project