使用完成处理程序按顺序执行操作

Posted

技术标签:

【中文标题】使用完成处理程序按顺序执行操作【英文标题】:Doing things in sequence using completion handlers 【发布时间】:2019-01-04 06:22:18 【问题描述】:

我有三个函数需要依次运行如下:

    从 Firebase 收集整数,将它们放入数组中,然后计算总和。完成后... 从 Firebase 收集不同的整数值。完成后... 第三个函数从函数 2 中获取值,然后从函数 1 中减去它。

我知道我需要使用完成处理程序,但在语法等方面需要一些帮助。

//第一个函数从 Firebase 中获取整数并将它们相加:

func LoadPointsCompleted(completion: @escaping(_ sumOfPointsCompleted:Int) -> Int)

    self.challengeList.removeAll()

    databaseReference = Database.database().reference()

    let userID = Auth.auth().currentUser?.uid

    let refChallenges = Database.database().reference(withPath: "Challenges").child(userID!).queryOrdered(byChild: "Status").queryEqual(toValue: "Complete")

    refChallenges.observeSingleEvent(of: .value, with:  (snapshot) in

        //if the reference have some values
        if snapshot.childrenCount > 0 

            //clearing the list
            self.challengeList.removeAll()



            //iterating through all the values
            for Challenges in snapshot.children.allObjects as! [DataSnapshot] 
                //getting values
                let challengeObject = Challenges.value as? [String: AnyObject]
                let Points = challengeObject?["Points"] as! Int

                //creating challenge object with model and fetched values
                let challenge = pointsModel(Points: (Points as Int?)!)

                //appending it to list
                self.challengeList.append(challenge)


                let sumOfPointsCompleted = self.challengeList.reduce(0) $0 + $1.Points

                let sumOfPointsCompletedString = String(sumOfPointsCompleted)
                self.Calc_Earned.text = sumOfPointsCompletedString

                completion(sumOfPointsCompleted)

            

        

    

    )

// 第二个函数只是从 Firebase 中的另一个位置获取一个整数值

func loadPointsRedeemed(completion: @escaping (_ Points_Redeem: Int) -> Int) 


    databaseReference = Database.database().reference()

    let userID = Auth.auth().currentUser?.uid

    databaseReference.child("Users").child(userID!).observe(DataEventType.value, with:  (snapshot) in

        let value = snapshot.value as? NSDictionary

        // let Points_Earn = value?["Points_Earned"] as? String ?? ""
        let Points_Redeem = value?["Points_Redeemed"] as! Int


        // self.Points_Earned.text = Points_Earn

        let points_redeemedString = String(Points_Redeem)
        self.Points_Redeemed.text = points_redeemedString

        // let pointsRedeemedAs = Points_Redeem

        completion(Points_Redeem)

        // Do any additional setup after loading the view.
    

)

// 第三个函数只是从前两个函数中取值并减去它们

 func BalanceOfPoints()

    let a = LoadPointsCompleted()
    let b = loadPointsRedeemed()


    let balance = a - b
    let balanceString = String(balance)

    self.Points_Balance.text = balanceString


但是,我在第三个函数“BalanceOfPoints”中遇到一些错误,如下所示:

在调用中缺少参数“完成”的参数 - 插入“完成: Int>”

当我第一次启动函数时,我不知道我的语法是否正确:

func LoadPointsCompleted(completion: @escaping(_ sumOfPointsCompleted:Int) -> Int)

还有……

func loadPointsRedeem(completion: @escaping (_ Points_Redeem: Int) -> Int)

有人可以帮忙吗?提前致谢。

【问题讨论】:

不要使用顺序完成处理程序,使用 Promise 方法或 Dispatch Group。处理顺序完成处理程序很难管理 n 个句柄错误。 【参考方案1】:

LoadPointsCompleted 将闭包作为参数(完成处理程序)

你可以给它一个nil完成处理程序

LoadPointsCompleted(completion: nil)

或者给它一个处理程序

LoadPointsCompleted()  sumOfPointsCompleted in

    return <#some Int#>

但是你在BalanceOfPoints 中的逻辑似乎有点不对劲,因为LoadPointsCompletedloadPointsRedeemed 同时被顺序调用,而且实际上并没有返回Int,只有函数的完成处理程序会这样做。例如 completion(sumOfPointsCompleted) 可以更改为 let a = completion(sumOfPointsCompleted) 但我确定这不是您想要的。

我会将这两个函数的签名更改为

func LoadPointsCompleted(completion: @escaping(_ sumOfPointsCompleted:Int) -> Void)

func loadPointsRedeemed(completion: @escaping (_ Points_Redeem: Int) -> Void) 

然后在BalanceOfPoints 中改为这样做

func BalanceOfPoints()

    LoadPointsCompleted()  sumOfPointsCompleted in
        loadPointsRedeemed()  Points_Redeem in
            let balance = sumOfPointsCompleted - Points_Redeem
            let balanceString = String(balance)

            self.Points_Balance.text = balanceString
        
    

但请注意 BalanceOfPoints 现在是一个异步函数。

不确定您问题中的第 1 步和第 2 步是否可以并行完成,但似乎可以,但在这个答案中,它们是按顺序进行的

【讨论】:

嗨 Fonix,好的,这确实有效。但是,现在如何调用 viewDidLoad() 中的所有三个函数?简单地这样做是行不通的:LoadPointsCompleted() loadPointsRedeemed() BalanceOfPoints() 没关系...我需要做的就是调用 BalanceOfPoints()。有效!谢谢!

以上是关于使用完成处理程序按顺序执行操作的主要内容,如果未能解决你的问题,请参考以下文章

按顺序打开程序的批处理文件

如何按顺序执行操作并更新 UI

iOS下的并行开发

Java 线程

使用if语句编写Shell脚本

Shell脚本应用