iphone - programmatically change navigation bar button to activity indicator

岁酱吖の 提交于 2019-12-21 06:05:32

问题


I have added a refresh UIBarButtonItem to my navigation bar on my iPhone app. When the user taps the button I'd like the refresh button to change to the animated activity indicator and once the operation (in this case a download) is complete switch the activity indicator back to the refresh button.

I have added the refresh button using IB. Then on the button tap I create a new activity indicator and keep an pointer to the original refresh button. Like so:

refreshButtonItem = self.navigationItem.leftBarButtonItem;
if (activityButtonItem == nil)
{
    activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20,20)];
    activityButtonItem = [[UIBarButtonItem alloc]initWithCustomView:activityIndicator];

}
self.navigationItem.leftBarButtonItem = activityButtonItem;
[activityIndicator startAnimating];

So far, so good. Problem is that when my download finishes and I try to re-add the refresh button (using the following):

[activityIndicator stopAnimating];
self.navigationItem.leftBarButtonItem = refreshButtonItem;

I get the following error:
[UIBarButtonItem retain]: message sent to deallocated instance

I'm not explicitly calling release.

A) When/where is this being deallocated

B) Is there a better way to achieve what I'm looking for?


回答1:


When you assign the activityButtonItem to leftBarButtonItem, the item that leftBarButtonItem used to point to is released. The leftBarButtonItem (and all properties with the retain option) are implemented similarly to this:

- (void)leftBarButtonItem:(UIBarButtonItem *)newItem {
  if (newItem != self.leftBarButtonItem) {
    [self.leftBarButtonItem release];
    leftBarButtonItem = [newItem retain];
  }
}

If you want to use the refreshButtonItem after reassigning the leftBarButtonItem, change your first line to:

refreshButtonItem = [self.navigationItem.leftBarButtonItem retain];




回答2:


Since iOS 5 with the introduction of ARC you no longer need to do retain.

Solution can be obtained as @cagreen explained while refreshButtonItem can be stored as class property, as well as loadingButton and loadingView.

In your interface declare:

@property (strong, nonatomic) UIBarButtonItem *refreshButton;
@property (strong, nonatomic) UIBarButtonItem *loadingButton;
@property (strong, nonatomic) UIActivityIndicatorView *loadingView;

Init loadingButton and loadingView in your viewDidLoad method:

self.loadingView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
self.loadingButton = [[UIBarButtonItem alloc] initWithCustomView:self.loadingView];

Then to show the loading spinner you can simply do:

 // Shows loading button
- (void)showLoadingView {

    // Keep reference to right bar button
    if (self.navigationItem.rightBarButtonItem) {
        self.refreshButton = self.navigationItem.rightBarButtonItem;
    }

    // Start animating and assign loading button to right bar button
    [self.loadingView startAnimating];
    self.navigationItem.rightBarButtonItem = self.loadingButton;
}

And to hide:

 // Hides loading button
- (void)hideLoadingView {
    [self.loadingView stopAnimating];
    self.navigationItem.rightBarButtonItem = self.refreshButton;
}


来源:https://stackoverflow.com/questions/2249363/iphone-programmatically-change-navigation-bar-button-to-activity-indicator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!