Lew
Lew

Reputation: 1461

How UIViewControllers created - by alloc/init vs. performSegueWithIdentifier

My iOS 8 project uses a Storyboard, wherein I have a UINavigationController, with a root UIViewController; let's call this A. I also have another UIViewController, connected via a Segue to this root controller; let's call this B. Pretty standard configuration.

Now, A is a subclassed UITableViewController, and in the table I have a list of URLs. The app user taps a table cell, the URL is extracted and passed to B. B is a subclassed UIViewController that contains a WKWebView.

Now, because B is on the UINavigationController's stack, users can tap the Back button while in B, returning to the table with the URLs (A). The user can then tap another cell, to load another URL.

Because I need to pass some data (the URL) to B, I'm invoking it with performSegueWithIdentifier, and in the corresponding prepareForSegue, I assign the URL to a property in B.

This all works fine. My questions reflect my still-nOOb status with respect to iOS and Objective-C.

The first question, when B is created via the performSegueWithIdentifier / prepareForSegue combo, when the user taps the Back button, is this controller deallocated by the OS? In other words, there's no longer an instance of this subclassed UIViewController floating around?

If it is, then presumably it's safe to have a new instance of it created if the user taps a table cell to view another URL. In other words, repeating the call to performSegueWithIdentifier, assigning the newly chosen URL in B's property, etc. Is it safe?

Or, if it's not deallocated automatically, then does repeating the call to performSegueWithIdentifier, etc. just keep creating more and more instances of B?

And, in either case, does it make sense to, when B is first created, capture a reference to it, and keep re-using it? In other words, before calling performSegueWithIdentifier, check if a reference to B already exists, and if it does, do a pushViewController with that reference to B?

So the basic question boils down to this: In a situation where a UIViewController needs to be made visible many times - through a user action - is an instance being newly created every time it's needed? If it is, then does this also imply that every instance is also being deallocated internally when it's no longer needed? And therefore I don't need to worry about the internals?

Or, if I keep using performSegueWithIdentifier every time, am I just creating a pile of new instances of the controller, and thus being wasteful and inefficient, when I could just capture a reference to the first new instance and keep re-using it?

I've tried to step through this process in the debugger and keep track of references, but I'm unsure whether I'm seeing what I should be seeing, and so I'm asking more knowledgeable developers.

Thank you for reading through this long question, and for your time in answering it.

Upvotes: 0

Views: 73

Answers (1)

andykkt
andykkt

Reputation: 1706

First of all, when you push view and pop view and if you are not retaining that view controller anywhere else then it will be released completely and it doesn't really matter how many time you call performSegueWithIdentifier to create this view if you are not retaining it or manage it reference well enough. However, in this case, I would create your 'B' view controller once using

 self.bController = [self.storyboard instantiateViewControllerWithIdentifier:@"BController"];

And then you call pushViewController using self.bController, function would be looking something like this..

- (void)presentURL:(NSString*)url
{
    if ( self.bController == nil ) {
        self.bController = [self.storyboard instantiateViewControllerWithIdentifier:@"BController"];
    }

    [self.bController setURL:url];

    [viewController.navigationController pushViewController:self.bController animated:YES];
}

And refresh the WKWebView with below code when it sets the URL

-(void)setUrlString:(NSString *)urlString {
    // set url string
    _urlString = urlString;

    // clear
    [self.webView loadHTMLString:@"" baseURL:nil];

    // load url with string
    if( _urlString != nil ) {
        // get address for hosting view
        NSURL* url = [NSURL URLWithString:_urlString];
        NSURLRequest* urlRequest = [NSURLRequest requestWithURL:url];
        [self.webView loadRequest:urlRequest];
    }
}

it will make bit simpler than prepareForSegue, however, again, repeating the call to performSegueWithIdentifier, assigning the newly chosen URL in B's property, etc. It is totally safe as long as you don't retaining anywhere else.. but performance wise it might be bit expensive than keeping one instance of B viewController and showing it multiple time because it has to read and initiate the view controller and the WKWebView instance so arguably it is bit expansive..

Upvotes: 1

Related Questions