Modal Windows with AFNetworking
If you're presenting a modal window on macOS and attempt to make network requests with AFNetworking, you might be surprised when those requests vanish into thin air. No timeouts, no errors - no result at all.
It can be easy to overlook the fact that methods like NSApplication -runModalForWindow: do not return until the modal session ends, and essentially freeze the main serial queue of Grand Central Dispatch (now simply 'Dispatch') in its tracks.
This is important when using libraries like AFNetworking which, by default, dispatch_async completion blocks to the main queue. The end result is that these blocks pile up but are unable to execute while your modal window is open. You won't receive any failures, errors, or responses - they're all stuck, waiting on your window to finish.
for your manager's requests. Your network completion blocks will then execute on a concurrent background queue without any problems.
Bear in mind the thread safety implications of this. If you need to update UI or perform mainthread-only work from these blocks, you can leverage -performSelectorOnMainThread: which doesn't rely on the main queue and works as expected even when a modal loop is running.
For libraries other than AFNetworking, the solution will depend on the API architecture. In general, however, anything that dispatches to the main queue will be impacted by your modal window and will require some accommodation if you expect it to work normally.
It can be easy to overlook the fact that methods like NSApplication -runModalForWindow: do not return until the modal session ends, and essentially freeze the main serial queue of Grand Central Dispatch (now simply 'Dispatch') in its tracks.
This is important when using libraries like AFNetworking which, by default, dispatch_async completion blocks to the main queue. The end result is that these blocks pile up but are unable to execute while your modal window is open. You won't receive any failures, errors, or responses - they're all stuck, waiting on your window to finish.
Solution
For AFNetworking, you can override or set -completionQueue to a background queue:
manager.completionQueue = dispatch_get_global_queue(DISPATCH_PRIORITY_DEFAULT, 0)
Or DispatchQueue.global() in Swift
Or DispatchQueue.global() in Swift
for your manager's requests. Your network completion blocks will then execute on a concurrent background queue without any problems.
Bear in mind the thread safety implications of this. If you need to update UI or perform mainthread-only work from these blocks, you can leverage -performSelectorOnMainThread: which doesn't rely on the main queue and works as expected even when a modal loop is running.
For libraries other than AFNetworking, the solution will depend on the API architecture. In general, however, anything that dispatches to the main queue will be impacted by your modal window and will require some accommodation if you expect it to work normally.