How to initialize OrderedDictionary - Swift Collections - swift

Reading from the github docs I can see how to use it, but when I try to initialize it (to empty):
var responses: OrderedDictionary = [:]
it says: Empty collection literal requires an explicit type
I tried this:
var responses: OrderedDictionary<String: <TransactionsDataItemsClassAModel>> = [:]
but doesn't work, what's the proper way to initialize this?
This is how I have initialized my non ordered diccionary:
var dataDiccionary: [String: [TransactionsDataItemsClassAModel]] = [:]
Thanks

The regular syntax for generic types is like Array<T> and Dictionary<K, V>
There's short-hand syntax specific to Array and Dictionary: [T] and [K: V].
You're confusing some things and combined the two into an an invalid middle-ground.
OrderedDictionary doesn't have any special short-hands, so you would just treat it like any other generic type. The generic type parameters are specified with a comma separated list:
OrderedDictionary<String, [TransactionsDataItemsClassAModel]>

Related

What does the parentheses mean in this var declaration?

I'm new to Swift and I just saw this declaration:
var completionHandlers = [(String) -> Void]()
As far as I know, this line is declaring an array of closures of type (String) -> Void, but I'm not sure of what the parentheses mean there.
[MyType]() is just syntactic sugar for Array<MyType>(), which itself is syntactic sugar for Array<MyType>.init(). It initializes an empty array of MyTypes.
It gets its own special syntax because Array is such a common data type.
Dictionary also has syntactic sugar in the style of [String: MyType](), for example.
The parenthesis is a way of calling the initialiser.
This is equivalent to:
var completionHandlers: [(String) -> Void] = []
Another way you will see it is:
var completionHandlers: [(String) -> Void] = .init()
You see it when initialising empty collections because if, for example you had:
var someVariable = ["hello", "world"]
The compiler would be able to infer the type of someVariable to be [String] because it knows the type of the contents. but You can't initialise an empty array like this because there is no information about the type. so [(String) -> Void]() is a way of providing the type to the empty initialiser.
The general recommendation in Swift is to use Type Inference where the type of the variable is inferred from it's initial value:
let intVariable = 3
let stringVariable = "Hello"
//etc
The style of code in your question follows this.
But in some cases with more complex types this can slow down the compiler, so many people are more explicit with their variable declarations.
let intVariable: Int = 3
let stringVariable: String = "Hello"
It's a matter of taste (and argument).

Is there any way in Swift to define a collection which holds elements with different data types?

In my specific case, I want something like:
var collectionWithDifferentTypes: [ObservableObject] = []
var elementOfTypeAWhichConformsToObservableObject = TypeA()
var elementOfTypeBWhichConformsToObservableObject = TypeB()
collectionWithDifferentTypes.append(elementOfTypeAWhichConformsToObservableObject)
collectionWithDifferentTypes.append(elementOfTypeBWhichConformsToObservableObject)
But letting arrays conform to ObservableObject is not possible. As the docs state, arrays, sets, and dictionaries can only contain elements of the same type. Is there any way in swift to have a collection similar to the one I've described above?
The reason you are getting this error is that ObservableObject specifies an associated type ObjectWillChangePublisher that has to be defined in classes that conform to the protocol. There's an annoying trait of Swift that any protocol that specifies an associated type can't be used as a generic parameter since the runtime needs to know how the associated type is defined in order to effectively use it.
In order to use such a protocol as a generic type, you have to do what the error message specifies and use it as a generic constraint. That means that wherever you are defining the array has to be made into a generic context using ObservableObject as a constraint.
(class field)
class SomeClass<T: ObservableObject> {
var myArray: [T] = []
}
(function variable)
func doAThing<T: ObservableObject>() {
var myArray: [T] = []
}
(See this article for a more in-depth explanation on what this error means.)
Of course, there's always the nuclear option of just defining the array as [Any].
Two ways I can think of. If you subclass TypeB with TypeA then you could use var collectionWithDifferentTypes: [TypeA] = [] or if they both conformed the same protocol. No need for the subclassing. Just use var collectionWithDifferentTypes: [protocolName] = []

The difference between an any type and a generic type in swift

What is the difference between an any type and generic type in swift?
Any Type Example:
let swiftInt: Int = 1
let swiftString: String = "miao"
var array: [Any] = []
array.append(swiftInt)
array.append(swiftString)
Generic Type Example:
func duplicate<T>(item: T, numberOfTimes n: Int) -> [T] {
var buffer : [T] = []
for _ in 0 ..< n {
buffer.append(item)
}
return buffer
}
Is this a matter of preference because both appear to solve the same problem by being able to substitute the desired type.
I'm not going to explain generics in details and i'll just point out the essential differences.
In the first example, you'll be able to append any type in that array, without being able to restrict beforehand your array to a specific type and to leverage compile time checks to guarantee that the array will not contain extraneous types. Not much to see in that example.
The second example contains instead a generic function that provides all of the above functionalities, consistency checks on the content of the array will come for free and if you want you'll also be able to specify additional characteristics of that generic type T, like requesting that it implements a specific protocol (e.g. limit duplicate() to object that implement Comparable or Equatable).
But that is just a simple example of a generic function, you can also have parametrized classes (what you'll use the most) and there are a lot of additional functionalities.
Never use Any as a poor-man generics, real generics are way more flexible, add useful checks and make more explicit your intentions, with minimal additional effort required to implement them.
Any means "I don't want any type checking and I won't be able to call type-specific methods without casting"
For example, try to call:
var array: [Any] = [1, 2]
var sum = array[0] + array[1] // you cannot do this! you have to cast to Int first
A generic type is a placeholder for a type. When used, a concrete type is used instead of it (e.g. an Int or a String).
In short, never use Any. There are very very few specific situations when Any is what you want to use.

How to assign a value to [any]

When I set c to a
var a: [Any]
var c: Array<PostCategory>
error shown:
cannot convert value of type 'Array' to expected argument type
[Any]
how to solve the problem?
The error message is a bit misleading but try initializing the array before assigning it:
var c: Array<PostCategory> = []
...or...
var c = Array<PostCategory>()
I bet your PostCategory is a struct. Apparently struct arrays aren't convertible to an Any array. This is weird because all types conforms to the Any protocol.
If you change the PostCategory to a class instead, it should work fine. You might need to create a new initializer for the class though, since classes doesn't give you the same default initializer as a struct does.

Mutating nested arrays in Swift Dictionary through custom accessor method

Say that we have a dictionary of arrays:
var dict: [Int: [Int]] = [:]
Is there something special about Dictionary's subscript methods? Can somebody explain why the following in-place append works:
dict[1] = []
dict[1]?.append(200)
// dict is now [1: [200]]
but the following doesn't:
var xs = dict[1]
xs?.append(300)
// dict is still [1: [200]], not [1: [200, 300]]
I (kind of) understand why the latter doesn't update the original dictionary, as it creates a copy of the array. But I don't understand why the first one works, I would assume that it similarly creates a copy.
More over (this is the actual problem I have), can I implement a method that allows similar in-place update behavior? The following code doesn't work:
extension Dictionary {
func mget(key: Key) -> Value? {
return self[key]
}
}
dict.mget(1)?.append(400)
It produces the following error:
49> d.mget(1)?.append(400)
repl.swift:49:12: error: immutable value of type '[Int]' only
has mutating members named 'append'
d.mget(1)?.append(400)
^ ~~~~~~