2

I'm not sure why Apple designs so many things in blocks... At least the problem in "PHAsset to UIImage" was able to be resolved due to a provided option. However, some of the other things I need are not provided by options.

For example:

func getAssetUrl(asset: PHAsset) -> NSURL {
    var option = PHContentEditingInputRequestOptions()
    asset.requestContentEditingInputWithOptions(option, completionHandler: {(contentEditingInput, info) -> Void in
            var imageURL = contentEditingInput.fullSizeImageURL
        println(imageURL)
        })
    return NSURL()
}

In these cases, I just want functions that take a block (such as requestContentEditingInputWithOptions to synchronically execute so I can return the imageURL). Is there any way to do this? (I've tried using some dispatch commands, but have not reached success yet).

Please note that I NEED to return the imageURL. Do not attempt to give me a solution in which I write stuff inside the block and don't return the imageURL.

Community
  • 1
  • 1
dcheng
  • 1,673
  • 1
  • 9
  • 19
  • 2
    Why do you need to return the image URL? Why can't use follow well established asynchronous patterns (e.g. add a `completion` closure that is called when you have the URL)? Yes, you can use semaphores to make an asynchronous method behave synchronously, but it's generally a horrible idea. They made this method is asynchronous for a reason. It's super easy to follow asynchronous patterns, and use `completion` closures. So why not do that?!? – Rob Jun 15 '15 at 18:45
  • 1
    I need to pass the URL into a preexisting function that takes just a URL. I guess I could use a completionHandler you wrote below, but I'm not sure if future functions will take the URL and additional parameters. If possible, can you show how to use semaphores? I am unable to do this correctly. – dcheng Jun 15 '15 at 19:28
  • 2
    Just put the function that takes the URL parameter and call it from inside the closure. Its the correct way to handle this. Making this behave synchronously can result in horrible UX and having the watchdog process kill your app if you do this at the wrong time. – Rob Jun 15 '15 at 19:33
  • Still confused. Say I have the following functions: A. printNSUrlAsString(NSUrl) B. relocateNSUrlToLocation(NSUrl, destination) C. getFile(NSUrl) If I put all the following inside the closure, then I might be relocating when I just want to get the file? Also I am unsure why fetching a URL of a file needs to be handles asyncly... Maybe I'm not using the correct method to fetch the URL? – dcheng Jun 15 '15 at 19:39
  • 1
    Photos is async because you're can't assume that the resource is local. Regardless of the reason why, we can always be confident it's not async just to be difficult, but rather for a pretty good reason. We use async patterns all over the place, so you might as well just get comfortable with them. Back to your example, if relo was async method, then you'd have it use the `completionHandler` closure pattern itself, and then nest them. If you have concrete example where asyn patterns feel hard, edit your question giving us a real-world scenario, and we can show you how to address it. – Rob Jun 15 '15 at 20:15

1 Answers1

3

I know you explicitly asked not to see this answer, but for the sake of future readers, I feel compelled to post the correct way to handle asynchronous methods, namely follow asynchronous patterns yourself and employ a completionHandler:

func getAssetUrl(asset: PHAsset, completionHandler: @escaping (URL?) -> Void) {
    let option = PHContentEditingInputRequestOptions()
    asset.requestContentEditingInput(with: option) { contentEditingInput, _ in
        completionHandler(contentEditingInput?.fullSizeImageURL)
    }
}

And you'd use it like so:

getAssetUrl(asset) { url in
    guard let url = url else { return }

    // do something with URL here
}

// anything that was here that needs URL now goes above, inside the `completionHandler` closure

There are other, more complicated patterns (operations, third-party promises/futures implementations, etc.), but the completionHandler pattern generally handles these situations quite gracefully.

Rob
  • 371,891
  • 67
  • 713
  • 902
  • Read the comment in the OP. I'm not sure how to elegantly use completionHandlers to guarantee future functions will be able to work. – dcheng Jun 15 '15 at 19:31