通过分段/分段控制



我想将数据从UISettingsViewController传递到UIViewController(主视图)。

我想做的是,当我在UISettingsViewController中设置默认小费率时,UIViewController中的值和小费率会发生变化,例如,如果我将默认小费率设置为10%,它会在主视图控制器中发生变化,并在我打开应用程序时设置为默认值。

我希望这是一个明确的解释,我来自另一个不会说英语的国家。

请查看我留下的图像,以便更好地了解我正在尝试做什么,我缝合图像两视图的视图主情节提要(用户界面)代码

import UIKit
class ViewController: UIViewController {
// Inputs
@IBOutlet weak var amountTextField: UITextField!
//Labels
@IBOutlet weak var TipPercentageLabel: UILabel!
@IBOutlet weak var numberOfPersonLabel: UILabel!
@IBOutlet weak var tipAmountLabel: UILabel!
@IBOutlet weak var totalBillLabel: UILabel!
@IBOutlet weak var billPerPersonLabel: UILabel!
//Slider & Stepper
@IBOutlet weak var tipSlider: UISlider!
@IBOutlet weak var personsStepper: UIStepper!
//Variables
var tipPercentage:Double = 0.20
var numberOfPerson:Int = 1
let numberFormatter:NSNumberFormatter = NSNumberFormatter()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    tipAmountLabel.text = "$0.00"
    totalBillLabel.text = "Bill Total"
    billPerPersonLabel.text = "$0.00"
    TipPercentageLabel.text =  "20.0%"
    numberOfPersonLabel.text = "1"
    self.amountTextField.becomeFirstResponder()
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
func setupContainer() {

    tipSlider.minimumValue = 0
    tipSlider.maximumValue = 100
    tipSlider.value = 20
    tipSlider.addTarget(self, action: "sliderTipChanged:", forControlEvents: .ValueChanged)
    personsStepper.minimumValue = 1
    personsStepper.maximumValue = 30
    personsStepper.value = 1
    personsStepper.addTarget(self, action: "sliderPersonChanged:", forControlEvents: .ValueChanged)
    amountTextField.text = ""
    refreshCalculation()
}
@IBAction func OnEditingFieldBill(sender: AnyObject) {
    refreshCalculation()
}
func refreshCalculation() {
    numberFormatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
    if let amount = numberFormatter.numberFromString(amountTextField.text!) as? Double {
        let tipAmount = amount * tipPercentage
        let totalBill = amount + tipAmount
        let billPerPerson = totalBill / Double(numberOfPerson)
        numberFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
        tipAmountLabel.text = numberFormatter.stringFromNumber(tipAmount)
        totalBillLabel.text = numberFormatter.stringFromNumber(totalBill)
        billPerPersonLabel.text = numberFormatter.stringFromNumber(billPerPerson)
    } else {
        tipAmountLabel.text = "-"
        totalBillLabel.text = "-"
        billPerPersonLabel.text = "-"
    }
    numberFormatter.numberStyle = NSNumberFormatterStyle.PercentStyle
    numberFormatter.minimumFractionDigits = 1
    numberFormatter.maximumFractionDigits = 1
    TipPercentageLabel.text = self.numberFormatter.stringFromNumber(tipPercentage)
   numberOfPersonLabel.text = "(numberOfPerson)"
} 
@IBAction func sliderTipChanged(sender: UISlider) {
    tipPercentage = Double(round(tipSlider.value)) / 100
    refreshCalculation()
}

@IBAction func StepperPersonChanged(sender: UIStepper) {
    numberOfPerson = Int(round(personsStepper.value))
    refreshCalculation()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var DestViewController : SettingsViewController = segue.destinationViewController as! SettingsViewController
    DestViewController =
   }
}

最后一行说DestViewController =的地方,是我不知道该做什么以及是否好的地方

第二视图控制器

