Reputation: 75
Im having an issue, I am trying to create a method which accepts a PFObject as a parameter. The PFObject in this case is the facebook picture URL. The method takes the URL and basically converts it into an image. I can get it to work if i just use this block of code without trying to make it into a method, however I would like to create a method out of this so that I dont have to keep repeating myself. When i try to return the users image i keep getting the error cannot convert the expressions type UIImage to type void swift
Here is the code
func downloadFBUserImage(object: PFObject?) -> UIImage? {
var userProfilePhotoURLString = object?.valueForKey("pictureURL") as String?
if userProfilePhotoURLString != nil {
var pictureURL: NSURL = NSURL(string: userProfilePhotoURLString!)!
var urlRequest: NSURLRequest = NSURLRequest(URL: pictureURL)
NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue(), completionHandler: { (NSURLResponse response, NSData data, NSError error) -> Void in
if error == nil && data != nil {
var userProfilePic: UIImage? = UIImage(data: data)
return userProfilePic
}
})
return nil
}
Upvotes: 1
Views: 2152
Reputation: 437452
The error is reporting that the completionHandler
of the sendAsynchronousRequest
is defined to pass you the response
, data
, and error
objects, but that it expects that completionHandler
, itself, to not return any values. But you're trying to return a value from within that completionHandler
closure.
Bottom line, you cannot simply return the UIImage
from your function, because you are performing asynchronous method (i.e. the data is returned later even though you return from the function immediately). So, employ asynchronous pattern:
func downloadFBUserImage(object: PFObject?, completionHandler: (UIImage?, NSError?) -> Void) {
if let userProfilePhotoURLString = object?.valueForKey("pictureURL") as? String {
let pictureURL = NSURL(string: userProfilePhotoURLString)!
let urlRequest = NSURLRequest(URL: pictureURL)
NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue()) { (response, data, error) -> Void in
if data != nil {
var userProfilePic = UIImage(data: data)
completionHandler(userProfilePic, nil)
} else {
completionHandler(nil, error)
}
}
}
}
And you'd call it using the same completion handler pattern that sendAsynchronousRequest
does:
downloadFBUserImage(object) { image, error in
if image == nil {
println(error)
} else {
// use the image here
}
}
// but don't try to use asynchronously retrieved image here
Upvotes: 1
Reputation: 24572
You cannot return to the completion block like that. The completion block does not have a return parameter. This is why you are getting an error.
For updating the image after download, you can pass in a block along with your downloadFBUserImage
function like below.
I used dispatch_async
because UI updates have to be done on the main thread.
func downloadFBUserImage(object: PFObject?, completion completionBlock:(UIImage) -> ()) -> (){
var userProfilePhotoURLString = object?.valueForKey("pictureURL") as String?
if userProfilePhotoURLString != nil {
var pictureURL: NSURL = NSURL(string: userProfilePhotoURLString!)!
var urlRequest: NSURLRequest = NSURLRequest(URL: pictureURL)
NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue(), completionHandler: { (NSURLResponse response, NSData data, NSError error) -> Void in
if error == nil && data != nil {
if let userProfilePic = UIImage(data: data) {
completionBlock(userProfilePic)
}
}
})
}
}
It can be called like this
func do() {
downloadFBUserImage(pfObject, completion: { (image) -> () in
//updateImage
dispatch_async(dispatch_get_main_queue(), { () -> Void in
// UI updates
}
})
}
Upvotes: 0