BLACK FRIDAY: Save 50% on all my Swift books and bundles! >>

SOLVED: Day 30 Project 5: navigation Title doesn't show

Forums > 100 Days of SwiftUI

Hi all, I'm walking through Day 30, Part 2 "Running code when our app launches", and unlike what the instruction says, I do not see a random eight-letter word at the top of the navigation view.

Does it happen because .navigationTitle(rootWord) is not working, or onAppear() is not working?

Here is my code.

I have followed every step and couldn't see where went wrong.

import SwiftUI

struct ContentView: View {
    @State private var usedWords = [String]() //an array of words already used
    @State private var rootWord = "" //to spell other words from
    @State private var newWord = "" //a string we can bind to a text field

    var body: some View {
        NavigationView {
            List {

                Section {
                    TextField("Enter your word: ", text: $newWord).autocapitalization(.none)
                }

                Section {
                    ForEach(usedWords, id: \.self) {word in
                        HStack {
                            Image(systemName: "\(word.count).circle.fill")
                            Text(word)
                        }
                    }
                }

            }
        }
        .navigationTitle(rootWord)
        // an alternative way is to write onSubmit(addNewWord), but I find this one to be intuitve
        .onSubmit{
            addNewWord()
        }
        .onAppear(perform: startGame)
    }

    // call this function when the user press return on the keyboard
    func addNewWord() {
        // lowercase and trim the word, to make sure we don't add duplicate words with case differences
        let answer = newWord.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
        // exit if the remaining string is empty
        guard answer.count > 0 else { return }
        withAnimation {
            usedWords.insert(answer, at: 0) // put it at the beginning of the array
        }
        newWord = ""
    }

    func startGame() {
        // 1. Find the URL for start.txt in our app bundle
        if let startWordsURL = Bundle.main.url(forResource: "start", withExtension: "txt") {
            // 2. Load start.txt into a string
            if let startWords = try? String(contentsOf: startWordsURL) {
                // 3. Split the string up into an array of strings, splitting on line breaks
                let allWords = startWords.components(separatedBy: "\n")

                // 4. Pick one random word, or use "silkworm" as a sensible default
                rootWord = allWords.randomElement() ?? "holyshit"
                // If we are here everything has worked, so we can exit
                return
            }
        }
        // If were are *here* then there was a problem – trigger a crash and report the error
        fatalError("Could not load start.txt from bundle.")
    }

}

2      

It look like yo have attached the .navigationTitle(rootWord) to the NavigationView and you need to attach it to a view inside the NavigationView so if you attach it to List it should work.

3      

Yes it worked. I don't exactly understand why though.

2      

NavigationView provides a container for a bunch of Views that can be navigated through. The container doesn't have a title itself; the title is supplied by each View that is contained within.

That way, each View you navigate to can have its own title rather than having one title for the entire navigation stack.

It also makes it easy for the back button to display the title of the previous View in the stack. It can hold the stack of previous Views and ask each one for its title when it needs to. Otherwise, the NavigationView would need to separately track all the previous titles in addition to tracking the previous Views.

3      

I will try to explain but think Paul says better in one of his video (not sure which one)

The Navigation Title belongs to the view inside the NavigationView. If you have ContentView that has a link to a SecondView you do not put a NavigationView in the SecondView as it inherits it from the previous view.

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink {
                SecondView()
            } label: {
                Text("Hello, world!")
            }
            .navigationTitle("First View")
        }
    }
}
struct SecondView: View {
    var body: some View {
        VStack {
            Text("Goodbye world!")
        }
        .navigationTitle("Second View")
    }
}

i have just seen @roosterboy has also explained as well hopefully you have a better understanding

2      

Thank you both, very helpful. When I work through projects, I like to read the text instead of watching Paul's video. Do you think the video is superior? I remember Paul wrote at the beginning of the 100 day course that there is a content equivalency between those two.

2      

I'm having this same problem, but the solution isn't working for me. I was able to confirm that "allWords" is being populated with the word list and a random word is being assigned to "rootWord." Despite this, the navigation title isn't showing up.

I can get a placeholder title to show up, for example .navigationTitle("Title") works.

 var body: some View {
        NavigationView {
            List {
                Section {
                    TextField("Enter your word", text: $newWord)
                        .autocapitalization(.none)
                }

                Section {
                    ForEach(usedWords, id: \.self) { word in
                        HStack {
                            Image(systemName: "\(word.count).circle")
                            Text(word)
                        }
                    }
                }
            }
            .navigationTitle(rootWord)
            .onSubmit(addNewWord)
            .onAppear(perform: startGame)
        }
    }

2      

Having the same issue as above. And judging by the date of the post, something may have changed recently in terms of modifying the value of navigationTitle dynamically from a State var. Or there is something I don't quite understand about this.

I've found out though that if you initialise the @State var to the default value shown in the course ("silkworm"), or any other, really, then it works fine.

For example:

@State private var rootWord = "silkworm"

However, if it's empty, then it does not show.

I have also checked printing the value of the rootWord State var after .onAppear is invoked when the view is loaded and the value is there and is different, pulled from the .txt file, every time.

2      

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.