import UIKit
class SettingsViewController: UIViewController {
@IBOutlet weak var tipControl: UISegmentedControl!
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
@IBAction func DefaultRate(sender: AnyObject) {
    var tipRate = [5, 10, 15, 2, 25, 30]
    var tipRates = tipRate[tipControl.selectedSegmentIndex]
}

如果我理解正确,当您更改设置的默认速率时,您希望它能立即对主视图产生影响。因此,我建议您在设置中创建一个协议,并添加一个符合该协议的弱委托属性(将其设置为mainViewController)。然后,当设置中的速率发生变化时,会触发对代理的调用,从而导致mainViewController中的refreshCalculation。使用委托模式可以使2之间的意图和关系非常清晰且类型安全,但也可以防止2个视图控制器之间的保留循环。此外,您希望在加载mainViewController时设置默认值,因此在更改速率时也需要将速率保存在NSUserDefaults中。并使用0.20的备份从主视图初始化中的NSUserDefaults中读取它。

protocol SettingsDelegate {
  func tipPercentageChanged(newValue : Double)
}
class SettingsVC : UIViewController {
  var destName : String!
  var delegate : SettingsDelegate?
  @IBAction func segmentedValueChanged(sender : UISegmentedControl){
    var tipRates = [0.05, 0.10, 0.15, 0.2, 0.25, 0.30]
    let tipRate = tipRates[sender.selectedSegmentIndex]
    delegate?.tipPercentageChanged(tipRate)
    NSUserDefaults.standardUserDefaults().setDouble(tipRate, forKey: "DefaultTipRate")
    NSUserDefaults.standardUserDefaults().synchronize()
  }
}
class MainVC : UIViewController, SettingsDelegate {
  var tipPercentage : Double = NSUserDefaults.standardUserDefaults().doubleForKey("DefaultTipRate") ?? 0.20
  override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let settingsVC = segue.destinationViewController as? SettingsVC{
      settingsVC.delegate = self
    }
  }
  func tipPercentageChanged(newValue: Double) {
    tipPercentage = newValue
    refreshCalculation()
  }
}

在控制器之间传递数据的方法是,要将数据提供给的控制器(在本例中为视图控制器)具有可以在segue源控制器(在此例中为设置视图控制器)中设置的公共属性。

我看到您的视图控制器有一个名为tipPercentage的属性,所以我假设这是您想要设置的值。我还看到您有两个分段,一个从视图控制器到设置视图控制器,然后返回。请注意,在故事板中设置segue标识符是很重要的,即使您只有一个segue,它也可以保持代码的干净、可维护和无错误。如果您有多个segue,那么标识符将是必需的。

要设置标识符,请进入情节提要,单击片段本身,然后在右侧窗格中为其提供标识符。为了实现这段代码的目的,我将调用第一个"showSettings"和第二个<strong]"goBackToViewController">

你为赛格做准备的方式和你做的有点不同。你在ViewController末尾写的几行应该是:

override func prepareForSegue(segue: UIStoryboardSegue, sender:AnyObject?) {
    if let id = segue.identifier { //identifier could be nil
       if id == "showSettings" {
           if let swv = segue.destination.destinationViewController as? SettingsViewController {
               //Do any preparation here 
            }
        }
    }
}

现在,对于你真正感兴趣的片段,我们需要做一点准备。首先,您在函数中声明了tipRates,因此永远无法从prepareFoeSegue访问它。相反,在类的顶部声明变量:

var tipRates:Double?

并像这样更改违约率:

@IBAction func DefaultRate(sender: AnyObject) {
    var tipRate = [5, 10, 15, 2, 25, 30]
    tipRates = Double(tipRate[tipControl.selectedSegmentIndex]) //We cast because tipRates is a double but tipRate an [Int]
}

既然我们可以访问类中的变量,我们就可以愉快地分段了。将以下代码放入设置视图控制器中:

override func prepareForSegue(segue: UIStoryboardSegue, sender:AnyObject?) {
    if let id = segue.identifier { //identifier could be nil
       if id == "goBackToViewController" {
           if let vc = segue.destination.destinationViewController as? ViewController {
                if let tip = tipRates {
                    vc.tipPercentage = tip/100 //We want the percentage
                }
            }
        }
    }
}

瞧!您的ViewController已获取信息。最后,请注意,当编译器能够弄清楚类型时,显式提及类型是不好的。例如var tipPercentage:Double = 0.20应该是var tipPercentage = 0.20

当编译器仅通过查看值就知道它是双精度的。此外,考虑将应用程序嵌入UINavigationController中以便于导航。

最新更新