Turn sharedLoader function into a normal function
Asked Answered
T

1

1

I have an imageLoader function, that loads the images while the other code keeps running. Now I want that same function to run first, before all the other code keeps running.

This is the function:

//calling the function

    ImageLoader.sharedLoader.imageForUrl(urlstring as String, completionHandler:{(image: UIImage?, url: String) in

        self.productImageView.image = image!

    })

//the function itself

func imageForUrl(urlString: String, completionHandler:(image: UIImage?, url: String) -> ()) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {()in
        var data: NSData? = self.cache.objectForKey(urlString) as? NSData

        if let goodData = data {
            let image = UIImage(data: goodData)
            dispatch_async(dispatch_get_main_queue(), {() in
                completionHandler(image: image, url: urlString)
            })
            return
        }

        var downloadTask: NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!, completionHandler: {(data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
            if (error != nil) {
                completionHandler(image: nil, url: urlString)
                return
            }

            if data != nil {
                let image = UIImage(data: data)
                self.cache.setObject(data, forKey: urlString)
                dispatch_async(dispatch_get_main_queue(), {() in
                    completionHandler(image: image, url: urlString)
                })
                return
            }

        })
        downloadTask.resume()
    })

}

how do I turn this int a normal function that does the same, but in sync

Tommietommy answered 23/6, 2015 at 1:19 Comment(0)
S
2

I just quickly made a function that takes an async function with a handler as a parameter and return the result synchronous, but be aware: Asynchronous methods from API's are like this for a reason, it may take a long time and therefore should be run on a background queue not to block the main queue. Anyways here is the function with an example:

func async(handler: Int -> Void) {
    dispatch_async(dispatch_queue_create("AsyncQueue", DISPATCH_QUEUE_SERIAL)) {

        NSThread.sleepForTimeInterval(1)
        handler(3)
    }
}

func syncFromAsync<R>(async: (handler: R -> Void) -> Void) -> R {
    let group = dispatch_group_create()
    var result : R!

    func handler(r : R) {
        result = r
        dispatch_group_leave(group)
    }

    dispatch_group_enter(group)
    async(handler: handler)
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER)

    return result
}

print(syncFromAsync(async))

Basically you create a dispatch_group and enter it, provide a handler in which you leave this dispatch_group and just wait until the group is left. Swift generics work very nicely with this.

More detail on how it works:

A dispatch group is created, which can be entered or left, we can also wait until a dispatch group is empty by calling dispatch_group_wait.

In my function, The result type is R which is also the type that the handler accepts. I'm declaring a function as my handler which is just like any other handler for an async function, but instead of doing something with the result, it just stores it in the optional result and then gives the signal that the group is left, which will resume our wait command.

So we enter the group, tell the async function to do its thing with the handler, and just wait until it's finished, whereas we know it's finished when the handler is called and the group therefore left.

Socage answered 23/6, 2015 at 2:12 Comment(3)
Looks nice, but how does it work? is the async function being called from the syncfromasync? So I just have to call syncfromasync() and put my imageforUrl() into the async function?Tommietommy
@ssd Yes you can put any async function with one handler parameter in the syncFromAsync function and it will be synchronous. I updated my answet for a better explanationSocage
Perfect! I tested with session.dataTaskWithRequest(...).resume() and it worked like a charm. Saved me a lot of delegate stuff for a simple network connectivity (ping) test.Haye

© 2022 - 2024 — McMap. All rights reserved.