initialize Swift Class variables in declaration or with init? - class

In Swift you can initialize a variable in a class when you declare the variable:
var name: String = "John"
or you can initialize with init:
var name: String
init(name: String) {
self.name = name
}
Which version do you use and when?

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.

Related

Conditional Defining a property in model object

I have a model object and there are some properties in that object. Based on some conditions, I want a property to be defined there or not to be defined. For example, this property is my app version.
class Person {
var name: String
var address: String
var age: String
// I want some condition here like if myAppVersion > 1.0 then add isChild
// property to my model object other wise don't add that
var isChild: Bool
// Normal property again
var gender: String
}
I want this behaviour because the properties are coming from the backend and all these properties are required, so if, for some reason, the BE doesn't send the a required property which the client is expecting, then I will crash. These properties have to be mandatory and not optional.
Don't do this.
Declare your parameter as an optional and set it to nil if you don't want it to have a value. You should create two separate classes if you want to have different implementations, but that would be pretty superfluous for just one little change.
If your application crashes just because a property has a nil value, you should really take a look at optional handling in Swift and nullability in Objective-C.

Swift static property initilizers are lazy why I could declared it as a constant

As far as I known (see reference A), Static property initilizers are lazy, and I found the following description by the office documents
You must always declare a lazy property as a variable (with the var
keyword) because its initial value might not be retrieved until after
instance initialization completes. Constant properties must always
have a value before initialization completes, and therefore cannot be
declared as lazy.
From the above information, I think I couldn't define the static property as a constant variable and I made a tryout, it turns out I can do that without triggering any error from the compiler.
Example:
class Person {
static let firstNaID = "First Name"
static let lastNaID = "Last Name"
}
Question: Is this a bug of the Swift 3.0.1 or I was wrong.
Reference A: Neuburg. M.2016. IOS 10 Programming Fundamental with Swift. P127
Thanks for your time and help
Neuburg M. is drawing a distinction between static properties and instance properties. You are pretending to ignore that distinction. But you cannot ignore it; they are totally different things, used for different purposes.
In this code:
class Person { // let's declare a static property
static let firstNaID = "First Name"
}
... firstNaID is already lazy. But now try to do this:
class Person { // let's declare an instance property
lazy let firstNaID : String = "First Name" // error
}
You can't; as things stand (up thru Swift 3.1), you have to say lazy var instead — and when you do, you get a lazy instance property.
Your static let declaration thus doesn't accomplish what lazy let wanted to accomplish, because a static property is not an instance property.
You are talking about type properties
Form the same chapter of the documentation
Type Properties
... Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use ...
Stored type properties can be variables or constants. Computed type properties are always declared as variable properties, in the same way as computed instance properties.
NOTE
...
Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they do not need to be marked with the lazy modifier.

Why do I use Initializers in Swift?

I am trying to get my head around initializers in Swift. I kind of get what they do, but I dont get why I need them.
For example: (from apples documentation)
class NamedShape {
var numberOfSides = 0
var name: String
var sideLength: Double
init(name: String, sideLength: Double) {
self.name = name
self.sideLenght = sideLength
}
}
If init should set an initial value, shouldn't self.sideLength equals an actual value, instead of just "sideLength". Or do I need to create an init to take in arguments to a function?
I'm so confused but would really appreciate if someone could help me.
The main purposes of initialisers is to initialise non-Optional variables. Your class has three variables - numberOfSides, name and sideLength. You give numberOfSides an initial value of zero, so it is happy. However, name and sideLength do not have values, which is "illegal" for a non-Optional. Therefore they must be given values in an initialiser. For example, if you comment out one of the lines in the init, you will get a compilation error because that variable will now not be initialised. And you do this when you cannot logically determine initial values at compile time - you could argue this is the case with numberOfSides too, as there is no shape that has no sides.
Elsewhere in your code you might want to validate numberOfSides is at least 1. This could be achieved by having numberOfSides undefined at compile time, and passed in the init, whereby if it's not at least 1, your initialiser could return nil (which would mean using an failable initialiser - init?).
Note that in your case, the name passed in the initialiser, is not the same as the name variable in the class. This is why you have to do:
self.name = name
To copy the name value passed in the initialiser into the variable in the class.

