0

I am taking the CS193 class. From this exact moment of the video.

Option 1:

class FaceView: UIView
{
    var scale: CGFloat = 0.90
    var mouthCurvature: Double = 1.0 

    private var skullRadius: CGFloat {
        return min(bounds.size.width, bounds.size.height) / 2 * scale
    }
 }

Why can't I write

Option 2:

class FaceView: UIView
{
    var scale: CGFloat = 0.90
    var mouthCurvature: Double = 1.0 

    private var skullRadius = min(bounds.size.width, bounds.size.height) / 2 * scale

 }

The professor goes and explains that you during initialization you can't access your own property and therefore if you do option 2, you will get an error saying: instance member 'bounds' cannot be used on type 'FaceView'.

OK, but aren't we still accessing the instance member 'bounds` in Option 1 as well? What's the difference? Or is it that accessing is OK, but you can't make one property dependent on another during initialization?

mfaani
  • 33,269
  • 19
  • 164
  • 293
  • the difference is when you access it. in option 2, faceview isn't instantiated yet, so it has no bounds – Jared Jun 07 '16 at 16:18
  • I guess I wasn't able to convey my question to you, I already know that... How is it that it's considered instantiated in Option 1? What are we doing there differently? Simply `return`ing and solving the issue doesn't demystify it for me... – mfaani Jun 07 '16 at 16:20
  • 3
    `scale` and `mouthCurvature` are initialized when an instance of `FaceView` is instantiated. Your computed property `skullRadius` is computed when the instantiated object has that property called for, after instantiation. In the other case where `skullRadius` is a regular property it's set up at instantiation so the other members are not yet available. –  Jun 07 '16 at 16:25

1 Answers1

1

This is one of the differences between stored properties and computed properties.

The stored properties scale and mouthCurvature are initialized when an instance of FaceView is instantiated.

In your first example skullRadius is a computed property which is computed when your FaceView instance has that property called upon, after instantiation.

In the second example skullRadius is a stored property which is initialized at instantiation. The other properties are not yet available at that point because they may or may not be initialized.

Here's how you can refer to another property during initialization:

class test {
  let foo = 1 // stored property
  let bar = 2 // stored property
  let buzz: Int // stored property not initialized when other stored properties are initialized
  init() {
    buzz = foo + bar // initialized after other stored properties
  }
}

Example showing how lazy properties can be modified:

class Test {
  lazy var foo: Int = { return 5 }()
}

let test = Test()
print(test.foo) -> "5"
test.foo = 10
print(test.foo) -> "10"
  • So you mean: **1)** *any* computed property happens **only** after instantiation? **2)** `bounds` is a stored property and `skullRadius` is a computed Property **3)** you can never do `SomeStoredProperty = someCalculationOfAnotherStoredProperty` *during* instantiation? **4)** Therefor you must do `SomeStoredProperty { return someCalculationOfAnotherStoredProperty}` – mfaani Jun 07 '16 at 16:33
  • 1
    You can get around it with `lazy var someStoredProperty: T = { ...return x }()`. – jtbandes Jun 07 '16 at 16:39
  • 1
    Yes, that's pretty much it. You can also use a stored property and refer to other stored properties if you set it in the init method. The init method occurs after the stored properties are initialized. I've updated my answer to show this. –  Jun 07 '16 at 16:39
  • Now that mentioned that we can use stored properties in init method...Can you explain what is [this](http://stackoverflow.com/questions/8056188/should-i-refer-to-self-property-in-the-init-method-with-arc). I do understand that this is Objective-C question but I think the concepts are very close and confused I am again! – mfaani Jun 07 '16 at 16:45
  • 1
    @jtbandes Correct, a lazy property can be used with a closure or a function call in order to set it at a later point. However, the property must be declared with `var` and not `let`. That can be an issue in some circumstances. –  Jun 07 '16 at 16:47
  • 2
    @Honey My Objective-C is a bit rusty but I don't think that question applies to Swift at all. –  Jun 07 '16 at 16:49
  • I'm curious what you mean by "it can be an issue"? – jtbandes Jun 07 '16 at 16:57
  • With `var` your property can be reassigned at any time. If you declare it with `let` then it's a constant. This is also true of lazy properties. –  Jun 07 '16 at 17:01
  • 1
    @Honey The computed (and lazy) properties only happen **when requested** _therefore_ only after instantiation. – rebusB Jun 07 '16 at 17:13
  • Computed properties are computed every time they are accessed. Lazy properties are computed only the first time they are requested. After that they are normal properties that can be changed. I put some code in my answer, try it out. –  Jun 07 '16 at 17:45