Swift 将计算的数据传回之前的视图控制器

Posted

技术标签:

【中文标题】Swift 将计算的数据传回之前的视图控制器【英文标题】:Swift passing calculated data back to previous view controller 【发布时间】:2018-03-10 06:05:25 【问题描述】:

我正在创建我的第一个简单的预算应用程序。基本上,我会接受一些用户输入,例如月收入和储蓄目标。然后他们点击“开始”,应用程序会计算他们的每日预算等内容。

在这里我遇到了麻烦。在所有的计算之后,我会显示“你每天可以花多少钱”(例如每天 20 美元),我会通过原始屏幕上的原始输入将其传递出去。

现在,在这个 VC (UserInfoVC) 中,我创建了一个按钮,让他们可以添加他们今天花了多少钱。所以当他们点击这个“添加花费的钱”按钮时,我打开一个新的 VC (AddSubtractMoney),在那里我展示了一个计算器,他们可以在其中输入他们今天花了多少钱(即 12 美元)并点击提交。

我将他们的输入与他们的每日预算进行比较,以获得新的每日预算。

现在,我无法将这个更新后的数字向后传递,以便在标签“dailySpendingLimitLabel”上的前一个 VC 上显示它。我知道 segues 不是向后传递数据的最佳方法。

我尝试过闭包,但最终迷失在语法、协议和委托(这是我的第二个月编码)中。

有没有一种简单的方法可以实现将这些数据传回之前的 VC 并在之前的显示标签中填充数据?

下面是代码。

第一个 sn-p 来自 UserInfoVC,我在其中显示了他们最初输入的数据,这些数据是我通过的。第二个 sn-p 来自 AddSubtractMoney 类,我在其中放置了计算器并在函数内创建了一个对象“newestUpdate”,该函数允许我计算他们在计算器上输入的数字减去他们原来的每日预算。为了得出一个我想向后提交给UserInfoVC的新预算。

class UserInfoViewController : ViewController 

var userNamePassedOver : String?
var userDailyBudgetPassedOver : Double = 99.0
var userDailySavingsPassedOver : Double = 778.00
var userMonthlyEarningsPassedOver : Double?
var userDesiredSavingsPassedOver : Double?
var newAmountPassedBack : Double = 0.0


@IBOutlet weak var dailySavingsNumberLabel: UILabel!
@IBOutlet weak var userNameLabel: UILabel!
@IBOutlet weak var dailySpendingLimitLabel: UILabel!



override func viewDidLoad() 
    super.viewDidLoad()

    userNameLabel.text = userNamePassedOver
    dailySpendingLimitLabel.text = String(format: "%.2f", userDailyBudgetPassedOver)
    dailySavingsNumberLabel.text = String(format: "%.2f", userDailySavingsPassedOver)




@IBAction func addSubtractMoneyPressed(_ sender: UIButton) 

    performSegue(withIdentifier: "addOrSubtractMoney", sender: self)




override func prepare(for segue: UIStoryboardSegue, sender: Any?) 

    if segue.identifier == "addOrSubtractMoney"

        let addOrSubtractMoneyVC = segue.destination as! AddSubtractMoney

            addOrSubtractMoneyVC.dailyBudgetPassedThrough = userDailyBudgetPassedOver
        
    



extension UserInfoViewController: AddSubtractMoneyDelegate 

func calculatedValue(value: Double) 

    dailySpendingLimitLabel.text = String(userDailyBudgetPassedOver - value)





import UIKit

protocol AddSubtractMoneyDelegate 
  func calculatedValue(value: Double)


class AddSubtractMoney: UIViewController 

@IBOutlet weak var outputLabel: UILabel!

var runningNumber = ""
var finalNumberPassedOver : Double?
var amountPassedBackToUserInfo : Double = 0.0
var dailyBudgetPassedThrough : Double = 0.0

var delegate: AddSubtractMoneyDelegate?

