NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

Day 60: best way to call one of two different views depending on an optional?

Forums > 100 Days of SwiftUI

I wrote my UserView for day 60's challenge like this:

import SwiftUI

struct UserView: View {
    var users: [User]
    var user: User

    var body: some View {
        VStack {
            Form {
                Section {
                    HStack {
                        Text("Age: ")
                            .fontWeight(.bold)
                        Spacer()
                        Text("\(user.age)")
                    }
                    HStack {
                        Text("Company: ")
                            .fontWeight(.bold)
                        Spacer()
                        Text(user.company)
                    }
                    HStack {
                        Text("Email: ")
                            .fontWeight(.bold)
                        Spacer()
                        Text(user.email)
                    }
                    HStack {
                        Text("Address: ")
                            .fontWeight(.bold)
                        Spacer()
                        Text(user.address)
                            .multilineTextAlignment(.trailing)
                    }

                    HStack {
                        Text("Date registered: ")
                            .fontWeight(.bold)
                        Spacer()
                        Text("\(user.registered, formatter: itemFormatter)")
                    }
                }

                Section(header: Text("About")) {
                    Text(user.about)
                        .padding(.vertical)
                }

                Section(header: Text("Friends")) {
                    ForEach(user.friends, id: \.id) { friend in
                        NavigationLink(destination: findFriend(from: friend, in: users)) {
                            Text(friend.name)
                        }
                    }
                }
            }
        }
        .navigationBarTitle(Text(user.name))
    }

    func findFriend(from friend: Friend, in users: [User]) -> some View {
        guard let user = users.first(where: { $0.id == friend.id }) else {
            return AnyView(Text("No match"))
        }
        return AnyView(UserView(users: users, user: user))
    }
}

private let itemFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    return formatter
}()

//struct UserView_Previews: PreviewProvider {
//    static var previews: some View {
//        UserView()
//    }
//}

I have two questions about things I think I've done slightly badly.

  1. How do I get the preview to work? I tried doing UserView(users: [User()], user: User()) but I got the error "Missing argument for parameter 'from' in call" and I couldn't work out how to create a dummy User() for the purposes of the preview.

  2. As you can see, I use the findFriend function to return a UserView which contains the user corresponding to the friend, but I wanted to make sure that if (for some reason) the underlying JSON specified a friend which didn't exist, I could return some view which indicated that in some way. My way works, but I was wondering whether there was a more elegant way to achieve this?

Just in case it's relevant, my User and Friend structs are defined thus in ContentView:

struct User: Codable {
    var id: String
    var isActive: Bool
    var name: String
    var age: Int
    var company: String
    var email: String
    var address: String
    var about: String
    var registered: Date
    var tags: [String]
    var friends: [Friend]
}

struct Friend: Codable {
    var id: String
    var name: String
}

   

First I assume this is the FriendFace one!

  1. As there is no data until the network call you need to add same data so in the struct User: Codable put this

    #if DEBUG
    // show in preview set up only
    static let example = User(
        id: "0",
        isActive: true,
        name: "Test Name",
        age: 99,
        company: "Test.inc",
        email: "test@test.com",
        address: "1 Test drive, Teston",
        about: "Occaecat consequat elit aliquip magna laboris dolore laboris sunt officia adipisicing reprehenderit sunt. Do in proident consectetur labore. Laboris pariatur quis incididunt nostrud labore ad cillum veniam ipsum ullamco. Dolore laborum commodo veniam nisi. Eu ullamco cillum ex nostrud fugiat eu consequat enim cupidatat. Non incididunt fugiat cupidatat reprehenderit nostrud eiusmod eu sit minim do amet qui cupidatat. Elit aliquip nisi ea veniam proident dolore exercitation irure est deserunt.\r\n",
        registered: Date(),
        tags: ["cillum"],
        friends: [Friend(id: "91b5be3d-9a19-4ac2-b2ce-89cc41884ed0", name: "Hawkins Patel")]
        )
    #endif

In the struct UserView. If you take out the var users: [User] then in struct UserView_Previews: PreviewProvider do

struct UserView_Previews: PreviewProvider {
    static var previews: some View {
       UserView(user: User.example)
   }
}

2. I know that the above will break this! And I have not done this bit of challenge but this would be depands on how you fetch the data for the "friend" but you might need to put it the @StateObjectand .environmentObject and then you can have @EnvironmentObject var users which means you need .environmentObject(users) in the Preview.

I also might try to avoid using AnyView() and the same View as what you coming from I would do a FriendView(passing in the user.friend.id) and find it the new View. (my opinion) and avoid using @EnvironmentObject in this view.

   

Hacking with Swift is sponsored by Stream

SPONSORED Check out Stream's cross-platform open source chat SDK on GitHub! Write once and deploy your app with fully featured chat UI on iOS and macOS.

Go to GitHub

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.