与完成处理程序结合使用的返回值存在问题

Posted

技术标签:

【中文标题】与完成处理程序结合使用的返回值存在问题【英文标题】:Having an issue with a return value in combination with a completion handler 【发布时间】:2017-09-16 11:24:58 【问题描述】:

我创建了 setAvatarImage 函数来下载 UIImage,然后在默认集合视图函数中返回该 UIImage。我可以在控制台中看到 UIImage 正在下载,因此返回值应该是 UIImage。但是,集合视图中不显示任何图像。

func setAvatarImages(_ senderUid: String!, completionhandler: @escaping (UIImage!) -> Void) 

    let ref = DatabaseReference.users(uid: senderUid).reference()
    ref.observe(.value, with:   (snapshot) in
        let user = User(dictionary: snapshot.value as! [String : Any])
        user.downloadProfilePicture(completion:  (image, error) in
            if image != nil 
                let profileImage = image
                print(profileImage!)
                completionhandler(profileImage!)
             else if error != nil 
                print(error?.localizedDescription ?? "")
            
        )
    )


override func collectionView(_ collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAt indexPath: IndexPath!) -> JSQMessageAvatarImageDataSource! 

    let message = messages[indexPath.item]
    var avatarImage: JSQMessagesAvatarImage!
    setAvatarImages(message.senderUID)  (profileImage) in
        avatarImage = JSQMessagesAvatarImageFactory.avatarImage(with: profileImage, diameter: UInt(kJSQMessagesCollectionViewAvatarSizeDefault))
        print(avatarImage)
    
    return avatarImage

我认为异步返回函数有问题。但我认为,给 setAvatarImage 函数一个完成处理程序应该可以解决这个问题。 谁能给我一些建议,以便返回下载的图像!

编辑!!!

考虑到 Alex 的建议,我更改了 setAvatarImage 函数。 首先我创建了一个字典:

   var profileImages = [String : UIImage]()

目的是将所有图像放入 profileImages 中,其中 user.uid 作为 viewdidLoad 中的键。

func setAvatarImages() 

    for user in chat.users 
        print(user.fullName)
        user.downloadProfilePicture(completion:  (image, error) in
            print(image!)
            if let profileImage = image 
                self.profileImages[user.uid] = profileImage
             else if error != nil 
                print(error?.localizedDescription ?? "")
            
        )
    

SetAvatarImages 在 vi​​ewDidLoad 中被调用。

为了从 JSQMessagesViewController 返回默认函数中的 AvatarImage,我这样做了:

 override func collectionView(_ collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAt indexPath: IndexPath!) -> JSQMessageAvatarImageDataSource! 

    let message = messages[indexPath.item]
    let avatarImage = JSQMessagesAvatarImageFactory.avatarImage(with: profileImages[message.senderUID], diameter: UInt(kJSQMessagesCollectionViewAvatarSizeDefault))
    return avatarImage

很酷的是它确实有效,尝试了几次。但是在 user.downloadProfileImage 函数中下载图像时突然崩溃。在它每次开始崩溃之前我唯一改变的是我删除了控制台中的断点以查看它的工作速度......有没有人知道它为什么现在崩溃了。 是的,我知道最好为图像添加一些缓存,但首先必须解决这个问题!

【问题讨论】:

我个人不是在使用 JSQMessages,但是当你在 Github 上查看他们的项目时,似乎语法不同,所以你可能想看看那里:)。同样对于您的图像变量,我建议您不要将其大写,因为大写名称通常用于类和结构名称,当有人阅读您的代码时可能会造成混淆 是的,我看了一下,但从逻辑上讲,与他们的代码相比,我看不出我使用的方法有什么缺点。 downloadProfilePicture 功能非常适合应用程序的其余部分快速下载图片。不过感谢您的回复,我会在示例项目中再次查看 嗯,我刚刚注意到,您是否尝试将返回的 avatarImage 放入您的 setAvatarImages 完成块中?因为由于您的完成块是异步调用的,所以很可能会在您的完成块被调用之前调用“return avatarImage”行。这可能是这里的问题 嗯,我尝试了很多东西,但我认为,用 return 命令洞察完成块是不可能返回一些东西的,因为完成块无法处理它。至少那是我所经历的。 是的,实际上你可能会在一个预期返回 'JSQMessageAvatarImageDataSource' 的函数中得到一个 Missing 返回 .. 再说一次我不确定 JSQMessages 是如何工作的,但你可以尝试把你的 setAvatarImages(message.senderUID ) 方法在 viewDidLoad 中,当你得到你的 profileImage 时,你使用 JSQMessagesAvatarImageFactory.avatarImage() 设置它,然后你重新加载你的数据,这将导致你的数据源方法再次运行 【参考方案1】:

终于明白了!

我只需要在 setAvatarImages 函数中添加一个完成处理程序!

 func setAvatarImages(completion: @escaping ([String : UIImage]) -> Void) 

    for user in chat.users 
        print(user.fullName)
        user.downloadProfilePicture(completion:  (image, error) in
            print(image!)
            if let profileImage = image 
                self.profileImages[user.uid] = profileImage
                completion(self.profileImages)
             else if error != nil 
                print(error?.localizedDescription ?? "")
            
        )
    

然后在viewDidLoad中

setAvatarImages(completion:  (profileUserImages) in
        print(profileUserImages)
    )

下一次停止缓存!

【讨论】:

以上是关于与完成处理程序结合使用的返回值存在问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 的完成处理程序中返回布尔值

Xcode 要求在完成处理程序中的返回值名称之前放置 _ [重复]

Alamofire 请求最初返回值,但在通过完成处理程序时被接收为 nil

DispatchQueue.main.async 块中未更新完成处理程序的返回值

如何在视图中显示来自 Swift 完成处理程序的返回值?

spring mvc怎么处理返回值