Swift: Accessing members of tuples in Array - iphone

Why am i getting this error?
Error: Value of type 'Any' (aka protocol<>) has no member 'name'
import UIKit
var alican = (name: "alican", surame:"yilmaz")
var array:[Any] = [alican]
print(array[0].name)

You've declared your Array as containing Any type. If you declare it like this the error should go away:
var array:[(name: String, surame: String)] = [alican]
If the array needs to be able to contain Any type you can pull out just those matching a particular type using flatMap.
var array:[Any] = [alican]
var nameSurnames = array.flatMap({ return $0 as? (name: String, surame: String) })
print(nameSurnames[0].name)

Just drop the typing of the array...
var array = [alican]
Typs is inferred wherever possible by swift.
You only need to explicitly type a variable if it is not possible to infer it automatically.

This is how you can access name and surname
var alican = (name: "alican", surame:"yilmaz")
var array = [alican]
print(array[0].name)

Related

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 .sortInPlace within a .forEach closure Swift

I am attempting to sort the arrays within a dictionary, but am getting an error. Here is the code I have tried. What am I missing & why won't this compile?
var dict = [Int: [String]]()
dict[1] = ["Zack", "James", "Bill", "Quin", "Mike", "Adam"]
dict[1]?.sortInPlace()
dict.forEach{$0.1.sortInPlace()} // error: cannot use mutating member on immutable value of type '[String]'
Edit: I was able to get the following code to work after realizing that the for each loop assigns a constant by default:
db.forEach{db[$0.0] = $0.1.sort()}
Swift, by default assigns each value inside closure to be immutable. You can modify the default behavior by declaring the variable as mutable using var as this,
dict.forEach({ (key: Int, var value: [String]) in
value.sortInPlace()
print(value)
})

"Deep-copy" of Swift dictionary with map()?

I have a GKGameModel that stores its internal state in an array a of Cards and a dictionary b that maps from Ints to arrays of Cards. GameplayKit mandates that I must copy this internal state in setGameModel:.
The following code is meant to just-copy the array and "deep-copy" the dictionary. FWIK this should be sufficient since Cards themselves never change.
var a: [Card]
var b: [Int: [Card]]
func setGameModel(gameModel: GKGameModel) {
let otherGameModel = gameModel as! GameModel
a = otherGameModel.a
b = otherGameModel.b.map { (i: Int, cards: [Card]) in (i, cards) }
}
However, this causes the following syntax error in the line that attempt the "deep-copy":
Cannot assign a value of type '[(Int, [Card])]' to a value of type
'[Int, [Card]]'.
What am I doing wrong?
In your case:
b = otherGameModel.b
is sufficient.
Because, Array and Dictionary are both value types. So when it is assigned to another variable, it will be deep copied.
var bOrig: [Int: [Int]] = [1: [1,2,3], 2:[2,3,4]]
var bCopy = bOrig
bCopy[1]![2] = 30
bOrig[1]![2] // -> 3
bCopy[1]![2] // -> 30
The error message reveals there is a type mismatch:
variable b is declared as Dictionary<Int,[Card]> but the map function returns an Array of tuplets (Int, [Card])

'AnyObject' is not a subtype of 'Custom Tuple'

I receive this error message: 'AnyObject' is not a subtype of 'KeyValuePair' when I try to compile the app.
Here is some code sample:
typealias KeyValuePair = (key: String, value: String) // custom tuple
var items = [KeyValuePair]()
func getSomeItems() -> [AnyObject]
{
return items as [AnyObject]
}
If I change for example var items = [KeyValuePair]() to var items = [String]() obviously it works. I also tried force case as!. Doesn't work
What is wrong with this code? Is there a possibility to case some [tuple] to [AnyObject]?
Thanks in advance!
You can cast class types to [Anyobject] (link), but the tuple type has compound type, which is not class type.
Instead of tuple use class or simply -> (key:String,value:String)

What is the difference between ":" and "=" in Swift?

Ive searched for the answer to this for a while and can't seem to find it.
But for example, what is the difference here:
var this: that
var this = that
Thanks
var this: That
declares a mutable variable of type That.
var this = that
declares a mutable variabel and assigns an instance of That to it. The type (That) is inferred in this case.
A more belt and braces method of declaring it:
var this: That = that
But usually type inference is enough.
: force assigns a constant/variable a type, whereas = assigns it a value
example of ::
let str: String = ""
example of =:
let str = ""
":" refers to defining the type of the variable
"=" refers to assigning a value to that variable
e.g.
var myString: String (declares a variable of type String)
var myString = "example text" (declares a variable who's type is implicitly determined to be String and assigns the value "example text" to it)
var myString: Int = "example text" (Syntax error. Defined a variable of type Int and tried to assign a String to that value)