通过segue / segmented控制传递

时间:2015-12-09 07:55:11

标签: iphone xcode swift swift2 segue

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

我试图做的是当我在UISettingsViewController中设置默认提示费率时UIViewController中的值和提示费率更改,例如,如果我将默认提示费率设置为10%在主视图控制器中更改,并在我打开应用程序时设置为默认值。

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

请查看我留下的图片,以便更好地了解我正在尝试做的事情,我缝合图像The View MainStoryBoard (user interface) code of Two Views

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]
}

2 个答案:

答案 0 :(得分:0)

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

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

}

答案 1 :(得分:0)

在控制器之间传递数据的方法是为您要提供数据的控制器(在本例中为View Controller)提供可在segue源控制器中设置的公共属性(在本例中为“设置视图”)控制器)。

我发现您的View Controller有一个名为tipPercentage的属性,因此我假设这是您要设置的值。我还看到你有两个segue,一个从View Controller到Settings View Controller,然后返回。请注意,在故事板中设置segue标识符很重要,即使您只有一个segue,它也可以保持代码清洁,可维护和无bug。如果您有多个segue,则必须使用标识符。

要设置标识符,请进入故事板,单击segues本身,然后在右侧窗格中为其指定标识符。出于此代码的目的,我将调用第一个segue " showSettings" 和第二个" goBackToViewController"

你为segue做准备的方式与你所做的有点不同。您在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 
            }
        }
    }
}

现在对于你真正感兴趣的segue,我们需要做一点准备。首先,您在函数中声明了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]
}

现在我们可以访问类中的变量,我们可以愉快地进行调整。将以下代码放在SettingsViewController中:

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中以便于导航。