1
votes

I have a UIPopoverController that I am loading with a ViewController to hold a UIWebView. When I press a button to present the Popover, the webpage loads fine. I can dismiss the Popover just as fine as well. When I press a button to present the Popover again, the UIWebView reloads. Is there a way to maintain/persist the state of the WebView in the ViewController so that the content remains the same when the popover is presented/dismissed?

Maybe another question is, when a Popover is dismissed, is my ViewController wiped? I don't believe it should be because it isn't a local variable, but I'm not so sure if I have a misunderstaing of how UIPopoverController's behave.

Relevant code below:

In my main ViewController:

_popoverMenuVC  = [[TBPopoverMenuViewController alloc] init];
_popoverMenuVC.delegate = self;
_popoverMenuVC.contentSizeForViewInPopover = CGSizeMake(300, 300*(1+sqrt(5)/2.));
_popoverCtr = [[UIPopoverController alloc] initWithContentViewController:_popoverMenuVC];

Code for my button:

- (void)menuBtnPressed:(id)sender
{
if (IS_IPAD) {
    UIButton *btn = (UIButton*)sender;
    if (!_popoverCtr.isPopoverVisible) {


        //set url for popover webview
        _popoverMenuVC.popoverURL = @"http://www.google.com";

        // show popover
        [_popoverCtr setPopoverContentSize:CGSizeMake(300, 300*(1+sqrt(5)/2.))];
        [_popoverCtr presentPopoverFromRect:btn.frame
                                     inView:self.view
                   permittedArrowDirections:UIPopoverArrowDirectionDown
                                   animated:YES];
    } else {


        // hide popover
        [_popoverCtr dismissPopoverAnimated:YES];
    }
}

Code for my popoverMenuVC:

-(void) viewDidAppear:(BOOL)animated{
[self setupUIs];
}

- (void)setupUIs
{
//  webview
wv = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 300, 300*(1+sqrt(5)/2.))];

//activity indicator
self.activityIndicator = [[UIActivityIndicatorView alloc]      initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
self.activityIndicator.frame = CGRectMake(0.0, 0.0, 40, 40);
self.activityIndicator.center = self.view.center;

// darkview for activity indicator
self.darkView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,300, 300*(1+sqrt(5)/2.))];
[self.darkView setBackgroundColor:[UIColor blackColor]];
[self.darkView setAlpha:0.4];

wv.delegate = self;
wv.scalesPageToFit = YES;
wv.scrollView.bounces = NO; //get rid of bounce for popover menu

[self.view addSubview:wv];

}

A few delegates for handing activity indicator:

#pragma mark Activity Indicator

- (void) showLoadingIndicator
{
[self.view insertSubview:self.darkView aboveSubview:self.view];
[self.view insertSubview:self.activityIndicator aboveSubview:self.darkView];
[self.activityIndicator startAnimating];
}

- (void) hideLoadingIndicator
{
[self.activityIndicator stopAnimating];
[self.activityIndicator removeFromSuperview];
[self.darkView removeFromSuperview];
}

#pragma mark UIWebView Delegates

-(void)webViewDidStartLoad:(UIWebView *)webView{
NSLog(@"Webview is starting to load");
[self showLoadingIndicator];
}

-(void)webViewDidFinishLoad:(UIWebView *)webView{
NSLog(@"request: %@", [[webView request] description]);
if(!webView.loading){
    NSLog(@"Webview has finished loading");
    [self hideLoadingIndicator];
}
}

I have a very similar implementation of this working for iPhone, without the Popover obviously, just with ViewControllers and it seems to work fine. Wondering if this has to work with the PopoverController itself...

Thanks for any help!

Edit 1:

I moved the following code to my main ViewController:

_popoverMenuVC  = [[TBPopoverMenuViewController alloc] init];
_popoverMenuVC.wv = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 300, 300*(1+sqrt(5)/2.))];
_popoverMenuVC.wv.scalesPageToFit = YES;
_popoverMenuVC.wv.scrollView.bounces = NO; //get rid of bounce for popover menu
_popoverMenuVC.req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]];
_popoverCtr = [[UIPopoverController alloc] initWithContentViewController:_popoverMenuVC];

I have nothing in my viewDidAppear function anymore, I now moved it to viewDidLoad:

- (void)viewDidLoad
{
[super viewDidLoad];
wv.delegate = self;
[wv loadRequest:req];
[self.view addSubview:wv];
}

But the WebView doesn't load anymore (which I think is related to this issue: iOS 7 UIWebView doesn't load webpage)

Moving the above code from ViewDidLoad to viewDidAppear will load my WebView, yet the same reloading problem persists.

Any additional help would be appreciated!

Edit 2:

I did some code refactoring in order to focus in on what might be causing this behavior:

In my main ViewController, I am setting up my PopoverViewController, along with its WebView, and setting it to be the init content for our UIPopoverController:

