如何快速使用异步函数?完成处理程序[重复]

Posted

技术标签:

【中文标题】如何快速使用异步函数?完成处理程序[重复]【英文标题】:How to work with async functions swift? Completion handlers [duplicate] 【发布时间】:2017-11-12 22:45:14 【问题描述】:

我试图等待函数处理以显示我的图像。我尝试了很多东西,但没有一个奏效。我知道这是一个异步函数,基本上我必须等待才能获得正确的值,但我不知道如何在这里修复这个函数。我希望你能帮助我。谢谢!

     func createListProductsGood(Finished() -> void) 

        refProducts.child("Products").queryOrderedByKey().observe(.childAdded, with:  snapshot in

            let prod = snapshot.value as! NSDictionary
            let active = snapshot.key
            let rejected = prod["NotInterested"] as! String
            let photoURL = prod["photoURL"] as! String
            var findit = false

           // print(rejected)

            if (rejected != self.userUID)
                //print(active)
                if rejected.contains(",")
                     var pointsArr = rejected.components(separatedBy: ",")
                        for x in pointsArr
                                if x.trimmingCharacters(in: NSCharacterSet.whitespaces) == self.userUID 
                                   // print("dont show")
                                    findit = true
                                    return
                                
                            

                    if (findit == false)
                        if let url = NSURL(string: photoURL) 
                            if let data = NSData(contentsOf: url as URL) 
                                self.ProductId = active
                                self.productPhoto.image = UIImage(data: data as Data)
                            
                    
                else
                    print(active)
                    if let url = NSURL(string: photoURL) 
                        if let data = NSData(contentsOf: url as URL) 
                            self.ProductId = active
                            self.productPhoto.image = UIImage(data: data as Data)

                        
                


            

               )

    finished()



已编辑:

这就是我的 viewDidLoad 的样子:

override func viewDidLoad() 
    super.viewDidLoad()
    setAcceptedOrRejected()
    createListProductsGood_ in
    






 func createListProductsGood(finished: @escaping (_ imageData: Data) -> Void) 

        refProducts.child("Products").queryOrderedByKey().observe(.childAdded, with:  snapshot in

            let prod = snapshot.value as! NSDictionary
            let active = snapshot.key
            let rejected = prod["NotInterested"] as! String
            let photoURL = prod["photoURL"] as! String
            var findit = false

           // print(rejected)

            if (rejected != self.userUID)
                //print(active)
                if rejected.contains(",")
                     var pointsArr = rejected.components(separatedBy: ",")
                        for x in pointsArr
                                if x.trimmingCharacters(in: NSCharacterSet.whitespaces) == self.userUID 
                                   // print("dont show")
                                    findit = true
                                    return
                                
                            

                    if (findit == false)
                        if let url = NSURL(string: photoURL) 
                            if let data = NSData(contentsOf: url as URL) 
                                self.ProductId = active
                                DispatchQueue.main.async 
                                    self.productPhoto.image = UIImage(data: data as Data)
                                
                            
                    
                else
                    print(active)
                    if let url = NSURL(string: photoURL) 
                        if let data = NSData(contentsOf: url as URL) 
                            self.ProductId = active
                            DispatchQueue.main.async 
                             self.productPhoto.image = UIImage(data: data as Data)
                            
                        
                
        
             )


这是我的第二种方法:

func setAcceptedOrRejected() 
    refProducts.child("Products").queryOrderedByKey().observe(.childAdded, with:  snapshot in

        let prod = snapshot.value as! NSDictionary

        if self.ProductId == snapshot.key

            self.texto = prod["NotInterested"] as! String
            self.refProducts.child("Products").child(self.ProductId).updateChildValues(["NotInterested": self.texto + ", " + self.userUID])

         )

【问题讨论】:

【参考方案1】:

你应该改变:

func createListProductsGood(Finished() -> void) 

到:

func createListProductsGood(finished: @escaping (_ something: SomeType) -> Void) 

或者更具体一点:

func createListProductsGood(finished: @escaping (_ imageData: Data) -> Void) 

然后,无论您在函数中获得图像的任何位置,调用

finished(imageData)

这样您就可以通过 闭包 将 imageData 传递 到需要的地方。

然后你像这样调用这个函数:

createListProductsGood imageData in 
    ...
   let image = UIImage(data: imageData)

   // update UI from main Thread:
   DispatchQueue.main.async 
   self.productPhoto.image = image
   

还有:

不习惯使用Finished(),你应该使用finished()

使用void 是错误的。您必须使用Void()


如果您在使用闭包和完成处理程序时遇到问题,我建议您首先尝试使用简单的 UIAlertController。见here。尝试使用闭包创建一个动作,例如见here


编辑:

感谢 Leo 的 cmets:

func createListProductsGood(finished: @escaping(_ imageData: Data?, MyError?) -> Void) 

let value: Data?
let error = MyError.someError("The error message")

    refProducts.child("Products").queryOrderedByKey().observe(.childAdded, with:  snapshot in

        let prod = snapshot.value as! NSDictionary
        let active = snapshot.key
        let rejected = prod["NotInterested"] as! String
        let photoURL = prod["photoURL"] as! String
        var findit = false

        // print(rejected)

        if (rejected != self.userUID)
            //print(active)
            if rejected.contains(",")
                var pointsArr = rejected.components(separatedBy: ",")
                for x in pointsArr
                    if x.trimmingCharacters(in: NSCharacterSet.whitespaces) == self.userUID 
                        // print("dont show")
                        findit = true
                        return
                    
                

                if (findit == false)
                    if let url = NSURL(string: photoURL) 
                        if let data = NSData(contentsOf: url as URL) 
                            self.ProductId = active // REMOVE
                            self.productPhoto.image = UIImage(data: data as Data) // REMOVE
                            finished(data, nil) //ADD
                        else
                            finished(nil,error) //ADD
                        
                    
                
            else
                print(active)
                if let url = NSURL(string: photoURL) 
                    if let data = NSData(contentsOf: url as URL) 
                        self.ProductId = active // REMOVE
                        self.productPhoto.image = UIImage(data: data as Data) // REMOVE
                        finished(data,nil) //ADD
                    else
                        finished(nil,error) //ADD
                    
                
            

        
    )

然后你这样称呼它:

   createListProductsGood  imageData, error in guard let value = imageData, error == nil else  // present an alert and pass the error message return  

   ...
   let image = UIImage(data: imageData)

   // update UI from main Thread:
   DispatchQueue.main.async  
   self.ProductId = active

   self.productPhoto.image = image  

基本上这种方式createListProductsGood 接受2 个闭包,一个用于如果图像存在,另一个用于如果返回错误。

【讨论】:

以上是关于如何快速使用异步函数?完成处理程序[重复]的主要内容,如果未能解决你的问题,请参考以下文章

快速完成处理程序

使用完成处理程序进行异步调用的多个 URLSession dataTask 导致内存上升

C++ Qt 异步进程快速计时建议

发出调用快速完成处理程序关闭的问题

循环的快速完成处理程序将执行一次,而不是由于循环而执行10次

如何在 Express 请求处理程序中编写非阻塞异步函数 [重复]