Make sure you perform the time consuming JSON request asynchronously (e.g. using NSURLSession
or equivalent third party library). You must make sure that you do not block the main thread because that will interfere with the activity indicator view.
So if you have code that is doing something equivalent to NSData(contentsOfURL:)
or NSURLConnection.sendSynchronousRequest()
, replace it with NSURLSession
or equivalent third party library).
It might look something like:
func performNetworkRequest(request: NSURLRequest, completionHandler: (String?, ErrorType?) -> ()) {
let spinner = startActivityIndicatorView()
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
defer { self.stopActivityIndicatorView(spinner) }
if successful {
completionHandler(..., nil)
} else {
completionHandler(nil, someError)
}
}
task.resume()
}
func startActivityIndicatorView() -> UIActivityIndicatorView {
let x = (self.view.frame.width / 2)
let y = (self.view.frame.height / 2) - (self.navigationController?.navigationBar.frame.height)!
let activityView = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)
activityView.frame = CGRect(x: 200, y: 120, width: 200, height: 200)
activityView.center = CGPoint(x: x, y: y)
activityView.color = .blueColor()
activityView.startAnimating()
self.view.addSubview(activityView)
return activityView
}
func stopActivityIndicatorView(activityView: UIActivityIndicatorView) {
dispatch_async(dispatch_get_main_queue()) {
activityView.removeFromSuperview()
}
}
And you'd use it like so:
performNetworkRequest(request) { responseObject, error in
}
Now, clearly that first parameter of the completion handler will match whatever what's being returned by your API (I used a String?
but often it would be a dictionary or some other rich structure), but hopefully this illustrates the basic idea: Start activity indicator on main thread, perform the request and parsing asynchronously, and only when the request is done, remove the activity indicator.