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

How do I fix "Expected member name following '.'" error?

Forums > Swift

I am trying to display text stored in an array and it's showing the error Expected member name following '.' and as far as I can tell I've done everything right. Here is my code:

struct CountdownView: View {
    private var countdowns = Countdowns()
    var body: some View {
        HStack{
            VStack {
                Text("1")
                    .font(.system(size: 50))
                Text("Day")
            } .padding(.trailing, 30)
            Divider()
                .frame(height: 85)
            Spacer()
                .frame(width: 30)
            VStack(alignment: .leading) {
                Text(countdowns.Events.$0.name)  // Error occurs here
                    .font(.system(size: 25))
                Text("23 hours, 32 minutes remaining")
            }
            Spacer()
        }
        .padding(.leading, 32.0)
        .frame(height: 90)
        Divider()
            .padding(.top, -1.0)
    }
}

Here is the data structure it is reading from:

class Countdowns: ObservableObject {
    @Published var Events = [Event]()
}

public struct Event: Codable {
    public var date = Date()
    public var time = Date()
    public var name: String
}

Thanks in advance for your help.

   

$0 is not a member of your Event struct. I'm not sure exactly what you are trying to accomplish, but if you want to access the first item in the Events array, you should use Events[0] instead of Events.$0.

You would use $0 in a case where you are looping through an array of items and accessing each one. So if, for instance, you were looping through countdowns.Events and displaying each one, you could use something like this:

ForEach(countdowns.Events) { 
    //$0 refers to the item passed into ForEach's closure
    VStack(alignment: .leading) {
        Text($0.name)
            .font(.system(size: 25))
    }
}

which is the equivalent of this:

ForEach(countdowns.Events) { event in
    VStack(alignment: .leading) {
        Text(event.name)
            .font(.system(size: 25))
    }
}

Also, you should not name properties using capital letters. Capitalized names are for types; start property and function names with a lowercase letter.

So...

class Countdowns: ObservableObject {
    @Published var events = [Event]()
}

You can even see that the syntax coloring applied by the forums colors names differently if they start with a capital letter versus starting with a lowercase letter. Because those conventions—while being only convention, not a rule—have meaning in Swift.

   

Thank you. I have renamed Events to events. When I attempt to use

ForEach(countdowns.Events) {
    VStack(alignment: .leading) {
        Text($0.name)
            .font(.system(size:25))
    }
}

I receive the error Contextual closure type '() -> TupleView<(Text, Text)>' expects 0 arguments, but 1 was used in closure body on the VStack. I have a feeling that it has something to do with the fact that the VStack isn't contained within the ForEach statement, rather the whole view is.

When I attempt to use

ForEach(countdowns.Events) { event in
    VStack(alignment: .leading) {
        Text(event.name)
            .font(.system(sixe: 25))
    }
}

I get the error Failed to produce diagnostic for expression; please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project on the var body: Some View of the view containing the ForEach loop.

   

Events should no longer exist as it should be events now

class Countdowns: ObservableObject {
    @Published var events = [Event]()
}

Then your ForEach loop would be

ForEach(countdowns.events) { event in
    VStack(alignment: .leading) {
        Text(event.name)
            .font(.system(size: 25))
    }
}

However that will fail as countdowns.events needs to have the Event struct as an identifiable type. The choice is either to add the Identifiable protocol or Hashable protocol to the Event struct.

Either

public struct Event: Codable, Identifiable {
    public var date = Date()
    public var time = Date()
    public var name: String
    public var id = UUID()
}

or

public struct Event: Codable, Hashable {
    public var date = Date()
    public var time = Date()
    public var name: String
}

If you use the Hashable version of the struct, then the ForEach loop needs to be modified or the unique identifier.

ForEach(countdowns.events, id: \.self) { event in
    VStack(alignment: .leading) {
        Text(event.name)
            .font(.system(size: 25))
    }
}

   

When I try both the Hashable and Identifiable methods, I get the error Instance member 'name' cannot be used on type 'Event'; did you mean to use a value of this type instead? at the Text(Event.name) line. When I do the Identifiable method I also get the error Type 'Event' does not conform to protocol 'Identifiable'.

   

ForEach(countdowns.events) { event in
    VStack(alignment: .leading) {
        Text(event.name)
            .font(.system(size: 25))
    }
}

This uses countdowns.events not countdowns.Events

Edit:

class Countdowns: ObservableObject {
    @Published var events = [Event]()
}

public struct Event: Codable, Hashable {
    public var date = Date()
    public var time = Date()
    public var name: String
}

struct CountdownView: View {

    private var countdowns = Countdowns()

    var body: some View {
        HStack{
            VStack {
                Text("1")
                    .font(.system(size: 50))
                Text("Day")
            } .padding(.trailing, 30)
            Divider()
                .frame(height: 85)
            Spacer()
                .frame(width: 30)

            ForEach(countdowns.events, id: \.self) { event in
                VStack(alignment: .leading) {
                    Text(event.name)
                        .font(.system(size: 25))
                }
            }
//            VStack(alignment: .leading) {
//                Text(countdowns.Events.$0.name)  // Error occurs here
//                    .font(.system(size: 25))
//                Text("23 hours, 32 minutes remaining")
//            }
            Text("23 hours, 32 minutes remaining")
            Spacer()
        }
        .padding(.leading, 32.0)
        .frame(height: 90)
        Divider()
            .padding(.top, -1.0)
    }
}

   

Unless I'm missing something that's what I already have, and is producing the error, because I've already changed Events to events, so I'm not too sure what to do.

   

Try cleaning your build folder. Menu\Product\Clean Build Folder. Sometimes Xcode leaves spurious build elements and products in the Build Folder.

See if that helps.

Also, did you try copying and pasting the code I uploaded?

   

I have cleared the build folder, and the only difference between your code and mine is that I'm calling

ForEach(countdowns.events, id: \.self) { event in
    CountdownView()
}

in the ContentView, instead of for the Text, because the whole CountdownView needs to be displayed for each event in the array, the text is just the first element I changed to access the Countdowns() class.

   

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.