_popoverMenuVC  = [[TBPopoverMenuViewController alloc] init];
_popoverMenuVC.wv = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 300, 300*(1+sqrt(5)/2.))];        
_popoverMenuVC.wv.scalesPageToFit = YES;
_popoverMenuVC.wv.scrollView.bounces = NO; //get rid of bounce for popover menu
_popoverMenuVC.req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]];
[_popoverMenuVC.view addSubview:_popoverMenuVC.wv];
_popoverCtr = [[UIPopoverController alloc] initWithContentViewController:_popoverMenuVC];

All of this is happening once outside of my TBPopoverMenuViewController's code.

In my TBPopoverMenuViewController.h, I set up a property for wv and req.

In my TBPopoverMenuViewController.m, I synthesize my wv, but not my req.

Here is my viewDidLoad, where I set the wv's delegate to self.

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view setBackgroundColor:[UIColor whiteColor]];
wv.delegate = self;
//    [wv loadRequest:_req];

}

And in viewDidAppear, this is where I load my request.

-(void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:NO];
[self setupActivityIndicator];
[wv loadRequest:_req];
}

Trying to load my request anywhere else, in view did load, or even in the main ViewController, it doesn't load the request in the popover. It only seems to want to happen in the viewDidAppear function.

Further, when I try to load the popover the second time, you can see the previous wv with the page loaded where it was before, but then almost immediately after the request seems to reload on top of that webview.

Does anyone have a solution? How can I maintain my webview when the popover dismisses and is re-presented. This seems to work fine on iPhone in a non-popover implementation, making me think that there is something I'm missing for iPad/iOS7/UIPopoverControllers.

Any help would be appreciated!

Edit 3:

After some debugging with Xcode's Instruments tool, I've realized that calling:

[wv loadRequest:_req];

In the viewDidAppear of my ViewController results in a memory leak! So there seems to be something essential in my problem with the UIWebView reloading and where/how I'm loading my request. As I've mentioned before, I've tried calling loadRequest outside of my Popover's ViewController in my main View Controller, with no luck. I also tried to call loadRequest in viewDidLoad, with no luck as well.

I was able to successfully call loadRequest in my menuBtnPressed function after the popover is presented:

- (void)menuBtnPressed:(id)sender
{
if (IS_IPAD) {
    popOverBtn = (UIButton*)sender;
    if (!_popoverCtr.isPopoverVisible) {

        [_popoverCtr setPopoverContentSize:CGSizeMake(300, 300*(1+sqrt(5)/2.))];   
        [_popoverCtr presentPopoverFromRect:popOverBtn.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
        [_popoverMenuVC.wv loadRequest:_popoverMenuVC.request];

    } else {
        // hide popover
        [_popoverCtr dismissPopoverAnimated:YES];
    }

Which boils down to the two places I can actually successfully call loadRequest for the UIWebView in my popover are:

-in viewDidApepar in the ViewController

-after presenting my popover with a button press

Both of these seem to still result in a memory leak according to Xcode's Instruments tools. I still can't get my UIWebView to maintain/persist state when going back from presenting -> dismissing -> re-presenting the popover.

Any suggestions?

2

2 Answers

1
votes

The viewDidAppear method of the popover is called every time the present is done.

So every time the popover is presented, the current code adds a new UIWebView which goes to the default url (with all the previous web views from the previous presents underneath).

A couple of changes should give you the behavior you want:

  1. In the popover content view controller, move the call to setupUIs from viewDidAppear to viewDidLoad.
  2. In the main view controller, move the setting of popoverURL to where the popover content view controller is first created (right after you alloc+init it).
0
votes

It turns out the answer to my problem as to...call loadRequest twice.

//setup popover menu vc
    _popoverMenuVC  = [[TBPopoverMenuViewController alloc] init];
    _popoverMenuVC.wv = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 300, 300*(1+sqrt(5)/2.))];
    _popoverMenuVC.delegate = self;
    _popoverMenuVC.wv.scalesPageToFit = YES;
    _popoverMenuVC.wv.scrollView.bounces = NO; //get rid of bounce for popover menu
    _popoverMenuVC.request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com/"]];
    [_popoverMenuVC.wv loadRequest:_popoverMenuVC.request]; //first request
    [_popoverMenuVC.view addSubview:_popoverMenuVC.wv];
    _popoverCtr = [[UIPopoverController alloc] initWithContentViewController:_popoverMenuVC];
    [_popoverMenuVC.wv loadRequest:_popoverMenuVC.request]; // second request

This results in the behavior I want. The UIWebView loads in the PopoverViewController with the page loaded, and when I present-> dismiss-> re-present the popover, the page UIWebView is where I left it. I have no idea why this works though, it seems like a bug or a hack, having to call the function twice. The loadRequest also seems to result in a memory leak according to the Instruments toolset in Xcode.

So I solved my problem, but I'm still a bit confused as to why this is the solution. Luckily I stumbled onto it...

Any clarification by anyone more experienced would be appreciated!