Swift Variable Declaration and Initialize

Swift Variable Declaration and Initialize

This one:

let x: Int = 4

creates a non-optional variable x and initialises it to 4. x can be used without issue.

This one:

let x: Int
// Cannot do anything with x yet
x = 4

creates a non-optional variable x with no defined value. It cannot be used without first assigning it to a value, either directly (as in your example) or by the result of some other statement. If you do try and use it, you'll get a compile-time error.

Swift Variables Initialization

Actually you have 5 ways to initialize properties.

There is no correct way, the way depends on the needs.

Basically declare objects like UILabel always – if possible – as constant (let).

The 5 ways are:

  • Initialization in the declaration line

    let label = UILabel(frame:...
  • Initialization in the init method, you don't have to declare the property as implicit unwrapped optional.

    let label: UILabel
    init() { ... label = UILabel(frame:...) ... }

The first two ways are practically identical.

  • Initialization in a method like viewDidLoad, in this case you have to declare the property as (implicit unwrapped) optional and also as var

    var label: UILabel!

    on viewDidLoad()
    ...
    label = UILabel(frame:...)
    }
  • Initialization using a closure to assign a default (computed) value. The closure is called once when the class is initialized and it is not possible to use other properties of the class in the closure.

    let label: UILabel = {
    let lbl = UILabel(frame:...)
    lbl.text = "Foo"
    return lbl
    }()
  • Lazy initialization using a closure. The closure is called (once) when the property is accessed the first time and you can use other properties of the class.

    The property must be declared as var

    let labelText = "Bar"

    lazy var label: UILabel = {
    let lbl = UILabel(frame:...)
    lbl.text = "Foo" + self.labelText
    return lbl
    }()

How properly declare a variable in Swift?

Method 1 is a standard variable declaration for a String. It has a setter and a getter

var dogName: String = "Charlie"

print(dogName) -> "Charlie"
dogName = "Rex" // Valid

Method 2 is a computed property of type String and is read-only

var dogName: String {
return "Charlie"
}

print(dogName) -> "Charlie"
dogName = "Rex" // Invalid as property is read-only

Method 3 is a read-only property of type () -> String, so basically a lambda function.

let dogName = {
return "Charlie"
}

print(dogName) -> "(Function)"
print(dogName()) -> "Charlie"
dogName = "Rex" // Invalid as property is read-only

Method 4 is a closure that will be executed when the containing object is initialised. As it is a var you can replace it with another value

var dogName: String = {
return "Charlie"
}()

print(dogName) -> "Charlie"
dogName = "Rex" // Valid

That being said, as Method 4 is a closure, you can execute other commands in it. Here is an example where you could use this construct to initialise a UILabel:

var dogNameLabel: UILabel = {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
label.text = "Charlie"
return label
}()

How to initialize a variable, but once done, its value is final

Based on Babul Prabhakar answer, but a bit more clean.

Approach 1:

var test: String? { didSet { test = oldValue ?? test } }

test = "Initial string"
test = "Some other string"
test = "Lets try one last time"

print(test) // "Initial string"

Edit: made it shorter

Approach 2:

let value: String
value = "Initial string"

I guess the second approach is the "built-in" option of Swift to declare a variable once. This is only possible when the variable is assigned right after the declaration though.

Initialize a swift variable without knowing the type

You should use definitely use an enum with associated values here. As Schottky said in their answer, you'll need a custom Codable implementation. Here's an example, implementing just 4 of the cases, assuming that User, Badge, Message, Debate are all Codable.

enum UserNotification: Codable {
case getBadge(Badge)
case groupReply(Message, Debate, Message)
case levelUnlock(User)
case userFollowLevelUnlock

var notifyType: String {
switch self {
case .getBadge:
return "get_badge"
case .groupReply:
return "group_reply"
case .levelUnlock:
return "level_unlock"
case .userFollowLevelUnlock:
return "user_follow_level_unlock"
}
}

enum CodingKeys: String, CodingKey {
/*
When decoding/encoding, use convertFromSnakeCase/convertToSnakeCase to convert the key names to/from snake case
No need to hard code them here
e.g.
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
*/
case notifyType
case target
case secondTarget
case thirdTarget
}

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(notifyType, forKey: .notifyType)
switch self {
case .getBadge(let badge):
// you can also encode the unused targets here if your backend needs them
try container.encode(badge, forKey: .secondTarget)
case .groupReply(let msg1, let debate, let msg2):
try container.encode(msg1, forKey: .target)
try container.encode(debate, forKey: .secondTarget)
try container.encode(msg2, forKey: .thirdTarget)
case .levelUnlock(let user):
try container.encode(user, forKey: .target)
case .userFollowLevelUnlock:
break // nothing more to encode in this case
}
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
switch try container.decode(String.self, forKey: .notifyType) {
case "get_badge":
self = .getBadge(
try container.decode(Badge.self, forKey: .secondTarget)
)
case "group_reply":
self = .groupReply(
try container.decode(Message.self, forKey: .target),
try container.decode(Debate.self, forKey: .secondTarget),
try container.decode(Message.self, forKey: .thirdTarget)
)
case "level_unlock":
self = .levelUnlock(
try container.decode(User.self, forKey: .target)
)
case "user_follow_level_unlock":
self = .userFollowLevelUnlock
default:
throw DecodingError.dataCorruptedError(forKey: .notifyType, in: container, debugDescription: "Unknown notifyType")
}
}
}

This way, the notification property can just be:

private var notification: UserNotification

and setResource is trivial.

Can I Declare and initialize multiple variables in one line with a tuple?

func getImagesTuple(from array: Array<String>) -> (UIImage, UIImage, UIImage) {
(UIImage(named: array[0])!, UIImage(named: array[1])!, UIImage(named: array[2])!)
}

let (imageOne, imageTwo, imageThree) = getImagesTuple(from: ["imageOne", "imageTwo", "imageThree"])

initialize Swift Class variables in declaration or with init?

Unless you are providing the initial value as an initializer parameter, for which you have for obvious reasons do that in the initializer, you can use any of the 2 ways.

My rules are:

  • if there are several initializers, and the property is initialized with the same value in all cases, I prefer inline initialization
  • if the property is (or should be) immutable, I prefer inline initialization
  • if the property can change during the instance lifetime, I prefer constructor initialization

but besides the first one, the other 2 are just based on personal preference.

How to declare but not initialize a property in a Swift class

Create an implicitly unwrapped optional - this will act like a normal variable but it does not need to be initialised - its initial value is nil. Just ensure the value is set before it is used otherwise you will get a fatal error for unwrapping nil.

class car {
var oneWheel: Wheel!

func run(inputWheel: Wheel) {
wheel = inputWheel
}
}


Related Topics



Leave a reply



Submit