I want to initialize every time a struct with dictionaries. Later, I'm going to use its properties instead a dictionary's keys and values - it seems rather easier. However, when I try the code below, it tells me that "Return from initializer without initializing all stored properties" and "1. 'self.one' not initialized" and "2. 'self.two' not initialized". My question is how to initialize a struct from a dictionary, so that I have basically a struct with the contents of the dictionary? Or how to transform it into struct?
struct Blabla {
var one: String
var two: [Int]
init(three: [String: [Int]]) {
for i in three {
self.one = i.key
self.two = i.value
}
} ERROR! - Return from initializer without initializing all stored properties
}
struct Blabla {
var one: String
var two: [Int]
init(three: [String: [Int]]) {
one = ""
two = []
for i in three {
self.one = i.key
self.two = i.value
}
} ERROR! - Return from initializer without initializing all stored properties
}
for in clause may have zero runs, in which case struct properties will not be initialized. You have to provide default values (or emit fatalError if you really need to).
While I think your example is pure synthetical, there is no need to loop through array, you can set properties to its last entry.
The issues is that if three is an empty Dictionary, the instance properties one and two don't get initialised. Also, you are overwriting the properties in each iteration of the for loop and the compiler cannot guarantee that there will be any iterations of the loop in compile-time, hence the compiler error.
You could make the initialiser failable to account for this by checking that the dictionary actually contains at least one key-value pair and assigning that first key-value pair to your properties.
struct Blabla {
var one: String
var two: [Int]
init?(three: [String: [Int]]) {
guard let key = three.keys.first, let value = three[key] else { return nil }
one = key
two = value
}
}
However, you should rethink what it is that you are actually trying to achieve, since with your current setup you have a mismatch between your init input values and the properties of your struct.
This code should compile, but it feels unsafe to me to initialize a Struct in this way because:
It assume your dictionary has values in it.
Your stored properties will always have the last value you looped through.
In order to pull values out to satisfy the compiler you need to force unwrap them. (With Dávid Pásztor's guard-letting approach, this can be avoided)
struct Blabla {
var one: String
var two: [Int]
init(three: [String: [Int]]) {
self.one = three.keys.first!
self.two = three[three.keys.first!]!
}
}
let input = ["pizza": [1,2]]
let l = Blabla(three: input)
If I were you I would let the memberwise initializer that you get for free do its thing and provide either a specialized initializer to handle your case of taking a Dictionary as input or move that parsing to another function/class/etc....
The compiler error is clear: If the dictionary is empty the struct members are never initialized. But the code makes no sense anyway as each iteration of the dictionary overwrites the values.
Maybe you mean to map the dictionary to an array of the struct
struct Blabla {
let one: String
let two: [Int]
}
let three = ["A":[1,2], "B":[3,4]]
let blabla = three.map{Blabla(one: $0.key, two: $0.value)}
print(blabla) // [Blabla(one: "A", two: [1, 2]), Blabla(one: "B", two: [3, 4])]
struct blabla{
var a : string
var b : [int] = []
init(_ data: [string:[int]]){
// whatever you want to do
}
}
Hello I have an optional variable which uses the willset functionality. Since its an optional the regular set will not work. inside the will set I am setting the variable to at least initialize it if the new value is nil. unfortunately, the value after is nil as well any ideas? Thank you
Code:
var arrayOfString: [String]? {
willSet {
self.arrayOfString = newValue == nil ? [String]() : newValue
}
}
Since its an optional the regular set will not work
Not correct. Since it's not a computed property set will not work.
You need to reread the section about willSet and didSet. willSet is called before any value is written to the variable. I.e. whatever you write to the variable inside willSet will be overwritten immediately by the assignment that invokes your code.
If you assign nil you will overwrite your string array with nil.
Simplify by just doing
var arrayOfString: [String] = []
You need to use didSet:
var arrayOfString: [String]? {
didSet {
self.arrayOfString = arrayOfString ?? []
}
}
Otherwise the value is immediately overwritten by the original value.
However note that if the variable should never contain an optional, it should be declared as such:
var arrayOfString: [String]
and the assignment should add the ?? [] when needed.
Otherwise you will have to handle unwrapping everytime you access the value anyway.
I'm new to Swift and is trying to learn its syntax. I saw this code online.
var items = [Int]()
I know
var = declaring a variable
items = the name of the variable is 'items'
[Int] = array of Int
However, I'm not sure the purpose of the () after [Int]. I know the code wouldn't compile without the (), but what is its purpose?
It is initializing a new instance of an Array that will contain Ints. It is a shorthand of this syntax:
var items = Array<Int>()
Instead of Array<Int> for the type you can use [Int] instead.
A third variation would be to explicitly state the type, and then assign an empty array.
var items: [Int] = []
What is wrong here and how to solve this problem?
struct Venue {
let building: String
var rooms: [String]?
}
func addRoom(building: String, room: String) {
if let venueIndex = find(venues.map {$0.building}, building) {
venues[venueIndex].rooms.append(room) //Cannot invoke 'append' with an argument list of type'(String)'
}
}
var venues: [Venue] = [...]
The problem is that venues[venueIndex].rooms is not a [String] but a [String]?. Optionals don’t have an append method – the value wrapped inside them might, but they don’t.
You could use optional chaining to do the append in the case where it isn’t nil:
venues[venueIndex].rooms?.append(room)
But you may instead want to initialize rooms to an empty index instead when it is nil, in which case you need to do a slightly messier assignment rather than an append:
venues[venueIndex].rooms = (venues[venueIndex].rooms ?? []) + [room]
However, it is worth asking yourself, does rooms really need to be optional? Or could it just be a non-optional array with a starting value of empty? If so, this will likely simplify much of your code.
I looked through docs some forums and found I can create an array in various ways. I am confused which one should we be using?
var testArray = [Int]()
testArray.append(1)
var anotherTestArray: [Int] = []
anotherTestArray.append(1)
var yetAnotherTestArray: Array<Int> = []
yetAnotherTestArray.append(1)
var yetYetYetAnotherTestArray = Array<Int>()
yetYetYetAnotherTestArray.append(1)
This is not empty array but It keeps it's type for each element to be strictly to an Int
var yetYetAnotherTestArray = [1]
I think the cleanest way to create an array is var testArray: [Int] = []
In swift array objects must be the same type. If you want to store different objects of different types use [AnyObject]. However, you should always know what is coming out of it. Since the returning type value will be AnyObject, you have to cast down the value to the type you want.
I really don't recommend using AnyObject as the type of your arrays unless you really know what you are doing.
Here is an example anyway:
let a: [AnyObject] = [1, "a"]
let b = a[0] // An Int
let c = a[1] // A String