0
votes

Thanks to the major update in Firebase, I'm switching the image hosting for my app from AWS to the now included GS Storage in Firebase. I've already imported all necessary pods, this app already do successfully upload images to assigned buckets, but the problem is when I want to download to memory images stored, and the app is crashing, debugging I found the following error in my FIRStorageReference object: "use of undeclared type 'FirebaseStorage'" I'm importing the Firebase header to the VC where the function is located.

func getImage(imageName: String) -> UIImage {
    let imageRef = kBucketRef.child(imageName) 
    print(imageRef) 
    var imageData: NSData? 
    var image: UIImage? 
    imageRef.dataWithMaxSize(200 * 1024) { (data, error) -> Void in 
        if (error != nil) { 
        imageData = data 
        image = UIImage(data: imageData!) 
        } else { 
            print(error?.localizedDescription) 
        } 
   }
    return image! 
}

later when trying to display image in: image.image = getImage(imageName) is called it throws the mentioned error in return image!

fatal error: unexpectedly found nil while unwrapping an Optional value

Printing description of imageRef: expression produced error: /var/folders/9q/g2rz2_hj15548cf15yrxz37c0000gn/T/lldb/1645/expr11.swift:1:46: error: use of undeclared type 'FirebaseStorage' $__lldb__DumpForDebugger(Swift.UnsafePointer< FirebaseStorage.FIRStorageReference >(bitPattern: 0x11d028fa0).memory) ^~~~~~~~~~~~~~~ /var/folders/9q/g2rz2_hj15548cf15yrxz37c0000gn/T/lldb/1645/expr11.swift:1:45: note: while parsing this '<' as a type parameter bracket $__lldb__DumpForDebugger(Swift.UnsafePointer(bitPattern: 0x11d028fa0).memory)

The output from 'print(imageRef)' prints the GS reference (gs://project-xxxxxx...) but the '.dataWithMaxSize()' fails

Thanks in advance


(days later) Ok, here is a workaround since the FIRStorage methods are not modifying vars in a separated function for later return:

let bucket: String = "gs://mystoragetesterxxxxxx.appspot.com"


func getImage() {

    let storage = FIRStorage.storage()
    let storageRef = storage.referenceForURL(bucket)
    let path = storageRef.child("photo.jpg")
    print(path)
    path.dataWithMaxSize(1024 * 1024) { (data, error) in
        if (error != nil) {
            print(error!.localizedDescription)
        } else {
            self.imageView.image = UIImage(data: data!)
        }
    }

}

Now getImage it's a void function, but it works

2

2 Answers

1
votes

Are you sure this isn't just an issue where you're declaring an optional type:

var image: UIImage?

Then calling an async function

imageRef.dataWithMaxSize...

and then without waiting for it, returning an implicitly unwrapped optional?

return image!

Seems to me like since image is nil, you're "unexpectedly unwrapping a nil" that is pretty much relying on a race condition to succeed.

I'd try something more like:

var image: UIImage? 
imageRef.dataWithMaxSize(200 * 1024) { (data, error) -> Void in 
    if (error != nil) { 
        return UIImage(data: data!)!
    } else { 
        print(error?.localizedDescription) 
    } 
}

In general though, wrapping an async call and trying to make it synchronous is a bad idea (unless you implement something like promises)--you should just use the async call to then update the UI element back on the main thread.

1
votes

Try something like this

let storage = FIRStorage.storage()

then the function

    func getImage(imageName: String) -> UIImage {
        let gsReference = storage.referenceForURL(imageName!)

        print(imageRef) 
        var imageData: NSData? 
        var image: UIImage? 
        let downloadTask = gsReference.dataWithMaxSize(200 * 1024) { (data, error) -> Void in 
            if (error != nil) { 
            //imageData = data 
            //image = UIImage(data: imageData!) 

             let image = UIImage.init(data: data!)

            } else { 
                print(error?.localizedDescription) 
            } 

          downloadTask.observeStatus(.Resume) { (snapshot) -> Void in
                print("Downloading has started")


            }
      }
    return image! 
}

Then you see on log if the download has started.