1

Mac OS X 10.11.3 El-Capitan, XCode 7.2.1, Alamofire 3.5.1 via Carthage

Trying to get the most basic Alamofire example I can think of to work. Although a seasoned developer I am new to XCode so I am sure I am just missing something basic. I setup a new project, added Alamofire via Carthage, added a simple get request in main.swift. Code builds and runs, but nothing from my response closure ever gets called. I added the sleep to try and be sure to wait long enough for the closure to get called. I have Little Snitch on and see that my project is calling httpbin.org. I have tried a variety of the response* methods. But closure never runs, what am I missing?

main.swift

import Alamofire

print("Start")
var x : String = "main"

Alamofire.request(.GET, "https://httpbin.org/get")
  .responseString {resp in
    print("in response handler")
    print("response \(resp)")
    x = "response"
}

sleep(90)
print("End \(x)")

Console Output

Start
End main

XCode

xcode screenshot

  • So all your code is in `viewDidLoad` or how are you calling the request? – xoudini Feb 04 '16 at 20:47
  • It is a command line application project in XCode. I just hit Run from XCode and it runs whatever I have in main.swift. At least that is what appears to happen. Console output shows start and end print statements. If I set a breakpoint to something not in the closure and debug, the debugger does stop at that breakpoint. Breakpoint inside the closure never gets triggered. – Padraic Renaghan Feb 04 '16 at 20:51
  • That might be your problem, see [this answer](http://stackoverflow.com/a/631005/5389870). – xoudini Feb 04 '16 at 21:01

3 Answers3

2

I think Alamofire by default calls the response handler in the main queue so if you make the request, sleep and print in the main queue/thread, the responseString is not executed from the main queue before the app terminates. Don't know about .responseString, but with .response you can specify the queue:

public func response<T: ResponseSerializerType>(
        queue queue: dispatch_queue_t? = nil,
        responseSerializer: T,
        completionHandler: Response<T.SerializedObject, T.ErrorObject> -> Void)
        -> Self
Tapani
  • 3,191
  • 1
  • 25
  • 41
  • oh, so my main.swift and the handler are set to run on the same queue and my main.swift effectively blocks the queue so nothing else can run. Ok, that makes sense. So I need to tell Alamofire to put my response handler on a different queue then I guess? If anyone has an examples of Alamofire code doing that I'd be appreciative – Padraic Renaghan Feb 04 '16 at 20:54
  • .response( queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), responseSerializer: Request.stringResponseSerializer(encoding: NSUTF8StringEncoding)) { response in // Print here } – Tapani Feb 04 '16 at 20:57
  • Got it working. Thanks so much @tapani for pointing me in the right direction. For completeness the code in this post is an example of how to get the response handler on a background (non-main) thread http://stackoverflow.com/a/29883233/204396 – Padraic Renaghan Feb 04 '16 at 21:04
1

Not sure why, but running the completion block on another thread didnt work for my command line tool; it still completed before waiting on the callback. I found a really nice alternative at http://mgrebenets.github.io/swift/2015/10/08/async-swift-scripting

This method uses RunLoop to keep the program running until the callback fires.

summary code

var keepAlive = true

Alamofire.request("http://httpbin.org/get", parameters: ["foo": "bar"])
            .response(
    responseSerializer: DataRequest.jsonResponseSerializer()) { response in

        print(response.result.value ?? "")                
        keepAlive = false
    }

let runLoop = RunLoop.current
while keepAlive && runLoop.run(mode: RunLoopMode.defaultRunLoopMode, before: Date(timeIntervalSinceNow: 0.1)) {
    // Run, run, run
}
raf
  • 535
  • 4
  • 18
0

Github repo of working example