How to only initialise some of the properties in a Swift class - swift

It's known that Swift compiler forces all the properties to be initialised in a constructer. However, sometimes I only want to have some of the properties to be initialised. Below is an example, I only have to use variable b in the second constructer and no need for the variable a but the complier is complaining "a is not initialised". I wonder how to deal with this case.
class aClass{
var a:String
var b:String
init(a:String){
self.a = "a"
}
init(a:String, b:String){
self.a = "a"
self.b = "b"
}
}

This is what optionals are for. your declaration of property b can change to var b: String?. This will make it so you don't have to give it a value in init. Then, when you want to use it, if let self.b = "my string" {...} or, if you know it has a value, you can force unwrap it: var myOtherString = b!.

Related

Why does Swift allow assigning a struct property to itself, but not a class property?

Swift has this awesome error that shows up when you try to do something of the form x = x:
class Foo {
var foo = 1
}
var a = Foo()
a.foo = a.foo // error
This helped me avoid typos where the class had two similarly named properties, and I want to assign one to the other, but mistakenly typed the same one twice.
However, in this particular case:
struct Foo {
var foo = 1 {
didSet {
print("Did set")
}
}
mutating func f() {
foo = foo
}
}
var a = Foo()
a.foo = a.foo
It successfully compiles! There isn't even an error on the foo = foo line! If I change Foo to a class, or if I remove the didSet, then the expected error appears. It's just this struct + didSet combination that makes the compiler think "yeah, a.foo = a.foo makes a lot of sense! Let me allow that!"
I found this related post, which is about how to stop getting this error, rather than how to get it.
I also looked on bugs.swift.org, but there were only 3 results, and none of them are related.
I'm using Swift 5.3.2 and Xcode 12.4.
Is there any reason why assigning a struct property to itself is more "OK" than assigning a class property to itself?

"Never" Type as Default Type for Multi-Generic Initialization

Problem
My goal is to somehow initialize a generic object similar to this:
struct SomeStruct<A, B> where A: View, B: View {
let a: A?
let b: B?
init(a: A? = nil, b: B? = nil) {
self.a = a
self.b = b
}
}
let someStruct: SomeStruct = .init(a: Color.red)
However, this snippet throws an error:
Generic Parameter 'B' Couldn't Be Inferred
Alternative #1: Diamond Notation
One alternative would be specifying Never type in a diamond notation:
let someStruct: SomeStruct<Color, Never> = .init(a: Color.red)
But this is a clunky solution as I don't want to pass types explicitly.
Alternative #2: Constrained Initializers
Another wordy alternative is writing custom initializers, omitting each type by specifying Never type:
struct SomeStruct<A, B> where A: View, B: View {
let a: A?
let b: B?
}
extension SomeStruct where A == Never {
init(b: B) {
self.a = nil
self.b = b
}
}
extension SomeStruct where B == Never {
init(a: A) {
self.a = a
self.b = nil
}
}
extension SomeStruct where A == Never, B == Never {
init() {
self.a = nil
self.b = nil
}
}
let someStruct: SomeStruct = .init(a: Color.red)
But as you can see, this requires a lot of repetitive code. So if I have an object of 10 generic types, this can become a mess.
Question
In short, I am looking for a way to retain a simple initializer, as shown in Problem section. Is there a way to provide a default type to a parameter (Never), as you would usually provide a default value to that parameter?.
This is not a solution, but rather Combine patterns reuse (as done by Apple SDK itself) ...
Instead of
let someStruct: SomeStruct<Color, Never> = .init(a: Color.red)
I would propose to use
let someStruct = SomeStruct<Color, Never>(a: Color.red)
as this is widely used notation by Apple itself, like AnySubscriber<Color, Never>, AnyPublisher<Color, Never>, etc.
let subject = CurrentValueSubject<CGFloat, Never>(0) // exactly your case
Note: for 10 types look at ViewBuilder
Is there a way to provide a default type to a parameter (Never), as
you would usually provide a default value to that parameter?
No. But everybody wants it (I asked them), and although there has been activity on the Swift forum about it, it hasn't come to pass yet.
Example thread:
https://forums.swift.org/t/draft-allow-default-value-for-parameters-in-generic-clause/11200
So if I have an object of 10 generic types, this can become a mess.
Aye, this is the state of things. Your problem, and lack of variadics, are the big ones.

Whether to use var or let during instances creation in Swift?

