0

I wrote a custom TableViewCell class that either returns the accessibilityLabel that was set on it, or just return its class name as the accessibilityLabel. Though one of the two implementations below doesn't work as expected. I'm trying to understand why...

returns correct className

class BaseTableViewCell: UITableViewCell {
    var _acsLabel: String?

    override var accessibilityLabel: String?{
        get{
            return _acsLabel ?? "\(type(of: self))"
        }set (newValue) {
            _acsLabel = newValue ?? ""
        }
    }
}

returns incorrect class name

class BaseTableViewCell: UITableViewCell {
    var _acsLabel: String? = "\(type(of: self))"

    override var accessibilityLabel: String?{
        get{
            return _acsLabel
        }set (newValue) {
            _acsLabel = newValue ?? ""
        }
    }
}

Both versions correctly return the value if I set the accessibilityLabel, however if the value is not set the default values they return are different.

For example I subclass UserNameTableViewCell off my BaseTableViewCell class and don't set the accessibilityLabel myself then:

  • The correct version returns the accessibilityLabel as UserNameTableViewCell.
  • The incorrect version returns the accessibilityLabel as returns "(BaseTableViewCell) -> () -> BaseTableViewCell"

Why is that?!

mfaani
  • 33,269
  • 19
  • 164
  • 293
  • Your class names and the output you show do not match. Are these typos? – rmaddy Jun 12 '18 at 18:33
  • it was a typo. Thanks. Fixed – mfaani Jun 12 '18 at 18:35
  • What is `UserNameTableViewCell`? – rmaddy Jun 12 '18 at 18:36
  • It's an example. So if I subclass `UserNameTableViewCell` off my `BaseTableViewCell` class and don't set the `accessibilityLabel` myself then I expect the `accessibilityLabel` to be **UserNameTableViewCell**. Yet it returns **"(BaseTableViewCell) -> () -> BaseTableViewCell"**. Is it clear now? – mfaani Jun 12 '18 at 18:37
  • Probably because `self` hasn't been initialized yet at the point when the property default value is set. Making the property `lazy` should fix it. – dan Jun 12 '18 at 19:04
  • 1
    Using `self` in a (non-lazy) property initialiser is usually a compiler error, but unfortunately isn't in your case because `NSObjectProtocol` has a `self()` instance method that you can refer to – compare my comment here https://stackoverflow.com/questions/50393312/why-can-i-use-self-when-i-initialize-property-with-a-closure/50394741#comment87805830_50394741 – Hamish Jun 12 '18 at 19:23
  • @dan Hah! Good catch. That was it. Would you like to write that as an answer so I can accept it? – mfaani Jun 12 '18 at 19:39

1 Answers1

1

self is not initialized by the time you call it in the second version of the code, that is why it shows the name of the super class.

If you set that variable as lazy, it will not be set from the beginning, but will be set right when you do myInstance.accesibilityLabel, thus making sure the name of the class is already available because self would have been initialised.

regina_fallangi
  • 2,080
  • 2
  • 18
  • 38
  • It's not initialized by that time. ok. So what is it that I'm printing? – mfaani Jun 13 '18 at 03:00
  • You are printing the `self()` of the `NSObjectProtocol`. `UITableViewCell` inherits from `UIView`, which implements `UICoordinateSpace`, which inherits from `NSObjectProtocol`. `UIView` implements `self()`. The default implementation of `self()`, like someone posted in a comment (did not see it before posting answer) is curried to `(Self) -> () -> (Self)`, which is what you get. And it is available before initialising because Swift lets you access property initialisers as if they were `static`. – regina_fallangi Jun 13 '18 at 07:17