What's "init" used for in swift? - swift

Is there difference ? And the effect of deinit ?
struct mark {
var mark: Int
}
struct mark {
var mark: Int
init(mark: Int) {
self.mark = mark
}
}

init is used to set initial values for properties on a struct or class type at the time it is created, before any other methods may be called on it and before it is passed as a parameter to other functions or methods.
In Swift, any non-optional properties must be set with initial values before init returns. Properties may be declared with initial values already, which excludes them from having to be set in an init method.
class types must have an init method implemented if there are any non-optional properties not already declared with initial values.
For struct types only, Swift will automatically generate an init method with parameters for each non-optional property that was not already declared with an initial value. You can optionally create any number of alternative init methods for the struct, as long as by the time each one returns, all non-optional properties have a value.
In your example, there is no difference between the init method created on the second line, and the automatically created init method provided for that struct type by Swift. But you could create alternate initializers that, for example, take a Double instead of an Int and then convert it internally before setting the mark property.
I think the key point to realize is that even when you do not specify an init method yourself, one still exists, as created automatically by Swift for struct types. So in both line one and line two of your example, an init method is being called (and they are essentially identical implementations). The only difference is that you wrote the init implementation in the second line, and the Swift compiler writes the init method in the first line.
deinitonly exists for class types, which are passed by reference and have memory management. Any deinit method you declare on a class you create will be called when there are no more references to that instance of the class and it will be released from memory. It's used to deregister from various observation patterns or otherwise clean up right before the instance is destroyed.

Related

Error "Inout argument could be set to a value with a type other than ..." when passing in a protocol type

I am coming from C++ to Swift. I have this situation with respect to protocols and structs (I am working with random numbers):
(1) A protocol RandomPr that specifies there are methods such as randFloat() that returns a Float between 0 and 1.
(2) A struct RandomS that implements RandomPr using a "real" random number generator.
(3) A struct FakeRandomS that implements RandomPr, but has additional methods such as loadFloat() to load an array of Floats that are then regurgitated when I call randFloat() on a FakeRandomS instance. (For testing purposes.)
Now I have a function DoSomething(rng: inout RandomPr), which I want to use with both RandomS and FakeRandomS. The parameter has to be in-out as I need to update the RNG (whether it is real or fake). No problem calling DoSomething with an instance of RandomS.
But if I do
var fakeRng = FakeRandomS()
fakeRng.loadFloat([0.1, 0.2, 0.3])
DoSomething(rng: &fakeRng)
I get an error "Inout argument could be set to a value with a type other than 'FakeRandomS'. The suggested fix is to define fakeRng as
var fakeRng: RandomPr = FakeRandomS()
But now trying to call loadFloat on fakeRng fails because RandomPr doesn't have a method loadFloat, and the compiler doesn't see that fakeRng does have one.
I tried making another protocol FakeRandomPr that contains the extra methods that FakeRandomS has, and defining
var fakeRng: RandomPr & FakeRandomPr = FakeRandomS()
but, frustratingly, I now get the "Inout argument could be set to a value with a type other than ..." error back again.
I could do the equivalent of this in C++ without problems (a pure abstract base class and two child classes, passed in by reference), and it didn't matter that one of the things I wanted to pass in has extra methods. I want to translate this into protocols and structs. What is the Swift solution?
What is the Swift solution?
You may need to use generics:
func doSomething<RP: RandomPr>(rng: inout RP) {
//...
}
Swift is not just another syntax of C++, better think in Swifty way.

Argument labels for initialization parameters in Swift 3.1

Apple's book "The Swift Programming Language (Swift 3.1)" states the following:
As with function and method parameters, initialization parameters can have both a parameter name for use within the initializer’s body and an argument label for use when calling the initializer.
However, initializers do not have an identifying function name before their parentheses in the way that functions and methods do. Therefore, the names and types of an initializer’s parameters play a particularly important role in identifying which initializer should be called. Because of this, Swift provides an automatic argument label for every parameter in an initializer if you don’t provide one.
I don't understand the last sentence, as I didn't notice any difference between functions/methods and initializers when it comes to parameters names/labels. How is the argument label automatically provided for an initializer?
The feature being described is this: Given a struct:
struct Point {
let x: Double
let y: Double
}
Swift will automatically generate Point.init(x: Double, y: Double). If you add an init method of your own in the main struct definition, then Swift won't create that automatic init. (If you add an init in an extension, then you will get an automatic init. This is why people often add convenience init in an extension for structs.)
The point the last paragraph is trying to make is that Point(x:y:) is preferable to Point(_:_:). The labels in an initializer are even more valuable than labels in method names, because all initializers have the same "base" name ("init"). They're just explaining why they didn't choose a more implicit default that some people might expect coming from other languages.
In short, sometimes unlabeled parameters make sense in methods depending on what the name of the method is and how unambiguous that makes the first parameter. But in init, unlabeled parameters should be eyed with strong suspicion.

How Do Custom Initializers Actually "Initialize"?

Learning Swift at the moment and it is my first time learning to code as well. I am studying initializers at this point and I am stuck at the idea of custom initializers.
Looking at the code below, I am really not sure how this actually initializes the instances. Isn't setting the value of a property equal to an uninitialized instance just going to result in another un-initialized property?
init (region: String, population: Int, stopLights: Int) {
self.region = region
self.population = population
numberOfStoplights = stopLights
}
Any help is appreciated. Thanks!
init is invoked after memory for your object (struct or class instance) is allocated. At that time the object exists but its fields (member variables) contain unknown (undefined) values.
Swift, for safety and for type consistency, never allows access to undefined values. So you must assign a value to every field of your object in init, even if that is just some "default" value. Optional fields are initialized with nil.

Why do the variables need to be initialized in class in swift but they don't need to be initialized in struct?

Im new to learn swift.I recently found that the variables or constants are needed to be initialized with an initial number or by the initializer.But in struct they don't need to be initialized?
They do need.
From the Swift Language Guide:
Classes and structures must set all of their stored properties to an
appropriate initial value by the time an instance of that class or
structure is created. Stored properties cannot be left in an
indeterminate state.
You can set an initial value for a stored property within an
initializer, or by assigning a default property value as part of the
property’s definition.
Source: Initialization
An example to #vadian 's answer:
struct S {
init() {}
let a: String
}
This will not compile:
Playground execution failed: Test.xcplaygroundpage:11:13:
error: return from initializer without initializing all stored properties
init() {}
^

Why is 'init' not assignable?

I just read that the init method can't be used as a value. Meaning:
var x = SomeClass.someClassFunction // ok
var y = SomeClass.init // error
Example found on Language reference
Why should it be like that? Is it a way to enforce language level that too dirty tricks come into place, because of some cohertion or maybe because it interferes with another feature?
Unlike Obj-C, where the init function can be called multiple times without problems, in Swift there actually is no method called init.
init is just a keyword meaning "the following is a constructor". The constructor is called always via MyClass() during the creation of a new instance. It's never called separately as a method myInstance.init(). You can't get a reference to the underlying function because it would be impossible to call it.
This is also connected with the fact that constructors cannot be inherited. Code
var y = SomeClass.init
would also break subtyping because the subtypes are not required to have the same initializers.
Why should it be like that?
init is a special member, not a regular method.
Beyond that, there's no reason that you'd ever need to store init in a variable. The only objects that could use that function in a valid way are instances of the class where that particular init is defined, and any such object will have already been initialized before you could possibly make the assignment.
Initializers don't have a return value. In order to assign it to something, it should be able to return something - and it doesn't.