1

I have a picker view that has images as it's scrollable items. I need to pull those images from my database so I'm getting the Unexptected non-void return value in void function error. Here is my code:

func pickerView(_ pickerView: AKPickerView, imageForItem item: Int) -> UIImage {
    let imgRef = FIRStorage.storage().reference().child("profile_images").child(pets[item])
    imgRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
        // Create a UIImage, add it to the array
        let pic = UIImage(data: data!)
        return pic
    }
}

So I understand why this doesn't work but I'm having a hard time finding out what's the best way to get around this. One solution I can think of is to just set the images to some generic photo until the callback happens, then update the picker view's image to the retrieved image. However, I don't know how to access individual picker view items in order to update its image.

If anybody with some experience can give me advice on how I can achieve my goal of setting these items to the data from an asynchronous call I'd greatly appreciate it!

AL.
  • 36,815
  • 10
  • 142
  • 281
MarksCode
  • 8,074
  • 15
  • 64
  • 133
  • Since this is an asynchronous function, it's better to use a callback. You can see my answer for more info. – KrishnaCA Jan 13 '17 at 06:06
  • May I know if your problem got resolved or not please? – KrishnaCA Jan 13 '17 at 17:51
  • The question is actually the issue. Trying to return *anything* from an asynchronous call is not the way to do it and goes against the nature of asynchronous functions. Do not use callbacks either as that overcomplicates the code and makes it hard to maintain. The simple solution is to make the call to firebase, which will return the image in the closure. Then append it to an array (assuming your dataSource is an array) then update your picker view. – Jay Jan 13 '17 at 19:02
  • @Jay ok, but how do I access an individual component of the picker view in order to change its image? – MarksCode Jan 13 '17 at 19:10
  • A UIPickerView has both a datasource and delegate which provide the required data to the picker. Typically the actual data for the pickerView is stored in an array, and provided to the view via the delegate calls such as numberOfComponentsInPickerView, numberOfRowsInComponent and titleForRow. The array is well.. an array and you can access the components (indexes) via the index, or a search or a variety of other techniques. In your case, as the images are read in, you add them to the array and once you have an amount read in, reload the pickerView which will pull the data from the dataSource. – Jay Jan 13 '17 at 19:18
  • So basically you suggest giving a dummy image then when all the pictures are loading, reload the data of the picker view? – MarksCode Jan 13 '17 at 19:58
  • No necessarily although that would work.If the images are small - like thumbnails they will load so quickly that it won't really affect your UI. i.e. loop through and load the pics you want, populate the array, display the picker and refresh it. It will be almost instantaneous. If the images are larger then you should provide feedback to the user that items are loading - perhaps a progress bar. I don't know what you use case is but either way, provide the user feedback as to what's going on. – Jay Jan 13 '17 at 22:05

1 Answers1

1

Your function here is an asynchronous function. You have to make use of callbacks in this case. You can rewrite the function in the following way to achieve desired results.

func pickerView(_ pickerView:AKPickerView, imageForeItem item:Int, completion:(_ resultImg: UIImage)->Void) {

    let imgRef = FIRStorage.storage().reference().child("profile_images").child(pets[item])
    imgRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
        // Create a UIImage, add it to the array
        if let pic:UIImage = UIImage(data: data!) {
            completion(pic)
        }
    }
}

This can be called as follows:

self.pickerView(pickerView, imageForeItem: 0) { (image) in
    DispatchQueue.main.async {
      // set resulting image to cell here
    }
}

Feel free to suggest edits to make this better :)

KrishnaCA
  • 5,615
  • 1
  • 21
  • 31