Default Initializer in Swift

Default Initializer in swift

Chances are it's an issue with the Swift compiler and access control (not pointing fingers, just trying to troubleshoot). Add an explicit initializer to the class and see if that works:

class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false

init() { }
}

If that doesn't work, then set the class to public, along with the initializer

    public class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false

public init() { }
}

Swift how to make the default initializer of a `struct` private

If you are noticing that implementing:

struct Foo {
let bar: String
static let sharedInstance = Foo(bar: "blah")
}

is legal even without giving bar an initial value, why? because Swift Structs have a default initializer, called the memberwise initializer:

Structure types automatically receive a memberwise initializer if they
do not define any of their own custom initializers. Unlike a default
initializer, the structure receives a memberwise initializer even if
it has stored properties that do not have default values.

The memberwise initializer is a shorthand way to initialize the member
properties of new structure instances. Initial values for the
properties of the new instance can be passed to the memberwise
initializer by name.

Meaning that if you tried to create a new instance of Foo struct, the compiler should -automatically- provide:

Sample Image

However, you can get rid of it by implementing private init(), but you have to make sure that all stored properties have -dummy- initial values (or maybe let them optionals...) because the struct no longer has an initializer for guaranteeing that the stored properties has values.

It should be similar to:

struct Foo {
var bar: String = ""
static var shared = Foo()

private init() {}
}

Remark: I would suggest to stuck with class when implementing a singleton pattern, you might want to check this answer (Thanks to
MartinR for mentioning it).

Codable default values during initialization

Once you conform to Encodable, it's as if your class has explicitly declared a encode(to:) method and a init(from:) initialiser.

By declaring an initialiser with arguments, you immediately lose the default (parameterless) initialiser that the compiler generates for you when all properties have a default value. This is why you can't do KillSwitches(). This is stated in the documentation:

Swift provides a default initializer for any structure or class that
provides default values for all of its properties and does not provide
at least one initializer itself.
The default initializer simply
creates a new instance with all of its properties set to their default
values.

KillSwitches has a init(from:) initialiser already, so Swift doesn't provide the default initialiser.

You just have to add the parameterless initialiser in yourself:

class KillSwitches: Codable {

public enum CodingKeys: String, CodingKey {
case featureOne
case featureTwo
case featureThree
}

let featureOne: Bool = true
let featureTwo: Bool = true
let featureThree: Bool = false

init() { }
}

And then you can do:

let defaultKillSwitches = KillSwitches()

if you want the default values.

How to pass default value when initializing a struct in swift

You have to give all of the properties a valid before you can call methods. I would refactor your init to something like this:

init(header: String?, errorLocation: String?, userID: String?, description: String, errorMessage: String) {
self.header = header ?? " ::Error::"
self.errorLocation = errorLocation ?? ""
self.userID = userID ?? ""
self.description = " ::description::" + description
self.errorMessage = " ::errorMessage::" + errorMessage

if errorLocation == nil {
self.errorLocation = getErrorLocation()
}
if userID == nil {
self.userID = getUserID()
}
}

That will fix the "self used before all stored properties are initialized" error.

To use default values, update the signature:

init(header: String? = nil, errorLocation: String? = nil, userID: String? = nil, description: String, errorMessage: String) {
// nothing else changes
}

Now you can call the initializer without the nil parameters.

For example:

let logError = LogError(header: nil, errorLocation: nil, userID: nil, description: "An error occurred while verifying if the user profile exists", errorMessage: "\(error?.localizedDescription ?? "")")

becomes:

let logError = LogError(description: "An error occurred while verifying if the user profile exists", errorMessage: "\(error?.localizedDescription ?? "")")

How to automatically create an initializer for a Swift class?

Update As of Xcode 11.4

You can refactor (right-click mouse menu) to generate the memberwise initializer for class and struct.

Note that struct automatic initializers are internal. You may want to generate memberwise initializer when defining a module to make it public.

Right-click > Refactor > 'Generate Memberwise Initializer'

xcode generate memberwise initialization

For older Xcode

There are handy plugins:

https://github.com/rjoudrey/swift-init-generator https://github.com/Bouke/SwiftInitializerGenerator

iOS custom init issue, how to set the default init method?

Remove the other init that you implemented and set yours as required

class CustomLabel: UILabel {

required init(_ title: String = "Star"){
super.init(frame: CGRect.zero)
text = title
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

}

let label1 = CustomLabel()
print(label1)

This works and uses the expected init

EDIT:

Bastian provided a useful link in their answer but has since removed it.

The link: Adding Swift Convenience Initializers

Useful snippet from link (in case the link ever breaks):

Designated or Convenience?

First a recap on the two types of initializer:

A designated initializer is the primary initializer for a class. It
must fully initialize all properties introduced by its class before
calling a superclass initializer. A class can have more than one
designated initializer.

A convenience initializer is a secondary initializer that must call a
designated initializer of the same class. It is useful when you want
to provide default values or other custom setup. A class does not
require convenience initializers.

The Three rules

With that clear you need to remember three rules for designated and
convenience initializers for class types:

  • A designated initializer must call a designated initializer from the
    immediate superclass.
  • A convenience initializer must call another
    initializer from the same class.
  • A convenience initializer must
    ultimately call a designated initializer.

What does this mean for us?
In simple terms, do not call super from your convenience initializer.
Call another initializer (convenience or designated) from the same
class.

Optional and default values need to be initialized with default initializer

You can define an initializer with default values for some params

struct Token {
var a: Int
var b: Int
var c: Int?

init(a: Int, b: Int = -1, c: Int? = nil) {
self.a = a
self.b = b
self.c = c
}
}

Now you can create a Token in several ways

Token(a: 1) // (1, -1, nil)
Token(a: 1, b: 2) // (1, 2, nil)
Token(a: 1, c: 3) // (1, -1, 3)
Token(a: 1, b: 2, c: 3) // (1, 2, 3)

Usually is a good practice writing the default value of a property on the same line where it is defined (as you did). I moved the default value of b from it's definition to the init just to make this example shorter.



Related Topics



Leave a reply



Submit