Swift 4.2: what does the following declaration mean - swift

I am new to swift and IOS so there is a lot of unknown. What does the following declaration statement mean?
private let _digest: (UInt64, UInt64)

It's a tuple. Just like how an array has an index for an element, this variable can also be accessed using . operator followed by the index.
_digest.0
_digest.1
However, if you want to access them using using a name rather than the index, that is also possible. (You can still access it using the index)
private let _digest: (first: UInt64, second: UInt64)
_digest.first
_digest.second
For more on Tuples.

This is a private constant of type tuple, which contains two UInt64 values.
You can read about tuples and other types in Swift here
An example:
let someTuple: (Double, Double) = (3.14159, 2.71828)
Usage:
print(someTuple.0) // 3.14159

What you are basically doing is declaring a constant variable - because of the keyword let - called _digest and you are assigning the type (UInt64, UInt64) to it, which is a tuple with two variables of type UInt64.

Its a tuple that holds two UInt64.
Tuple is a group of different values represented as one . According to apple, a tuple type is a comma-separated list of zero or more types, enclosed in parentheses. It’s a miniature version of a struct.
let person = ("John", "Smith")
var firstName = person.0 // John
var lastName = person.1 // Smith
Also, if needed its possible to access there elements by name instead of index.
var person = (fName:"John", lName:"Smith", age:Int())
person.age = 33
print(person.fName) // John
print(person.lName) // Smith
print(person.age) // 33
Further, the type of a tuple is determined by the values it has. So ("tuple", 1, true) will be of type (String, Int, Bool).
For more information please visit here

Related

What does Array and ... does here?

I have this line here, I can not understand the purpose, and the sytacs.
instances = Array(Array(instance.enumerated())[prefixItems.count...])
What does ...
What does [prefixItems.count...] when creating an Array?
How instances can be assigned to a type like: [(Int, Any)].
this is the whole statement, it is syntactically valid:
let instances: [(Int, Any)]
if let prefixItems = schema["prefixItems"]?.array {
guard instance.count > prefixItems.count else {
return AnySequence(EmptyCollection())
}
instances = Array(Array(instance.enumerated())[prefixItems.count...])
} else {
instances = Array(instance.enumerated())
}
but for some reason I need convert Any to DataToValidate, like:
let instances: [(Int, DataToValidate)]
and then I got error:
Cannot assign value of type 'Array<EnumeratedSequence<(JSONArray)>.Element>' (aka 'Array<(offset: Int, element: JSONValue)>') to type '[(Int, DataToValidate)]'
The x... is a one-sided range from x to "as far as possible", i.e., to the end of the array in case of subscripting, as done here.
Array(instance.enumerated()) initializes an array from the enumerated sequence instance, i.e., [(Int, Any)]. The subscript [prefixItems.count...] takes the elements from that array starting from the index prefixItems.count and continuing to the end. The outer Array initializes an array of that sequence.
The types of everything involved above (in practice some will have more specific actual types, but they conform to these):
instance – some Sequence, but we can consider it [Any]
instance.enumerated() – Sequence<(Int, Any)>
Array(instance.enumerated()) – [(Int, Any)]
Array(instance.enumerated())[prefixItems.count...] – Sequence<(Int, Any>)>
Array(Array(instance.enumerated())[prefixItems.count...]) – [(Int, Any)]
P. S. As pointed out in comments, note that the intermediate array and subscripting is unnecessary, and the same outcome can be achieved with Array(instance.enumerated().dropFirst(prefixItems.count)). This also makes the guard unnecessary.

Find the sum of an array in swift

I have an array that holds integer values. And I have defined it like so:
#State private var numbers: Array = []
the array is updated as the user uses the app. At a certain point, I need to find the sum of all the values in the array. Here is what I tried to do:
let sumOfNum = numberz.reduce(0, +)
However, this is giving me the following error on the plus(+) symbol:
Cannot convert value of type '(Int) -> Int' to expected argument type '(Int, Any) throws -> Int'
Not sure what the problem is. Any help or guidance would be appreciated.
Your issue is probably your Array declaration. You should declare is as an array of Int instead of an array of Any.
So your array declaration should be
#State private var numbers: [Int] = []

Trying to understand how constructors and different parameter types work inside classes in Swift

