I am creating a completionHandler
which returns a Dictionary but when I call this method in another class the value of it is nil.
func fetchLate
Your question is garbled. Your sample code isn't valid, and does not show a completion handler in use.
I suspect you misunderstand how async requests and completion handlers work. Here is the sequence.
Here is a realistic example of how an async process with completion handlers might work: (You can find a working Xcode project that demonstrates this code on Github at this link)
First a class AsyncManager that simulates downloading an image from the internet:
class AsyncManager
{
static let sharedAsyncManager = AsyncManager()
func asyncFetchImage(#imageName: String, completion: (image: UIImage?, status: String) -> ())
{
println("Entering \(__FUNCTION__)")
//Simulate a network operation by waiting 3 seconds before loading an image
let nSecDispatchTime = dispatch_time(DISPATCH_TIME_NOW,
Int64(3.0 * Double(NSEC_PER_SEC)))
let queue = dispatch_get_main_queue()
dispatch_after(nSecDispatchTime, queue)
{
() -> Void in
let result = UIImage(named: imageName)
println("Loading image in background")
let status = result != nil ? "image loaded" : "Error loading image"
println("About to call completion handler")
completion(image: result, status: status)
}
println("Leaving \(__FUNCTION__)")
}
}
It is a singleton. It has a static let sharedAsyncManager that you use to fetch a single instance of the AsyncManager.
The AsyncManager provide a single method, asyncFetchImage, that takes an image name and a completion block. The function doesn't return any result, because it returns immediately, before the image load has taken place.
The code doesn't really download the image from the internet. Instead it simply uses the GCD call dispatch_after to wait 3 seconds before loading an image and invoking the completion block.
Now I create a ViewController class and give it a "Load Image" button. I create an IBOutlet
theImageView
to a UIImageView
that will display the image I'm going to load.
I write an IBAction method for the Load Image button. Here's what that IBAction looks like:
@IBAction func loadImage(sender: UIButton)
{
let theAsyncManager = AsyncManager.sharedAsyncManager
println("about to call asyncFetchImage")
theAsyncManager.asyncFetchImage(imageName: "wareto_blue_150x115")
{
(image, status) -> () in
println("Beginning completion block")
self.theImageView.image = image
println("In completion block, status = \(status)")
}
println("After call to asyncFetchImage")
}
}
Now, the fun part. Here's the sequence of events:
I press the loadImage button. The IBAction method runs.
It gets a reference to the async download manager singleton.
It displays a message, then calls theAsyncManager.asyncFetchImage. The AsyncManager.asyncFetchImage method displays a message on entry, queues up a call to load the image 3 seconds later, displays a "leaving" message, and returns, before the image is loaded. There is nothing to return, because the image loading code hasn't run yet.
The view controller's loadImage method displays it's "After call to asyncFetchImage" message and returns.
A few seconds later, the code inside asyncFetchImage actually runs. It displays a message, loads the image, then invokes the completion handler.
Here is the set of messages you get back when you run the code above:
about to call asyncFetchImage
Entering asyncFetchImage(imageName:completion:)
Leaving asyncFetchImage(imageName:completion:)
After call to asyncFetchImage
Loading image in background
About to call completion handler
Beginning completion block
In completion block, status = image loaded
Note that the last line of the loadImage IBAction:
println("After call to asyncFetchImage")
displays a message before the message about loading an image is displayed. The code call to asyncFetchImage returns immediately, before any work is done. The code after the call to asyncFetchImage runs next, but the image still hasn't loaded. There's no way to return a result at this point, because the image load is hasn't even started yet.