0

In the below code, why is test.implicitString an optional, even though the property is stored as implicitly unwrapped? I believe I need the properties to be implicitly unwrapped because my initializers call functions to initialize all values (so I can use the same function later in an update method). Is there an easy way to make it so these properties are non-optional while still allowing me to initialize the properties via a method call from within init()?

class Test {
  var implicitString: String!
  init(string: String) {
    implicitString = string
  }
}

let test = Test(string: "Hello world")

let shouldBeString = test.implicitString

// 1: Prints Optional<String> instead of String
print(type(of: shouldBeString))

// 2: Prints Optional("Hello world") instead of "Hello World"
print(String(describing: test.implicitString))
othomas
  • 256
  • 2
  • 10
  • 1
    Related: https://stackoverflow.com/questions/39633481/implicitly-unwrapped-optional-assign-in-xcode-8 – Martin R Apr 01 '18 at 13:07
  • and http://stackoverflow.com/questions/39537177/swift-3-incorrect-string-interpolation-with-implicitly-unwrapped-strings – Hamish Apr 01 '18 at 14:46

2 Answers2

2

Since you have an init method that initialise the property you can simply remove the implicit unwrapping.

class Test {
  var implicitString: String
  init(string: String) {
    implicitString = string
  }
}
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
  • This is the correct answer. (voted.) As long as the init method gives it a value, it doesn't need to be an optional at all. – Duncan C Apr 01 '18 at 13:46
  • The `!` on the declaration is not a "forced unwrap". It makes the variable "implicitly unwrapped". – rmaddy Apr 01 '18 at 16:41
  • Yes you’re right, bad wording on my part. I’ll fix it – Joakim Danielson Apr 02 '18 at 06:55
  • That won’t work because I need to set the properties via a method call. I want to be able to have an `update(from data: [String: Any])` function that reuses the initialization code to set all the instance variables. Seems silly to have that exact same code duplicated in the init and the update method but I cannot centralize that code without making all the variables implicitly unwrapped. And therein lies the problem. How can I call a function in my init, and not have my properties all be optional when used. Default values seems silly since they’ll never be used, but maybe that’s the answer. – othomas Apr 02 '18 at 19:28
  • It sounds like you need to have default values then but the whole solution is a little strange. First you are going to set all properties to specific values in the init method then later you will modify all parameters of the object, if you're completely changing the object maybe it would be better to create a new instance instead. – Joakim Danielson Apr 02 '18 at 19:52
  • Yes, I’m debating between updating the existing and creating a new instance. The class in mind is my model and I’m hoping to issue an update call, have it update the database, and then update itself with the new data and fire a completion. So really it shouldn’t be a new instance I don’t think, since it still represents the same database object, it’s just that the object has been updated. – othomas Apr 02 '18 at 21:19
0

You can get rid of the optional by setting a default value:

class Test {

    var implicitString: String = ""

    init(string: String) {
        update(value: string)
    }

    func update(value: String) {
        implicitString = value
    }

}
alanpaivaa
  • 1,959
  • 1
  • 14
  • 23
  • I know that, but it doesn't really answer the question. The question is, why are instance variables that are implicitly unwrapped considered to be regular optionals when they're actually used outside the class. Seems to me like they should either continue to be implicitly unwrapped, or should be non-optional all together. Kind of defeats (at least part of) the purpose of having them be implicitly unwrapped if I still have to unwrap them when I use them. – othomas Apr 04 '18 at 01:53