New to Swift but have some previous knowledge about C# and Java programming. Trying to understand how "Constructors" and parameter types work in Swift when creating and instantiating a class.
My problem is below:
public class MyClass {
private var somethingA : String
private var somethingB : String
private var somethingC : Int
private var complexes:[String:[String:Int]] = [String:[String:Int]]();
init() {
self.somethingA = "";
self.somethingB = "";
self.somethingC = 0;
self.complexes = [somethingA:[somethingB:somethingC]];
}
public func addSomething(somethingAA : String) {
self.somethingA = somethingAA;
}
public func addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) {
self.somethingA = somethingAA;
// How do I assign the complex:(somethingBB, somethingCC) parameter to my self variable 'complexes'?
}
}
When I tried doing it like the following, I get the following errors for each line:
self.somethingB = somethingBB; // Use of unresolved identifier 'somethingBB'
self.somethingC = somethingCC; // Use of unresolved identifier 'somethingCC'
self.complexes = [somethingAA:[somethingBB:somethingCC]]; //use of unresolved identifier 'somethingBB' and 'somethingCC'
the function addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) takes a tuple of name complex which consist of String and Int. To assign values from tuple to your properties, you need to use tupleName.propertyName kind of pattern, using this your addAddComplex function becomes
public func addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) {
somethingA = somethingAA
somethingB = complex.somethingBB
somethingC = complex.somethingCC
//create a dict with somethingB and somethingC values
complexes = [somethingAA: [somethingB: somethingC]]
print(complexes)
}
Now if you call function addComplex like below which will print ["AAA": ["BBB": 10]]
let myClass = MyClass()
myClass.addSomething(somethingAA: "Hellow")
myClass.addComplex(somethingAA: "AAA", complex: (somethingBB: "BBB", somethingCC: 10))
For error inside function addComplex, parameter complex is tuple, which contains two value named somethingBB of type String and somethingCC of typle Int.
So to access value from tuple you have to access it with dot notation.
self.somethingB = complex.somethingBB
self.somethingC = complex.somethingCC
or you can access parameters from tuple using below syntax also :
self.somethingB = complex.0
self.somethingC = complex.1
To assign value to complexes is type of Dictionary of key-value pair. Here key is type of String and value is another Dictionary of [String:Int]. So you have to construct same structure using raw values from function parameters inside function like below.
self.complexes = [somethingAA:[somethingBB:somethingCC]]
Try this code:
public func addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) {
self.somethingA = somethingAA;
self.somethingB = complex.somethingBB
self.somethingC = complex.somethingCC
self.complexes = [somethingAA:[somethingBB:somethingCC]]
}
Tuples are one of Swift's less visible language features. They occupy a small space between Structs and Arrays. In addition, there's no comparable construct in Objective-C (or many other languages).
A tuple can combine different types into one. Tuples are value types
and even though they look like sequences they aren't sequences, as
there's no direct way of looping over the contents.
There are different types of tuples:
// A simple tuple
let tuple1 = (2, 3)
let tuple2 = ("a", "b", "c")
// A named tuple
let tuple3 = (x: 5, y: 3)
// Different types of contents
let tuple4 = (name: "Carl", age: 78, friends: ["Bonny", "Houdon", "Miki"])
The ways in which you can access tuple elements are:
// Accessing tuple elements
let tuple5 = (13, 21)
tuple5.0 // 13
tuple5.1 // 21
let tuple6 = (x: 21, y: 33)
tuple6.x // 21
tuple6.y // 33
Now coming to your question the comlpex parameter is a named tuple In which
complex:(somethingBB: String, somethingCC: Int)
the first parameter in the tuple is somethingBB type of string and somethingCC type of Int.
You can simply access somethingBB and somethingCC by doing
self.somethingB = complex.somethingBB
self.somethingC = complex.somethingCC
or
self.somethingB = complex.0
self.somethingC = complex.1
It is unclear how you want to add the tuple to the complexes property. Do you want to add a new entry in the dictionary? Do you want to replace the existing dictionary with the parameter values?
You probably have a misunderstanding of how tuples work. This parameter:
complex:(somethingBB: String, somethingCC: Int)
Is a parameter called complex, with the type of (somethingBB: String, somethingCC: Int). There is not a single parameter called somethingBB or somethingCC. There is, however, complex.somethingBB and complex.somethingCC. Think of tuples in Swift like System.Tuple in C#, but better. That way, you wouldn't mistake somethingBB and somethingCC as parameters when they are just members of a tuple type.
Now, you should know how to add the tuple into the dictionary. If you want a new entry:
complexes[somethingAA] = [complex.somethingBB: complex.somethingCC]
If you want to replace the existing entry:
complexes = [somethingAA : [complex.somethingBB : complex.somethingCC]]
In production code, you should probably not use complex types like [String: [String: Int]], create a struct or class for it.
EDIT:
If you want to append an entry to the inner dictionary, you need to check whether there is a value associated with the key somethingAA first:
if complexes[somethingAA] == nil {
complexes[somethingAA] = [somethingBB: somethingCC]
} else {
complexes[somethingAA][somethingBB] = somethingCC
}

