Referencing Self in Super.Init

Referencing self in super.init

Short answer:

You cannot capture and use self as a value before super.init returns. In your case, you are trying to "pass" self to super.init as an argument.

As per why the second part works, simply because without using self in it, it does not capture self, thus it does not use self as a value.

If you don't want to use self in the closure, then you don't need to worry about strong/weak reference there, because there is no reference to self there at all (since it was not captured). No danger of retain cycle.


Short sidenote about "using self as a value" - you can use self on the left-hand side of an assignment to refer to properties of the self when initializing them:

let myProperty: String

init(with myProperty: String) {
// this usage of self is allowed
self.myProperty = myProperty
super.init(nibName: nil, bundle: nil)
}

Longer answer with references and stuff:

As per documentation:

Safety check 4

An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.

First phase of initialization is ended by calling super.init, when the

From the same documentation:

Phase 1

A designated or convenience initializer is called on a class.

Memory for a new instance of that class is allocated. The memory is not yet initialized.

A designated initializer for that class confirms that all stored properties introduced by that class have a value. The memory for these stored properties is now initialized.

The designated initializer hands off to a superclass initializer to perform the same task for its own stored properties.

This continues up the class inheritance chain until the top of the chain is reached.

Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance’s memory is considered to be fully initialized, and phase 1 is complete.

So only after calling super.init you are allowed to use self as value:

Phase 2

Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access self and can modify its properties, call its instance methods, and so on.

Finally, any convenience initializers in the chain have the option to customize the instance and to work with self.

Now I am not surprised at all that when you try to use self as a value in a capture list of the closure, that it crashes. I am more surprised that the compiler does allow you to do it - now I guess it's an edge case for which error handling wasn't implemented.

In the second case:

Action(title: "Yes", {
//Blank.. doesn't reference `self` in any way (weak, unowned, etc)
})

You don't really capture self, that's why it is allowed and it works. But you don't have access to self there. Try to add there some code that uses self and the compiler will complain:

Sample Image

So in the end, if you want to use self in the closure, you will have to find a way how to first call super.init and only after that add self capturing closures to the properties.

Why super().__init__ doesn't have a self-reference?

Super's functionality in this case is implemented in the CPython parser. See PEP 3135

Replacing the old usage of super, calls to the next class in the MRO (method resolution order) can be made without explicitly passing the class object (although doing so will still be supported). Every function will have a cell named __class__ that contains the class object that the function is defined in.

The new syntax:

super()

is equivalent to:

super(__class__, <firstarg>)

[...]

While super is not a reserved word, the parser recognizes the use of super in a method definition and only passes in the __class__ cell when this is found. Thus, calling a global alias of super without arguments will not necessarily work.

Emphasis added.

Using self in a callback passed to super.init

I managed to work around this meaningless restriction by refactoring the class somewhat. Instead of simply passing the constructor the data it needs directly, instead there's a getter for the data which just happens to be called exactly once by the superclass constructor. The variable that stores this data, instead of being immutable and proper, now is initialized with nil (i.e. left uninitialized) and then initialized later through the getter and then there's another getter-only computed property.

So now anyone who tries to read the class will be thoroughly confused by the worthless meandering around the point, but it does actually have the desired semantics.

init let properties with reference to self in subclass in swift

This is a good use case for an implicitly unwrapped optional.

The Apple documentation states:

“Implicitly unwrapped optionals are useful when an optional’s value is
confirmed to exist immediately after the optional is first defined and
can definitely be assumed to exist at every point thereafter. The
primary use of implicitly unwrapped optionals in Swift is during class
initialization.”

This means that you can use an implicitly unwrapped optional when a property depends on some aspect of self (but not the superclass) when it is initialised.

The property will be nil until it is set in the init() method and then must never be nil again.

class NodeView: UIView {

var _nodePlugView: NodePlugView!

init (node: Node) {
super.init()
_nodePlugView = NodePlugView (parentView: self)
}
}

Where to put super.init() when init() also initializes member variable and references self

You must initialize all non-optional properties declared in your subclass before you can call super.init()

So you have two ways of solving such issues:

  1. Change property type to optional (either SpriteComponent? or SpriteComponent!).
  2. Initialize every property either when you declare it or in your initializer before calling super.init

In your case first option suits better.

You can find more info about Swift two-phase initialization here:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html

This tutorial may also be helpful: (Adding Properties to Subclasses paragraph):
https://www.raywenderlich.com/121603/swift-tutorial-initialization-part-2

Use of 'self' in property access 'model' before super.init initializes self super.init(brand: brand, model: model)

You are calling the superclass init method to initialize part of your subclass. However, before you have initialized it, you passed an uninitialized variable. Simply add those variables into the parameter of the Piano:

init(hasPedals: Bool, brand: String, model: String)

Why should I call self=[super init]

You mean why

self = [super init];

rather than

[super init];

Two reasons:

  1. in initialisation, failure is indicated by returning nil. You need to know if initialisation of the super object failed.
  2. the super class might choose to replace the self returned by +alloc with a different object. This is rare but happens most frequently with class clusters.

Edited in response to Michael's comment:

I can understand why I need to save and return [super init]. But is it just convention and good looking makes us use self as a temporary variable to pass result along?

No. Instance variables are accessed relative to the self pointer, so in the following:

-(id) init
{
self = [super init];
if (self != nil)
{
myBoolIvar = YES;
// The above is an implicit version of self->myBoolIvar = YES;
}
return self;
}

self has clearly got to point to the right block of memory i.e. the one you are going to return.

The other point is that if super init returns different class instance then the rest of the code after that line may not even make sense, lead to memory leaks and crashes, not even talking about the object instantiated from that class.

That could be a problem. If I subclassed NSNumber and [super init] decided to return an NSString (which it could - there's nothing to stop it) that would clearly be a disaster. Whatever super returns from -init must be "compatible" with the subclass in the sense of providing space for ivars and being further subclassible or it's a horrendous bug (unless, of course, the problem is documented). So, in general, you don't need to worry about checking the class. However, do read the documentation. See for instance the section on subclassing NSString in NSString's docs.

self' used in method call 'foo' before 'super.init' call

You should not set instance methods into instance properties even where referencing self.methodName is allowed, which makes reference cycles.

A simple workaround is something like this:

class BrowDownEvaluator: BothEvaluator {
static func onBoth(delegate: FaceTriggerDelegate, newBoth: Bool) {
delegate.onBrowDownDidChange?(browDown: newBoth)
if newBoth {
delegate.onBrowDown?()
}
}

static func onLeft(delegate: FaceTriggerDelegate, newLeft: Bool) {
}

static func onRight(delegate: FaceTriggerDelegate, newRight: Bool) {
}

init(threshold: Float) {
super.init(threshold: threshold, leftKey: .browDownLeft, rightKey: .browDownRight,
onBoth: BrowDownEvaluator.onBoth,
onLeft: BrowDownEvaluator.onLeft,
onRight: BrowDownEvaluator.onRight)
}
}

If you want to access self as an instance of BrowDownEvaluator, things get a little more complicated.



Related Topics



Leave a reply



Submit