Initializing Swift properties that require self as an argument
You've found the primary use case of the Implicitly Unwrapped Optional.
- You need to access
self
frominit
, beforetimer
is initialized. - Otherwise,
timer
should never be nil, so you shouldn't have to check it outside ofinit
.
So, you should declare let timer: NSTimer!
.
Pass self as argument within init method in Swift 1.2
The Problem
The problem is your use of let
- optionals declared as let
aren't given a default value of nil
(var
is however). The following, introduced in Swift 1.2, wouldn't be valid otherwise since you wouldn't be able to give myOptional
a value after declaring it:
let myOptional: Int?
if myCondition {
myOptional = 1
} else {
myOptional = nil
}
Therefore, you're getting the error 'Property 'self.panGestureRecognizer' not initialized at super.init call' because before calling super.init(coder: aDecoder)
, because panGestureRecognizer
isn't nil
; it hasn't been initialised at all.
The Solutions:
1. Declare panGestureRecognizer
as a var
, meaning it will be given a default value of nil
, which you could then change after calling super.init(coder: aDecoder)
.
2. In my opinion, the better solution: don't use an implicitly unwrapped optional and declare panGestureRecognizer
with an initial value of UIPanGestureRecognizer()
. Then set the target after super.init
is called:
class SubView: UIView {
let panGestureRecognizer = UIPanGestureRecognizer()
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
panGestureRecognizer.addTarget(self, action: Selector("panAction:"))
}
}
How can I initialize a class property that depends on an initializer argument as well as `self`?
An alternative is to declare consumer
in Supplier
as weak optional
to avoid a retain cycle (Consumer
holds a strong reference to Supplier
and vice versa)
class Consumer
{
let supplier: Supplier
init(observer: Observer)
{
self.supplier = Supplier(observer: observer)
supplier.consumer = self
}
}
class Observer {}
class Supplier
{
let observer : Observer
weak var consumer : Consumer?
init(observer: Observer, consumer: Consumer? = nil) {
self.observer = observer
self.consumer = consumer
}
}
And this is Swift: No trailing semicolons.
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)
}
}
Is it possible to initialize properties at the beginning of a class?
You have to initialize all instance properties somehow. And you have to do it right up front, either in the declaration line or in your init
method.
But what if you don't actually have the initial value until later, like in viewDidLoad
? Then it is silly to supply a real heavyweight value only to replace it later:
var v = MyView()
override func viewDidLoad() {
self.v = // get _real_ MyView and assign it in place of that
}
Instead, we use an Optional to mark the fact that we have no value yet; until we obtain and assign one, it will be nil
:
var v : MyView? // means it is initially `nil`
override func viewDidLoad() {
self.v = // get _real_ MyView and assign it to our property
}
Why can i use self when I initialize property with a closure?
The target in your code is probably nil
, the reason that this might work is that:
...If you specify nil, UIKit searches the responder chain for an
object that responds to the specified action message and delivers the
message to that object
(from the documentation of the method)
You can verify that the target is actually nil
by setting a breakpoint during or after your controller's init and by inspecting the _targetActions
array (in the debugger's variables view) of the button (you can see that target
's address is 0x0
).
In your example, loginRegisterButton
is set during the controller's initialization which means that there is no self
yet (in other words you cannot guarantee that all instance variables are initialized at this point). The way lazy
solves this is that the actual assignment is deferred on first access.
Property initializers run before 'self' is available
As correctly pointed out by vadian you should create an init
in such scenarios:
class MyOwn {
let myUser: User
var life: Int
init() {
self.myUser = User(name: "John", age: 100)
self.life = myUser.age
}
}
You can't provide a default value for a stored property that depends on another instance property.
swift init properties with self or not?
You can use without self, but the field variable need be different than outside variable.
Why?
Simple, variables in field is constant statement (let
) init(sideLength: Double, name: String)
sideLenght
and name
in this line are constants variables, because this you can't set new value for it.
ps. let
in swift is same than const
in other language
Ex.
The correct way to implement is with self.
, because in this case we tell to compiler to set the variable outside in our class.
Other example now setting variable without self.
, look next image, we can use without self because it is outside variable.
Related Topics
Uilabel, Uifont and Utf-8 Triangle
Uploading Image with iOS App to Server File Size Is Too Large
Removing Lagging Latency in Drawing Uibezierpath Smooth Lines in Swift
Hide a Phone Call Completely in iOS (Jailbreak Device)
Open Uiimagepickercontroller in Landscape Mode
How to Upload Multiple Image on Firebase Using Swift
What Is the Use of Singleton Class in Objective-C
Type 'Nsattributedstringkey' (Aka 'Nsstring') Has No Member 'Font'
Google 400 Error: Invalid Request Custom Scheme Uris Are Not Allowed for 'Web' Client Type
What Does $0 Represent in Closures in Swift
Programmatically Detect Dark Mode in Swiftui to Display Appropriate Image
Cannot Invoke 'Indexof' with an Argument List of Type '(Checklistitem)'
Offline Crash Reporting in Crashlytics
How to Hide a Bar Button Item for Certain Users