swift Firebase return in asynchron Task

2019-03-07 02:36发布

I have a problem with the Firebase SDK for iOS in swift 2. Im trying to set a picture to a downloaded from the Firebase storage. When I call the function it gives back nil. I think its because the download task provided by the Firebase sdk is asynchron, so when the return state meant is called the uid which is necessary isn't set because the Task isn't finished. How can I solve this so I get the right picture returned?

override func viewDidLoad() {
   super.viewDidLoad()
   imageView.image = downloadProfilePicFirebase()
}

The Firebase download function:

func downloadProfilePicFirebase() -> UIImage{

    print("download called")

    //local paths
    let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    let documentDirectorPath:String = paths[0]
    let imagesDirectoryPath = documentDirectorPath.stringByAppendingString("/profiles")

    var uid = String()


    if let user = FIRAuth.auth()?.currentUser {
        let uid = user.uid

        let storageRef = FIRStorage.storage().referenceForURL("gs://myid.appspot.com")
        let profilePicRef = storageRef.child("/profile_pic.jpg")

        let homeDir: NSURL = NSURL.fileURLWithPath(NSHomeDirectory())
        let fileURL: NSURL = homeDir.URLByAppendingPathComponent("Documents").URLByAppendingPathComponent("profiles").URLByAppendingPathComponent("profile_pic").URLByAppendingPathExtension("jpg")

        // Download to the local filesystem
        let downloadTask = profilePicRef.writeToFile(fileURL) { (URL, error) -> Void in
            if (error != nil) {
                print(error)
            } else {
                // svaed localy now put in ImageView
            }
        }
    }
   return UIImage(contentsOfFile: "\(imagesDirectoryPath)"+"/profile_pic_user_"+uid+".jpg")!
}

1条回答
做自己的国王
2楼-- · 2019-03-07 03:07

Firebase is asynchronous as you mentioned so let it drive the flow of data within your app.

Don't try to return data from a Firebase block - let the block handle the returned data and then move to the next step once that data is valid within the block.

There's a couple of options:

One option is to populate your data from the .writeToFile completion handler

override func viewDidLoad() {
   super.viewDidLoad()
   downloadPic()
}

func downloadPic {
    let download = profilePicRef.writeToFile(localURL) { (URL, error) -> Void in
      if (error != nil) {
        // handle an error
      } else {
        imageView.image = UIImage(...
        //then update your tableview, start a segue, or whatever the next step is
      }
    }
}

A second option is add an observer to the node and when that completes, populate your imageView

override func viewDidLoad() {
   super.viewDidLoad()

   let download = storageRef.child('your_url').writeToFile(localFile)

   let observer = download.observeStatus(.Success) { (snapshot) -> Void in
     imageView.image = UIImage(...
     //then update your tableview, start a segue, or whatever the next step is
   }
}
查看更多
登录 后发表回答