iosxcodeswiftcs193pmember-initialization

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.


Solution

  • 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.