Swift: get the compile time name of variable (referencing to a class)

Is there a way to get the compile time name of a variable in Swift 2?
I mean the first variable name, which references to a new class instance, if any.
Here is a simple example:
public class Parameter : FloatLiteralConvertible {
var name:String?
var value:Double
// init from float literal
public required init (floatLiteral value: FloatLiteralType) {
self.value = Double(value)
self.name = getLiteralName()
}
func getLiteralName () -> String {
var literalName:String = ""
// do some magic to return the name
return literalName
}
}
let x:Parameter = 2.0
print(x.value) // this returns "2.0"
print(x.name!) // I want this to return "x"
I've already checked similar questions on that topic handling mirroring or objective-c reflections. But in all those cases, one can get only the property names in a class - in the example above name and value.
The same question has been asked in 2014 - Swift: Get Variable Actual Name as String
- and I hope, that since then there is a solution in swift 2.
No, there is no way to do that.
You have to understand that in the compiled state that variable usually does not exist. It can be optimized out or it is represented only as an item on the execution stack.
Even in languages with much better reflection that Swift has, usually you cannot inspect local variables.
To be honest, getting the name of a local variable dynamically has no practical use case.

Why do I need to declare an optional value as nil explicitly in Struct - Swift

Here's a quote from the docs:
If your custom type has a stored property that is logically allowed to have “no value”—perhaps because its value cannot be set during initialization, or because it is allowed to have “no value” at some later point—declare the property with an optional type. Properties of optional type are automatically initialized with a value of nil, indicating that the property is deliberately intended to have “no value yet” during initialization.
If I do this with a class it works fine:
class MyClass {
var someProperty: String?
}
var myClass = MyClass()
myClass.someProperty // Shows nil
However, if I do this with a struct type, I get an error on initialization:
struct MyStruct {
var someProperty: String?
}
// ERROR
var myStruct = MyStruct()
Error:
Missing argument for parameter 'someProperty'
I can remedy this by declaring it nil explicitly like so:
struct MyStruct {
var someProperty: String? = nil
}
// Valid
var myStruct = MyStruct()
Question
Given the documentation, I would expect properties on any type that are set as optionals to be defaulted to nil. Is there a reason I have to declare it explicitly on a struct?
Why?
No good reason, like many of you, I'm just experimenting.
Both Classes and Structs need to have all property values set when they are initialized. This can be done either through explicit default values or by setting a value in the designated initializer.
However, Structs differ in the fact that they have an automatically generated memberwise initializer.
When you don't define a value for someProperty explicitly, your struct has one initializer only: the automatically generated memberwise one.
If you do provide a default value, you get two: one that takes no arguments, and one that takes a value for someProperty as an argument
From the docs:
All structures have an automatically-generated memberwise initializer,
which you can use 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:
let vga = Resolution(width: 640, height: 480)
Unlike structures, class instances do not receive a default memberwise
initializer. Initializers are described in more detail in
Initialization.
I agree this is rather quirky (unless I'm also missing something). For structures with only optionals, it might be worth suggesting (via Apple bugreport) that in such cases, a default parameterless initialiser is also added by default?
Another remedy is
var myStruct = MyStruct(someProperty:nil)
However, if you had a lot of optional members, this becomes clumbsy.
I think this is an deliberate difference between structs and classes, which makes a bit of sense. For example when you have a struct, say a 3d point with three floats for XYZ. It doesn't make much sense to have a nil value for x or y or z. With a class on the other hand this is a very important feature. If you think about a downloader class, for example, that goes and downloads a text file and stores it in a property. It makes more sense for that property to be nil when the class is first initialized. Since apple has changed structs to be much more closely related to classes I think this is an important distinction. It's my opinion that setting the optional explicitly to nil is a bug.
My reasoning for this:
In the optional documentation all of the example are on classes.