Query Regarding WebViewController Implementation


#1

I have a query regarding the implementation of WebViewController.

In the header file we create the following property for a UIWebView:

I know we need to do this so that ListViewController can set it’s content when it is pushing it onto the navigation stack.

What I don’t understand is why, in the init: method of the implementation do we create a new UIWebView instance:

instead of using our property:

which works perfectly?

Maybe I am missing something here :blush:

Thanks,
Nick
http://myfirstiphoneapp.co.uk
http://easyintervalsapp.co.uk


#2

In fact, you can’t simply write

because the property webView is not synthesized in WebViewController.m, therefore neither a webView instance variable nor a webView getter method are generated to support this readonly property. The reasoning behind the peculiar treatment of the webView property is interesting – if I grasped it correctly when studying chapter 25, of course.

This is the explanation I ended up with. WebViewController already has a reference to the UIWebView in its view instance variable – and WebViewController’s explicit webView getter method does use that to return the view (with a convenient cast from UIView to UIWebView). A webView instance variable would then be a cumbersome double of WebViewController’s inherited view property.

Most importantly, a second (strong) reference to the view would make it impossible for the system to sweep it from memory in case of a low memory warning (checked with Instruments). The view variable is set to nil when a low memory warning occurs, but our webView variable is not, so the web view remains alive – at least until the next time we select a row in the master table view and a new web view is allocated.

An alternative to the approach taken in the text could be making webView a weak property, synthesizing it in WebViewController.m (no need to implement an explicit getter method for it in this case) and assigning to it with care:

[code]@interface WebViewController : UIViewController

@property (nonatomic, weak, readonly) UIWebView *webView;

@end[/code]

[code]@implementation WebViewController

@synthesize webView;

  • (void)loadView
    {
    CGRect screenFrame = [[UIScreen mainScreen] applicationFrame];

    UIWebView *wv = [[UIWebView alloc] initWithFrame:screenFrame];
    webView = wv;

    [webview setScalesPageToFit:YES];

    [self setView:webView];
    }

@end[/code]

In loadView we can’t write

because webView, at that moment, is the only reference to the newly created object, but it is weak, so the object is immediately destroyed. We must put up a strong reference (wv) before assigning to webView, in order to maintain the UIWebView alive for the duration of the method. At the end of the method, the WebViewController takes ownership of the UIWebView with its view instance variable.


#3

Thanks for your explanation Alberto however:

yet, a readonly property does have a getter method as it is readonly, and in fact I believe we actually override this be implementing our own getter method for it:

- (UIWebView *)webView { return (UIWebView *)[self view]; }

What is confusing me (and I don’t know why), is that if I synthesise the webView property, then change the loadView: method to be:

[code]- (void)loadView
{
CGRect screenFrame = [[UIScreen mainScreen] applicationFrame];
webView = [[UIWebView alloc] initWithFrame:screenFrame];

[webView setScalesPageToFit:YES];

[self setView:webView];

}[/code]
it works fine. I also ran it through instruments using my iPhone, and there appeared to be no problems.

Nick
http://myfirstiphoneapp.co.uk
http://easyintervalsapp.co.uk


#4

Ciao fujilla. Let me re-state the first point of my previous post, the one you quote. If you don’t synthesize the webView property, you have neither a webView instance variable nor a webView accessor method. Try for yourself. Comment out all the original code for WebViewController.m and enter the following instead:

[code]#import “WebViewController.h”

@implementation WebViewController

  • (void)loadView
    {
    CGRect screenFrame = [[UIScreen mainScreen] applicationFrame];
    webView = [[UIWebView alloc] initWithFrame:screenFrame];
    [webView setScalesPageToFit:YES];
    [self setView:webView];
    }

@end[/code]

Here we are trying to use the webView instance variable (without synthesizing the property) and are not providing an explicit implementation of the webView method. You will see three errors and a warning, lamenting that neither the former nor the latter do in fact exist. When we implement the webView method, we are defining, not overriding it. Let’s double check this. Revert to the original code of WebViewController.m, and simply comment out the implementation of the webView method. If you run the project, it will crash as soon as you select a row in the master table view, because the non-existent webView method is called in tableView:didSelectRowAtIndexPath:.

If you modify the code in the box above and synthesize webView, the errors and the warning disappear and the project runs without a hitch, because now both the variable and the method are properly generated. The code, as you say, works fine, except that you now have two strong references to the UIWebView (our webView and the inherited view instance variable). Only one of them (view) is set to nil for you in case of a low memory warning, so you incur in the memory problem described in my previous post.


#5

Yes, I do know that if you “don’t” synthesise the webView property, you cannot access it in the implementation file.

This is why I said

The reason I quoted you is that you say webView does not have a getter if it is not synthesised, yet this is not the case.


#6

Quousque tandem, fujilla, abutere patientia nostra? Quamvis repetita non semper iuvare pervicacia tua aperte demonstras, tamen paterna indulgentia tempus nostrum in hac re denuo libenter consumemus. Tertium, utinam postremum!, hoc tibi dicimus: sine proprietatis synthesi compilator methodos non emittit ad eam legendam et mutandam aptos. Plane nobis videris ea argumenta non satis accurate recensuisse quae in secunda nostra epistula liberaliter enumeravimus. Quod si proprietatis synthesin non facimus nec ipsi methodos comparamus, illi vero ut praedicas in codice occulte sublatitant, quis, quaesumus, eos furtim scribit? Thomae Amoris avi nostri veneranda manus?

This in case you understand my latin better than my english (which is a possibility, given the poor state of the latter). In further posts I will try other languages, dead and alive, if necessary :wink:

Anyway, this thing about accessory methods is a side problem. The main question is why synthesizing webView (as a strong reference) is not an ideal solution, even if it seems to work.