override func viewDidLoad() 
    super.viewDidLoad()

    outputLabel.text = "0"


    // Do any additional setup after loading the view.



@IBAction func buttonPressed(_ sender: UIButton) 
    runningNumber += "\(sender.tag)"
    outputLabel.text = runningNumber




@IBAction func submitNewInfo(_ sender: UIButton) 

    // FIX FIX

    AddSubtractMoneyController.addToMoneySpentArray(amountISpent: outputLabel.text!)

    sendBackUpdatedNumber()

    dismiss(animated: true, completion: nil)




@IBAction func allClearedPressed(_ sender: UIButton) 
    runningNumber = ""
    outputLabel.text = "0"


// THIS LINE PRODUCES THE CORRECT INPUT IN OUTPUT CONSOLE WHEN I PRINT- BUT I CANT FIGURE HOW TO TRANSFER IT BACK TO PREVIOUS VC

func sendBackUpdatedNumber()

    let newestUpdate = UserInfo(whatYouSpentToday: runningNumber, oldDailyBudgetPassed: dailyBudgetPassedThrough)

   amountPassedBackToUserInfo = dailyBudgetPassedThrough - Double(runningNumber)!
   newestUpdate.goalToSaveDaily = amountPassedBackToUserInfo

    print(amountPassedBackToUserInfo)

    self.delegate?.calculatedValue(value: amountPassedBackToUserInfo)






【问题讨论】:

你可以使用协议委托 可能重复***.com/questions/25522912/… 感谢两位的建议! 【参考方案1】:

我的建议是使用回调闭包。与协议/委托相比,它的代码更少,更容易处理。

AddSubtractMoney 中声明一个callback 变量并在sendBackUpdatedNumber 中调用它并传递Double

class AddSubtractMoney: UIViewController 

   // ...

    var callback : ((Double)->())?

  // ...

    func sendBackUpdatedNumber()

        let newestUpdate = UserInfo(whatYouSpentToday: runningNumber, oldDailyBudgetPassed: dailyBudgetPassedThrough)
        amountPassedBackToUserInfo = dailyBudgetPassedThrough - Double(runningNumber)!
        newestUpdate.goalToSaveDaily = amountPassedBackToUserInfo
        print(amountPassedBackToUserInfo)
        callback?(amountPassedBackToUserInfo)
    

prepare(for segue 中将闭包分配给callback 变量并添加要在返回时执行的代码

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 

    if segue.identifier == "addOrSubtractMoney"
        let addOrSubtractMoneyVC = segue.destination as! AddSubtractMoney
        addOrSubtractMoneyVC.callback =  result in
             print(result)
            // do something with the result
        
        addOrSubtractMoneyVC.dailyBudgetPassedThrough = userDailyBudgetPassedOver
    

【讨论】:

哇,这非常简单而且有效!非常感谢!根据我的理解,闭包是一个高级主题,但是在遵循并理解了您的逻辑之后,您在我的脑海中描绘了一幅非常清晰的画面。再次感谢 不要忘记在闭包内使用 [weak self] 以避免内存泄漏。 @atereshkov 你好。我应该在哪里使用weak self?你能提供一个代码应该是什么样子的 sn-p/模板吗?谢谢。 @fishhau 只是谷歌“弱自我封闭”。 ***.com/questions/24468336/… 在这种特殊情况下,如果您稍后使用 result 触发 self,则: addOrSubtractMoneyVC.callback = [weak self] result in ... 【参考方案2】:

使用委托

if segue.identifier == "addOrSubtractMoney" 

    let addOrSubtractMoneyVC = segue.destination as! AddSubtractMoney

        addOrSubtractMoneyVC.dailyBudgetPassedThrough = userDailyBudgetPassedOver

       addOrSubtractMoneyVC.delegate = self
    

你需要在AddSubtractMoney类中添加delegate属性

var delegate: AddSubtractMoneyDelegate?

AddSubtractMoney 类中创建协议

protocol AddSubtractMoneyDelegate 
  func calculatedValue(value: Double)

并回复委托

 func sendBackUpdatedNumber()

    let newestUpdate = UserInfo(whatYouSpentToday: runningNumber, oldDailyBudgetPassed: dailyBudgetPassedThrough)

   amountPassedBackToUserInfo = dailyBudgetPassedThrough - Double(runningNumber)!
   newestUpdate.goalToSaveDaily = amountPassedBackToUserInfo

    print(amountPassedBackToUserInfo)

    self.delegate.calculatedValue(value: amountPassedBackToUserInfo)

现在你需要在设置了委托的类中实现这个委托方法。

这里在UserInfoViewController 中设置了类委托,所以你需要实现它的委托方法

extension UserInfoViewController: AddSubtractMoneyDelegate 

  func calculatedValue(value: Double) 

       //set label here
   


【讨论】:

感谢您的快速回复!我遵循了你所有的代码,对于扩展,我放置了这个代码来设置标签扩展 UserInfoViewController: AddSubtractMoneyDelegate func computedValue(value: Double) dailySpendingLimitLabel.text = String(userDailyBudgetPassedOver - value) 但是,我仍然无法让先前的视图控制器上的视图显示 userDailyBudget - 我传回的值 我需要做一个“视图确实出现”调用或什么?用这些新号码替换旧号码? 你只是错过了兄弟...addOrSubtractMoneyVC.delegate = self 将其设置为prepareForSegue...:) 是的!!!非常感谢我的朋友..你是一个很大的帮助..我开始更多地了解委托和协议流程!我真的很感谢您的帮助!【参考方案3】:

