Search code examples
objective-cuinavigationcontrollerinitializationswiftuinavigationitem

Conversion of custom init routines in Swift


I need to subclass SVModalWebViewController.m (GitHub), which is itself a subclass of UINavigationController, and am incorporating this code into a new app that will be created entirely in Swift. I've run into several issues, so I decided to first convert just this very simple class into Swift to debug.

Initialization is a little different in Swift compared with Objective-C (read more about Swift initialization here), which is why I'm not returning self in the Swift code.

Here's the original Obj-C code (minus the *.h, which instantiates barsTintColor):

#import "SVModalWebViewController.h"
#import "SVWebViewController.h"

@interface SVModalWebViewController ()

@property (nonatomic, strong) SVWebViewController *webViewController;

@end


@implementation SVModalWebViewController

#pragma mark - Initialization


- (id)initWithAddress:(NSString*)urlString {
    return [self initWithURL:[NSURL URLWithString:urlString]];
}

- (id)initWithURL:(NSURL *)URL {
    self.webViewController = [[SVWebViewController alloc] initWithURL:URL];
    if (self = [super initWithRootViewController:self.webViewController]) {
        UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
                                                                                    target:self.webViewController
                                                                                    action:@selector(doneButtonClicked:)];

        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
            self.webViewController.navigationItem.leftBarButtonItem = doneButton;
        else
            self.webViewController.navigationItem.rightBarButtonItem = doneButton;
    }
    return self;
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:NO];

    self.webViewController.title = self.title;
    self.navigationBar.tintColor = self.barsTintColor;
}

@end

And here's the entire Swift version of the class (I simplified to just one init method since I didn't need to init with URL specifically):

import UIKit

class SVModalWebViewController: UINavigationController {
    var webViewController: SVWebViewController!
    var barsTintColor: UIColor?

    // This was added because of a compiler error indicating it needed to be added
    init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    init(address urlString: String!) {
        let url: NSURL = NSURL.URLWithString(urlString)
        self.webViewController = SVWebViewController(URL: url)
        super.init(rootViewController: self.webViewController)

        let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self.webViewController, action: Selector("doneButtonClicked:"))

        if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
            self.navigationItem.leftBarButtonItem = doneButton
        } else {
            self.navigationItem.rightBarButtonItem = doneButton
        }
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        // self.title may not be set, and is considered an optional in Swift, so we have to check first
        if self.title {self.webViewController.title = self.title}
        self.navigationBar.tintColor = self.barsTintColor
    }
}

The issue I'm having relates to setting the Done button in the navigationItem. Currently they're not showing up at all when this code is called:

let webViewController = SVModalWebViewController(address: "http://www.google.com");
webViewController.barsTintColor = UIColor.blueColor()
self.presentModalViewController(webViewController, animated: true)

The modal view appears just fine and I'm able to correctly set the bar color property, but the Done button does not show up. It appears that I don't have proper access to the navigationItem of the UINavigationController. Note that I had to add the init with nibName method due to a compiler error without it. This wasn't required in the Obj-C code and I'll admit I'm not sure why it's needed in Swift - that could be part of the issue.

Any thoughts as to why I cannot set the self.navigationItem.leftBarButtonItem property of the UINavigationController? Thanks!


Solution

  • A UINavigationController does not have a navigationItem. Well, it does, but it's useless. It is the navigationItem of the child controller (in this case, the rootViewController, which you are also calling self.webViewController) that appears in the navigation bar.