简体   繁体   中英

How can I initialize a struct or class in Swift?

I have a struct called Person in this code in the down, I am creating an instance of it, like this one:

let peson: Person = Person(name: "Dan", age: 21)

But I noticed that we can make it with this code as well:

let peson: Person = { Person(name: "Dan", age: 21) }()

So what is the difference? When I should use first way and when I should use second way?

struct Person {

    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
}

This is the Swift equivalent of what JS calls an Immediately invoked funciton expression (IIFE)

{ Person(name: "Dan", age: 21) } is a closure, of type () -> Person .

{ Person(name: "Dan", age: 21) }() calls this closure, passing no arguments (since it has no parameters), and returns the new Person . The result evaluated to just a Person .

You could nest this any number of times. You could even do:

let person: Person = {{{{{{{{{{ Person(name: "Dan", age: 21) }()}()}()}()}()}()}()}()}()}()

or

let person: Person = {{{{{{{{{{ Person(name: "Dan", age: 21) }}}}}}}}}}()()()()()()()()()()

But there's obviously no point. You code would be most idomaticly written as:

let person = Person(name: "Dan", age: 21)

When you want to perform multiple operations while initializing, using closures will help you keep the code clean. See example snippet below -

struct Person {
    var name: String
    var age: Int
    var maritalStatus: MaritalStatus?
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    init (name: String, age: Int, maritalStatus: MaritalStatus) {
        self.init(name: name, age: age)
        self.maritalStatus = maritalStatus
    }
    
    enum MaritalStatus: String {
        case single = "Single"
        case married = "Married"
        case divorced = "Divorced"
    }
}

let person1 = Person(name: "Jonn", age: 10)
let person2: Person = {
    var person = Person(name: "Bob", age: 26)
    person.maritalStatus = .married
    return person
}()
let person3 = Person(name: "Sam", age: 45, maritalStatus: .divorced)

In the above example, person1 and person3 are initialozed with different initilizers, but person 2 assigns the maritalStatus property differently.

Now consider initializations when you want to change mulitple properties on a object, for example UIView - initializing it, changing the corner radius, assigning a background view, adding pre-selected sub views etc., such closure style of initialization is very helpful.

The anonymous closure is an unnamed function. It's useful whenever you want to initialize something with the result of calling a function, but you don't want to write a function like:

  func makeDan() -> Person {
     ...
  }

  let person = makeDan()

That would mean you have to come up with a name for the function and find some place to put it, which means it's also visible and can be called by other pieces of code that don't need anything to do with makeDan. It's often useful to have functions that have no names.

Needing a function to initialise something is useful when you have something complex that needs some kind of computation, so multiple lines of stuff. It's also useful when the initialization is only wanted to be done if/when required:

lazy var dan: Person = { ... }()

Perhaps because the computation is expensive in some kind of resource use, like cpu or memory. Or possibly because the computation involves some kind of side effect, like opening a database or something, that's only wanted if/when the property is used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM