Kanishk Dilta Kanishk Dilta - 7 months ago 20
Swift Question

How do member Initializers work in Structs ? (In Swift)

Since I am a complete beginner, I don't even know whether I am asking the right question or not. But I am having trouble understand why the "User(name: "John ...)" part of the code in the for loop works

CASE1
struct User
{
let name: String
let company: String
let login: String
let password: String



static let database: Dictionary<String, User> = {
var theDatabase = Dictionary<String, User>()
for user in [
User(name: "John Appleseed", company: "Apple", login: "japple", password: "foo"),
User(name: "Madison Bumgarner", company: "World Champion San Francisco Giants", login: "madbum", password: "foo"),
User(name: "John Hennessy", company: "Stanford", login: "hennessy", password: "foo"),
User(name: "Bad Guy", company: "Criminals, Inc.", login: "baddie", password: "foo")
] {
theDatabase[user.login] = user
}
return theDatabase
}()


}

but this doesn't

CASE2
struct User
{
let name: String
let company: String
let login: String
let password: String

for user in User(name: "John Appleseed", company: "Apple", login: "japple", password: "foo"){
print(user)

}


}

To understand how CASE1 works I ran a simpler version of this code i.e. CASE2. Even though the exact same thing is happening in both cases,[ Regarding User(..arguments..) ] I get the error "Declaration Expected" in the second case.
Sir Paul(Stanford cs193p) said this was a fairly simple database , but I have been trying to figure this problem out for more than 6 hours.

Answer

for-loops must be contained in closures.

In case 1, you are declaring a static property called database using a closure. This is the declaration:

static let database: Dictionary<String, User> = {
    // This is the body of the closure
}()

And you put the for-loop in the closure body. This tells the swift compiler when to execute the for-loop, which is when the closure is executed.

In case 2, the for-loop is in the struct. But a struct isn't a closure. So the swift compiler does not know when to execute the for-loop.

The only things that can be in a struct are declarations, such as property declarations, function declarations and struct declarations. A for-loop isn't a declaration so that's why the compiler complains that it expected to see a declaration.

The code in case 1 works because the database is a property declaration.


But... there's another problem!

For-in loops only loops through objects that conform to the SequenceType protocol. Examples of such objects include arrays and String.CharatcerView.

In case 1, the for-in loop loops through an array, which conforms to SequenceType. See those [ and ]? They denote an array! In case 2, you don't have those around the newly created User, so it is just a User, which does not conform to SequenceType and thus cannot be used in a for-in loop.

To solve both of your problems, use this code:

struct User
{
    let name: String
    let company: String
    let login: String
    let password: String



    static let database: Dictionary<String, User> = {
        var theDatabase = Dictionary<String, User>()
        for user in [
            User(name: "John Appleseed", company: "Apple", login: "japple", password: "foo")] {
                theDatabase[user.login] = user
        }
        return theDatabase
    }()
}

As you can see, I added a declaration of database and the closure and added [] around the user.