Replace UIBarButtonItem with UIActivityIndicatorView

Updated for Swift 5.2, Xcode 11.4

enter image description here

class ViewController: UIViewController {

    var activityIndicator = UIActivityIndicatorView()
    var refreshBarButton = UIBarButtonItem()
    var activityBarButton = UIBarButtonItem()

    override func viewDidLoad() {
        super.viewDidLoad()

        activityIndicator.sizeToFit()
        activityIndicator.color = self.view.tintColor

        activityBarButton = UIBarButtonItem(customView: activityIndicator)
        refreshBarButton = UIBarButtonItem(barButtonSystemItem: .refresh, target: self, action: #selector(refreshBarButtonPressed))

        showRefreshButton()
    }

    func performNetworkOperation(completion: @escaping()->()) {
        //simulate network operation
        DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
        completion()
        })
    }

    @objc func refreshBarButtonPressed() {

        showActivityIndicator()
        activityIndicator.startAnimating()

        performNetworkOperation {
            self.activityIndicator.stopAnimating()
            self.showRefreshButton()
        }
    }

    func showRefreshButton() {
        self.navigationItem.setRightBarButton(refreshBarButton, animated: true)
    }

    func showActivityIndicator() {
        self.navigationItem.setRightBarButton(activityBarButton, animated: true)
    }
}

Just create two different UIBarButtonItems

One for the activity indicator and another for a normal UIBarButtonItem.

UIActivityIndicatorView * activityView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[activityView sizeToFit];
[activityView setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin)];
UIBarButtonItem *loadingView = [[UIBarButtonItem alloc] initWithCustomView:activityView];
[self.navigationItem setRightBarButtonItem:loadingView];
[loadingView release];
[activityView release];

UIBarButtonItem * normalButton = [[UIBarButtonItem alloc] initWithTitle...];
[self.navigationItem setRightBarButtonItem:normalButton];
[normalButton release];

When you want to switch them, just reassign the rightBarButtonItem to whichever.