Swift: Call self method inside init
No, it's not a defect, simply self
cannot be referenced in an initializer until all stored properties have been initialized, and a super class initializer has been invoked (if any).
In your case it seems legit to do the initializations in a method, and call that from the initializer, but unfortunately it doesn't work.
Possible solutions:
- make the properties optional or implicitly unwrapped (discouraged, unless you really need them optionals)
initialize the properties with fake values before calling
reset
:init() {
self.a = 0
self.b = 0
self.c = 0
self.d = 0
reset()
}or
var a = 0
var b = 0
var c = 0
var d = 0
init() {
reset()
}
Initialising member to class function causes 'self' used in method call error
It might be better to not use a Bool
, but rather a nested Enum
, which is also more extendible if you wanna add some other modes of haptic feedback later on.
I have a generalized solution for a generalized problem of your question. So either you do:
public class FunctionOwner {
private let mode: Mode
public init(`do` mode: Mode = .default) {
self.mode = mode
}
}
public extension FunctionOwner {
enum Mode {
case foo, bar
}
func fooOrBar() {
switch mode {
case .foo: foo()
case .bar: bar()
}
}
}
private extension FunctionOwner {
func foo() {
print("doing foo")
}
func bar() {
print("doing bar")
}
}
public extension FunctionOwner.Mode {
static var `default`: FunctionOwner.Mode {
return .foo
}
}
// USAGE
FunctionOwner(do: .bar).fooOrBar() // prints "doing foo"
FunctionOwner(do: .foo).fooOrBar() // prints "doing bar"
Or if you for some reason do want to keep the stored Mode
, you can do this (might be relevant for your actual question on how you do a workaround of referencing self
in the init.):
public class FunctionOwner {
private let _function: (FunctionOwner) -> Void
public init(`do` mode: Mode = .default) {
_function = { functionOwner in
switch mode {
case .foo: functionOwner.foo()
case .bar: functionOwner.bar()
}
}
}
}
public extension FunctionOwner {
enum Mode {
case foo, bar
}
func fooOrBar() {
_function(self)
}
}
// The rest of the code is the same as the example above
Call methods from Swift initializer
declare it as an implicitly unwrapped optional
class MyClass : NSObject {
var myProperty: String!
init() {
super.init()
self.setupMyProperty()
}
func setupMyProperty() {
self.myProperty = "x"
}
}
page 499 of "The Swift Programming Language" manual
Use of self in method call before super.init initializes self', can't init properties through a method call
Form documentation:
Swift’s compiler performs four helpful safety-checks to make sure that
two-phase initialization is completed without error:Safety check 1 A designated initializer must ensure that all of the
properties introduced by its class are initialized before it delegates
up to a superclass initializer.
You need to set value for instance variable before you call super.init() And after this action you will access to call instance methods. In your case you can do this:
override init (frame : CGRect) {
self.collectionView = UICollectionView()
super.init(frame : frame)
// Now you can call method
self.someMethod()
}
ADD for question's EDIT:
You can't call method before super.init()
call because of safety reasons. If you will do it then your method can use some properties which have not yet been initialized in the parent class
Swift. Use of 'self' in method call before all stored properties are initialized
You can't call methods on self before all non-optional instance variables are initialized.
There are several ways to go around that.
- Change properties to optionals or implicitly unwrapped optionals
(not recommended) - Make the
buildCircle()
method static or just a
function in the file and call theaddSubview()
for all the circles
after all of the properties were initialized and you calledsuper.init()
- etc. You just have to avoid calls to self before the
class was initialized.
Use of 'self' in method call 'f' before all stored properties are initialized
It doesn't mean that if you haven't written self
with function call f
then it will not reference to self
as of f
is still instance method, so with init
it must be called after all the instance properties are initialized means after the the instance of class is initialized. So simply call f()
after you initialized
the instance property a
.
class A {
var a: String
init(a: String) {
self.a = a
f()
}
func f() {
print("HeHe")
}
}
Use of self in method call before super.init initialises self
You are not calling super.init(frame:)
from your init(frame:viewController
method. It needs to be done between setting self.currentViewController
and calling setup
.
init(frame: CGRect, viewController: UIViewController) {
self.currentViewController = viewController
super.init(frame: frame)
setup()
}
You should read the Initialization chapter (especially the Class Inheritance and Initialization section) of the Swift book. Initialization of a class needs to be done in a clearly documented fashion.
How to set delegate to self inside init function?
The error message told you what needs to be done, you need to call super.init() in your init.
class MQTTController:NSObject, CocoaMQTTDelegate {
static let sharedInstance = MQTTController()
var clientID:String
var mqtt:CocoaMQTT
private override init() {
clientID = "xyz-" + String(ProcessInfo().processIdentifier)
mqtt = CocoaMQTT(clientID: clientID, host: "mqttcontroller.mqtt.net", port: 1883)
mqtt.username = "myusername"
mqtt.password = "mypassword"
mqtt.willMessage = CocoaMQTTWill(topic: "/will", message: "dieout")
mqtt.keepAlive = 30
mqtt.cleanSession = true
MQTTController.isConnecting = true
super.init() // This line was missing
mqtt.delegate = self
mqtt.connect()
}
}
Instantiate Self outside of init in Swift
You may use the (dynamically typed) metatype returned by type(of:)
to access an initializer of the concrete type of the metatype. Quoting the Language Reference - Metatypes
Use an initializer expression to construct an instance of a type from
that type’s metatype value. For class instances, the initializer
that’s called must be marked with therequired
keyword or the entire
class marked with the final keyword.
So in your case, you could use the metatype of self
to call a required
initializer of the concrete type of self
, e.g.
func myCustomCopy() -> Self {
return type(of: self).init()
}
Note that, as specified in the quote above, since you are working with a non-final class, the initializer must be a required
one.
Related Topics
Check Whether the Arreferenceimage Is No Longer Visible in the Camera's View
Receiving Data from Nsinputstream in Swift
How to Procedurally Draw Rectangle/Lines in Swift Using Cgcontext
Cannot Invoke "+=" with an Argument List of Type (Int, @Value Int)
Is There Difference Between Using a Constructor and Using .Init
Why Do We Need to Specify Init Method
Check If on Correct Dispatch Queue in Swift 3
How to Find a Maximum Value in a Swift Dictionary
How to Convert Unix Timestamp into Swift Nsdate Object
Swift Catch Enum Case with Binding
How to Display Mtkview with Rgba16Float Mtlpixelformat
How to Run the Simulator the Operation Couldn't Be Completed. (Launchserviceserror Error 0.)
Swift "Retry" Logic on Request
Structuring Data for Chat App in Firebase
Date/Time Natural Language Approximation in Swift
Which Measuring Unit Is Used in Scnvector3 Position for X, Y and Z in Arkit
Differences Between Ways of Initializing a Dictionary
Auth.Auth().Currentuser.Reload() Doesn't Refresh Currentuser.Isemailverified