Using init() in map()

TL;DR
Why doesn't this work?
"abcdefg".characters.map(String.init) // error: type of expression is ambiguous without more context
Details
One really cool thing I like in Swift is the ability to convert a collection of one thing to another by passing in an init method (assuming an init() for that type exists).
Here's an example converting a list of tuples to instances of ClosedInterval.
[(1,3), (3,4), (4,5)].map(ClosedInterval.init)
That example also takes advantage of the fact that we can pass a tuple of arguments as a single argument as long as the tuple matches the function's argument list.
Here another example, this time converting a list of numbers to string instances.
(1...100).map(String.init)
Unfortunately, the next example does not work. Here I am trying to split up a string into a list of single-character strings.
"abcdefg".characters.map(String.init) // error: type of expression is ambiguous without more context
map() should be operating on a list of Character (and indeed I was able to verify in a playground that Swift infers the correct type of [Character] here being passed into map).
String definitely can be instantiated from a Character.
let a: Character = "a"
String(a) // this works
And interestingly, this works if the characters are each in their own array.
"abcdefg".characters.map { [$0] }.map(String.init)
Or the equivalent:
let cx2: [[Character]] = [["a"], ["b"], ["c"], ["d"]]
cx2.map(String.init)
I know that I could do this:
"abcdefg".characters.map { String($0) }
But I am specifically trying to understand why "abcdefg".characters.map(String.init) does not work (IMO this syntax is also more readable and elegant)
Simplified repro:
String.init as Character -> String
// error: type of expression is ambiguous without more context
This is because String has two initializers that accept one Character:
init(_ c: Character)
init(stringInterpolationSegment expr: Character)
As far as I know, there is no way to disambiguate them when using the initializer as a value.
As for (1...100).map(String.init), String.init is referred as Int -> String. Although there are two initializers that accept one Int:
init(stringInterpolationSegment expr: Int)
init<T : _SignedIntegerType>(_ v: T)
Generic type is weaker than explicit type. So the compiler choose stringInterpolationSegment: one in this case. You can confirm that by command + click on .init.

Functions on generic arrays

I would like to use more functional programming in Swift. Some of the functions I write could work well on Arrays of various types. I don't want to rewrite the same function with different types (or typealiases.) The pattern how the function would work is often the same, just with different types. So, I tried something like this:
// Add indeces to an array of any type. I.e., returns an array of tuples of the array index and the original element.
func addIndeces<T: AnyObject>(toArray: Array<T>) -> Array<(index: Int, value: T)> {
var arrIndex: [Int] = []
for index in 0...toArray.count {
arrIndex.append(index)
}
return Array(Zip2(arrIndex, toArray))
}
When I call this function
// Note: reminderList is of type [Reminder]
let indexedReminderList = addIndeces(reminderList) as! [(index: Int, reminder: Reminder)]
I get a runtime error: "fatal error: can't unsafeBitCast between types of different sizes"
What am I doing wrong?
The function you are writing already exists – kind of. enumerate "return a lazy SequenceType containing pairs (n, x), where n\ s are consecutive Int\ s starting at zero, and x\ s are the elements of base"
This means you can write your function as:
func addIndices<T>(toArray: [T]) -> [(index: Int, reminder: T)] {
// if you want to label the tuple elements index: and reminder:,
// you still have to use map:
return map(enumerate(toArray)) {
(index: $0, reminder: $1)
}
}
Note, you don’t need to write T: AnyObject unless you specifically want to prevent this function from accepting anything other than arrays of classes (as that's what AnyObject is - the protocol that only classes, not structs or enums, conform to).
Note, enumerate only works for integer-indexed collections. To make it more general, you could write zip(indices(someCollection),someCollection)). indices returns a range of all the indices of any collection, so is equivalent to someCollection.startIndex..<someCollection.endIndex.
You want to cast the tuple Array of type [(index: Int, value: T)] where T is of type Reminder to a tuple Array of type [(index: Int, reminder: Reminder)]. So you can see that the tuples have different element names (value and reminder) where both have different byte sizes - therefore the error.
So you should take the same element names for both tuples.
If you want to change the element names:
let newTupleArray = oldTupleArray.map{ (newElementName0: $0.0, newElementName1: $0.1) }
The range 0...toArray.count consist all elements form 0 to the count of toArray, including the count value, and in your case arrIndex will always have one more element then toArray. Thats what is causing different size error. To fix it replace your range with this one 0..<toArray.count