WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

Project 4: How do I solve challenge 3?

Forums > 100 Days of Swift

Hello, I tried for challenge 3 but couldn't figure it out. What to do after I convert the view controller to table view. Thank you for your help.


Hi, It took me quite long to solve this third challenge, I could not finish this challenge without hints from Michele Galvagno and notes from Project 1. In my opinion, this challenge requires so many small steps that the human brain could not remember all. Therefore, writing it down would be the perfect way to learn. Missing only one small step could not make it happen. Here is my writing:

  1. Make copy of project 4, open the copy to continue.

  2. In Main.storyboard, remove current Navigation Controller Scene. Open Library, search and drag “Table View Controller” to the canvas.

  3. Place this new “Table View Controller” into a navigation controller by clicking on Editor menu and choose Embed In —> Navigation Controller. 
In Document Outline, select on the new Navigation Controller, in Attributes Inspector, Is Initial View Controller should be marked.

  4. To host the new table view screen, we need to create new code that can be navigated from the Project Navigator. Go to File menu, choose New —>File, a window appears, choose iOS, then choose Cocoa Touch Class, then click Next. For the name, enter “TableViewController” in Class. To tell iOS what it should build on, enter “UITableViewController” in Subclass of. Ensure Also create XIB file is not checked. Click Next and Create to add the new file.

  5. In Main.storyboard: 

    a) Look for the new Table View Controller, inside there should be a Table View which contains a Table View Cell. A Table View Cell is responsible for displaying one row of data in a table. Select it, in Attribute Inspector, enter the text e.g “websiteName” into the text filed marked Identifier.

    b) Click on the new Table View Controller that is above Table View, in Identity Inspector, in the Class box, select or enter “TableViewController”, and check on Inherit Module From Target, so our new user interface is connected to the new code we made earlier.

    c) In View Controller Scene, to give it a name, go to Identity Inspector, then enter e.g “WebView” in Storyboard ID.

  6. In TableViewController.swift:

    a) Cut and paste websites array from ViewController.swift to TableViewController.swift, place them right after class TableViewController. 
For ex:

    var websites = ["apple.com", "hackingwithswift.com", "yle.fi"]

b) Adjust numberOfRowsInSection method with websites.count.
For ex:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return websites.count

c) We don’t need numberOfSections method, so erase if it’s there.

d) Complete cellForRowAt method, with an identifier of “websiteName” that we used earlier for Table View Cell.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "websiteName", for: indexPath)
        cell.textLabel?.text = websites[indexPath.row]
        return cell

e) A method of didSelectRowAt() should be added as follows:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if let webViewController = storyboard?.instantiateViewController(withIdentifier: "WebView") as? ViewController {
            webViewController.websiteToLoad = websites[indexPath.row]
            navigationController?.pushViewController(webViewController, animated: true)

  1. In ViewController.swift:

    a) Create a global var of string - the name of the website to load.

    var websiteToLoad: String?

b) Replace from

let url = URL(string: "https://" + websites[0])!


let url = URL(string: "https://" + websiteToLoad!)!

c) Remove openTapped() method and related buttons inside it since we don’t them anymore.

d) Remove the line of “Open” rightBarButtonItem.

e) Inside decidePolicyFor(), remove the website loop, and its braces. Replace “website”with “websiteToLoad”, as follows:

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        let url = navigationAction.request.url

            if let host = url?.host {
                    if host.contains(websiteToLoad!) {
        let deniedAc = UIAlertController(title: "Access Denied", message: "This website is not allowed!", preferredStyle: .alert)
        deniedAc.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        present(deniedAc, animated: true)


Thanks so much for this, @hannale1892!

I now see why I was going about this all wrong, so much appreciated.

The only query / issue I have with the above is your decidePolicyFor code seems to only permit url's with the host of the website you specifically clicked from the initial list, whereas if you had two websites in your whitelist that somehow linked to one another, you would possibly get an issue trying to access website 2 through website 1 as you didn't open website 2 directly from the start? Is that right?

Either way, for the stage we're at in learning swift, this has been great and I appreciate it.


Hacking with Swift is sponsored by Emerge

SPONSORED Optimize your app’s startup time, binary size, and overall performance using Emerge’s advanced app optimization and monitoring tools. Reliably measure app size, speed up your app's startup time with Emerge's Launch Booster, and much more. Emerge is actively used by many of the top mobile development teams in the world.

Find out more

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

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.