Koen Koen - 1 year ago 123
Swift Question

Compiler errors for struct init in Swift

I have the following struct:

struct Person {
let name: String
let age: Int
let assets: Double

To initialize a person, I would like to pass it a dictionary that contains the name and age, as well as info to calculate the assets:

public init(info: [String : AnyObject]) {
if let name = info["name"] as? String {
self.name = name

if let age = info["age"] as? Int {
self.age = age

if let assets = info["assets"] as? [String : AnyObject] {
calculateAssets(assets: assets)

mutating func calculateAssets(assets: [String : AnyObject]) {
self.assets = 1+2+3.4 // really do this with info from the dictionary

With this setup, I get two compiler errors:

  1. 'self' used before all stored properties are initialized

  2. Return from initializer without initializing all stored properties

Following the compiler suggestions, I added a default value for each property, and changed them to be a

struct Person {
var name: String = ""
var age: Int = 0
var assets: Double = 0.0

// init ...

And indeed, the compiler errors are gone.

But am I on the right track by making these corrections?

Answer Source

The problem is that in your init function you might initialize the variables but you can't be sure, since the conditions of the if statements can be false. This is why the compiler is giving you the errors (also because you are trying to call self.assets in another function when the variable might still not be initialized - so you at least need to change this one to a var).

If you can't be sure that the values in the info dictionary are valid you should change your variables to var.

Now you have two choices:

  • Give your variables a default value (like you did in your example)
  • Declare your variables as Optionals (like suggested by @Özgür).

Your choice depends on what makes more sense. If your default values make sense for your situation and you can work with the variables having those values then I'd go with that.

Otherwise, you should go with the Optionals. Optionals obviously have the plus that you don't need to initialize them but then the con is that you'll need to implicitly or explicitly unwrap them later when you want to use them (using ? or !).

If - for whatever reason - you can be sure that the values in the info dict are valid - you could also leave your name and age as constants (let) and just explicitly unwrap the dictionary values when you assign them:

self.name = info["name"] as! String

self.age = info["age"] as! Int

But as I said this would only work if info["name"] and info["age"] contain valid values, otherwise you will get a runtime exception. So the "default value" or "Optional" choices are your safe and clean options, whereas this is the quick and dirty way.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download