您也可以使用unwind segue 传回数据。

【讨论】:

Here 是来自 Google Developers YouTube 频道的 5 分钟视频,它很好地展示了 unwind segues 的来龙去脉。【参考方案4】:

如果您不了解委托背后的流程(面向协议),您可以简单地浏览以下代码。仅当两个类都有效时

但这不是一个好习惯 了解协议、闭包或通知中心广播,了解最常用、灵活且可重用的编码方法。

UserInfoViewController

class UserInfoViewController : ViewController 
   fun receiveBackUpdatedNumber(numberString:String)

   

   override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
      if segue.identifier == "addOrSubtractMoney"
        let addOrSubtractMoneyVC = segue.destination as! AddSubtractMoney
      addOrSubtractMoneyVC.userInfoViewController = self
        
      

   
 

AddSubtractMoney

class AddSubtractMoney: UIViewController 
  var userInfoViewController: UserInfoViewController!
  var updatedNumber = ""
  func sendBackUpdatedNumber()
    self.userInfoViewController.receiveBackUpdatedNumber(numberString: updatedNumber)
   

如果你确定你可以使用协议。协议坚持一个类强制实现一个方法,这使得代码更可重用和独立。

在上述方法中,我们在执行 segue 时将当前视图控制器(UserInfoViewController)的实例传递给下一个视图控制器(AddSubtractMoney),因此我们可以访问 UserInfoViewController 中函数的任何属性strong> 来自 AddSubtractMoney。所以很容易将数据从 AddSubtractMoney 传递到 -> UserInfoViewController

【讨论】:

创建之前的VC对象来传回数据并不是一个好习惯。 是的,我知道!我得出这个结论..随时编辑答案。 如果某些部分有误,我会进行编辑,但我不会用新的答案替换您的整个答案。顺便说一句,您可以检查其他正确的答案,甚至我在任何答案之前都做了评论。

以上是关于Swift 将计算的数据传回之前的视图控制器的主要内容,如果未能解决你的问题,请参考以下文章

将数据传回 MVVM

使用委托将 NSMutableArray 传回前一个视图控制器

Swift如何更新先前视图控制器中的标签

将@Html.EditorFor“日期”值传回控制器,操作值并传回视图以填充下拉列表

Swift - 将数据从父视图控制器传递到子视图控制器

关闭时如何从模态视图控制器传回数据