UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Choosing a website: UIAlertController action sheets

We're going to lock this app down so that it opens websites selected by the user. The first step to doing this is to give the user the option to choose from one of our selected websites, and that means adding a button to the navigation bar.

Somewhere in viewDidLoad() (but always after it has called super.viewDidLoad()), add this:

navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Open", style: .plain, target: self, action: #selector(openTapped))

We did exactly this in the previous project, except here we're using a custom title for our bar button rather than a system icon. It’s going to call the openTapped() method when the button is tapped, so let's add that now. Put this method below viewDidLoad():

@objc func openTapped() {
    let ac = UIAlertController(title: "Open page…", message: nil, preferredStyle: .actionSheet)
    ac.addAction(UIAlertAction(title: "apple.com", style: .default, handler: openPage))
    ac.addAction(UIAlertAction(title: "hackingwithswift.com", style: .default, handler: openPage))
    ac.addAction(UIAlertAction(title: "Cancel", style: .cancel))
    ac.popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
    present(ac, animated: true)
}

We haven’t written the openPage() method yet, so ignore any warnings you see about it for the time being. Just like in project 3 we’re calling openTapped() from Apple’s own Objective-C code in UIBarButtonItem, so the method must be marked @objc.

Just like in project 3, setting the alert controller’s popoverPresentationController?.barButtonItem property is used only on iPad, and tells iOS where it should make the action sheet be anchored.

We used the UIAlertController class in project 2, but here it's slightly different for three reason:

  1. We're using nil for the message, because this alert doesn't need one.
  2. We're using the preferredStyle of .actionSheet because we're prompting the user for more information.
  3. We're adding a dedicated Cancel button using style .cancel. It doesn’t provide a handler parameter, which means iOS will just dismiss the alert controller if it’s tapped.

Both our website buttons point to the openPage() method, which, again, doesn't exist yet. This is going to be very similar to how we loaded the web page before, but now you will at least see why the handler method of UIAlertAction takes a parameter telling you which action was selected!

Add this method directly beneath the openTapped() method you just made:

func openPage(action: UIAlertAction) {
    let url = URL(string: "https://" + action.title!)!
    webView.load(URLRequest(url: url))
}

This method takes one parameter, which is the UIAlertAction object that was selected by the user. Obviously it won't be called if Cancel was tapped, because that had a nil handler rather than openPage.

What the method does is use the title property of the action (apple.com, hackingwithswift.com), put "https://" in front of it to satisfy App Transport Security, then construct a URL out of it. It then wraps that inside an URLRequest, and gives it to the web view to load. All you need to do is make sure the websites in the UIAlertController are correct, and this method will load anything.

You can go ahead and test the app now, but there's one small change we can add to make the whole experience more pleasant: setting the title in the navigation bar. Now, we are the web view's navigation delegate, which means we will be told when any interesting navigation happens, such as when the web page has finished loading. We're going to use this to set the navigation bar title.

As soon as we told Swift that our ViewController class conformed to the WKNavigationDelegate protocol, Xcode updated its code completion system to support all the WKNavigationDelegate methods that can be called. As a result, if you go below the openPage() method and start typing "web" you'll see a list of all the WKNavigationDelegate methods we can use.

Scroll through the list of options until you see didFinish and press return to have Xcode fill in the method for you. Now modify it to this:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    title = webView.title
}

All this method does is update our view controller's title property to be the title of the web view, which will automatically be set to the page title of the web page that was most recently loaded.

Press Cmd+R now to run the app, and you'll see things are starting to come together: your initial web page will load, and when the load finishes you'll see its page title in the navigation bar.

Using a UIAlertController is an easy way to let users choose which website to visit.

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.7/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.