What should be used to create the instances of classes in Swift and why?
please explain the usage of let and var during the instances creation in Swift
below is the code :-
class ConstantTest{
let constant: String
init(constant: String) {
self.constant = constant
}
func printConstant() {
print(constant)
}
}
let constanttest = ConstantTest(constant: "Hello")
constanttest.printConstant()
var test = ConstantTest(constant: "Hie")
test.printConstant()
Use let if:
it is a constant (or in the case of reference types like class, if the reference cannot be replaced with another reference); and
you're able to set it during the initialization process.
But if you need to be able to change it at a later point, use var, such as true variables whose values are not constant (or in the case of reference types, if you need to replace it with another instance). But variables and properties whose values are not set during the initialization process, you have to use var. For example, lazy stored properties use var because their value is not set when the initialization process completes, but only when you first reference it. Another example includes view controllers' references to their outlets that are hooked up only when the view hierarchy is created at a later point.
Needless to say, computed properties use var, too.
But, if you can use let, you should do so, as it's easier to write safe code if you know what is a constant and what is a variable. In your example, you'd use let.
Note: In the case of reference types, like class types, let does not mean that that the object itself is necessarily immutable, merely that you cannot replace it with another instance. If you want to enjoy control over whether it's immutable or not, consider using a value type (e.g. a struct).
Let me see if I can make that final note more clear. Consider:
class Foo {
var value: String
init(value: String) {
self.value = value
}
}
Then the following is permitted:
let obj = Foo(value: "a")
obj.value = "b" // changing mutable property of reference type, Foo, is permitted
But the following is not:
let obj = Foo(value: "a")
obj = Foo(value: "b") // replacing `obj` with a new instance of `Foo`, is not
If you don't want to be able to change value property, you can define value to be immutable (or at least, not publicly mutable), e.g.:
class Foo {
let value: String // or `private(set) var value: String`
init(value: String) {
self.value = value
}
}
Or don't define Foo as class (a reference type) and instead define it to be a struct (a value type):
struct Foo {
var value: String
init(value: String) {
self.value = value
}
}
let obj = Foo(value: "a")
obj.value = "b" // this is not permitted, because Foo value-type, `obj`, was declared with `let`, making it immutable
Note, that final example, declaring Foo as a value type (a struct) does change it fairly fundamentally, e.g.
var obj1 = Foo(value: "a")
var obj2 = obj1 // this value is a copy of `obj1` not a reference to the same object that `obj1` pointed to
obj1.value = "b"
print("\(obj1.value)") // will print "b"
print("\(obj2.value)") // will print "a"
But value types, while it requires a slightly different mindset to use them, are incredibly useful for easily writing safe code. See WWDC 2015 Building Better Apps with Value Types in Swift.
There are varying reasons to use each. The simplest way to explain this is that let is for defining constants, while var is for defining variables. When using let the value cannot be changed. So in your application if you need a value that can be changed, use var. As well you might think of searching for your answer, as there are many duplicates of this question.
Source: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html

Recursive type definitions in Swift

I have encountered what would seem like an extremely simple issue to solve, and I think I may be missing something.
The program crashes when attempting to create a recursive variable (?) with the typed to a class while being a member of the said class. For example:
class A {
var x: A
init() {
x = A()
}
}
Checking the crash log suggests a recursion of sorts, with init() being called infinitely.
Is there a proper method/syntax to solve this sort of problem, given that I need the variable x to be typed to class A, and the initializer must initialize variable x to class A?
It's obvious that at some step you should left property x uninitialized. So, thats better to declare it as Optional, and initialize it after instance was created:
class A {
var x: A?
}
let mainObject = A()
let nestedObject = A()
mainObject.x = nestedObject
Not sure but i think you are looking for this
class A {
var x: A?
init() {
}
anothermethod() {
x = A()
}
}
and you can call this method like
let a = A()
a.anothermethod()

Swift - Pointer to a Pointer

I'm trying to figure out how to create a pointer to a pointer in Swift. Now, I know we don't exactly have pointers in Swift, but here is what I am trying to accomplish:
var foo = objA() //foo is variable referencing an instance of objA
var bar = foo //bar is a second variable referencing the instance above
foo = objA() //foo is now a reference to a new instance of objA, but bar
//is still a reference to the old instance
I would like to have bar be a reference to the foo variable instead of it being a reference to the foo object. That way, if foo becomes a reference to a different object, bar goes along for the ride.
One way of having a secondary reference to a variable would be a computed variable:
class C {}
var a = C()
var b: C { return a } // b is a computed variable, returning the current value of a
b === a // true
a = C()
b === a // true, whereas "var b = a" would have made this false
I believe this is what you want:
class O {
let n: Int
init(n: Int) { self.n = n }
}
var foo = O(n: 1)
var bar = withUnsafePointer(&foo) {$0}
print(bar.pointee.n) // Prints 1
foo = O(n: 2)
print(bar.pointee.n) // Prints 2
(Replace pointee with memory for Swift < 3.0)
I really don't know why you'd want that though.
You can try to use UnsafeMutablePointer. See an example below:
let string = UnsafeMutablePointer<String>.alloc(1)
string.initialize("Hello Swift")
print(string.memory)
let next = string
next.memory = "Bye Bye Swift"
print(string.memory) // prints "Bye Bye Swift"
But it smells a little and It will be better to avoid using technique like this.