Underlying type for Tuple in Swift
Declaring
let x: Tuple
doesn't make sense for two reasons:
- the tuple cardinality is missing (see below)
- the parametric types are missing
It's pretty much as declaring
let x: Array
which is forbidden as well (the parametric type is missing)
The difference here is also that Tuple
is not a type per se. A tuple type is defined by both the types of the elements it holds and their number.
So a Tuple
type doesn't make sense, rather you will have several types Tuple2
, Tuple3
and so on. Each TupleX
has have X
type parameters, which will define the concrete type once provided.
In swift the compiler creates this types for you (I have no references for that, but it's the only reasonable assumption I can make), probably up to a finite number (which I still haven't found). The naming of this types doesn't look to be explicit, so you won't find a Tuple2
, but instead you'll have a ($T1, $T2)
type.
To sum it up, declaring a Tuple
parameter is meaningless for several reasons, but you can surely have something like
var x: (Int, String)
or
var y: Optional<(Int, String)>
and so on.
To further clarify my point, here's why Tuple2
and Tuple3
need to be two different types:
class Tuple2<T1,T2> {
init (_ e1: T1, _ e2: T2) {}
}
class Tuple3<T1,T2,T3> {
init (_ e1: T1, _ e2: T2, _ e3: T3) {}
}
Tuple2(1, "string")
Tuple3(1, "string", ["an", "array"])
This is probably similar to what the compiler generates, and you can easily see that each TupleX
takes a different number of type parameters, hence we need to define a type for each X.
How to detect that parameter is a tuple of two arbitrary types?
You can use Swift's baby introspection methods to get at this:
func isTuple(b: Any) -> Bool {
return reflect(b).disposition == MirrorDisposition.Tuple
}
Note that reflect
is largely undocumented and may only be there as support for the playground / debugger, but as far as I know this is the only way to do this.
To achieve this you need to drill down into what reflect()
gives you, which is a struct that conforms to MirrorType
, which I call a reflection, for lack of a better term. You can subscript the reflection of a tuple to get reflections of the tuples members, and then get the value back out as Any
. At that point you can use optional binding to safely rediscover the underlying type:
func process(value: Any) {
println("Any \(value)")
}
func process(value: String) {
println("String \(value)")
}
func processTuple(b: Any) -> Bool {
let isTuple = reflect(b).disposition == MirrorDisposition.Tuple
let r = reflect(b)
for i in 0..<r.count {
println(r[i].0) // string holding tuple part name: ".0", ".1", etc
println(r[i].1.value) // the value of that tuple part: "aa", 1.2
process(r[i].1.value) // calls process(Any)
if let val = r[i].1.value as? String {
process(val) // calls process(String)
}
}
return isTuple
}
let myString = "aa"
let myDouble = 1.2
processTuple((myString, myDouble)) //returns false
Output:
.0
aa
Any aa
String aa
.1
1.2
Any 1.2
What is the limit (if any) to the tuple cardinality in Swift?
In the current version of Xcode 6 Beta, compilation fails with tuples of arity larger than 1948 (the swift
executable exits with code 254; there isn't a specific warning or error).
Flatten TupleViews using SwiftUI
One way to fix this is to use the type eraser AnyView
:
var body: some View {
switch shape {
case .oneCircle:
return AnyView(ZStack {
Circle().fill(Color.red)
})
case .twoCircles:
return AnyView(ZStack {
Circle().fill(Color.green)
Circle().fill(Color.blue)
})
}
}
UPDATE
I add the following to answer the commenters who are asking why this is needed.
One commenter says
ZStack is still a View, right?
Actually, no. ZStack
by itself is not a View
. ZStack<SomeConcreteView>
is a View
.
The declaration of ZStack
looks like this:
public struct ZStack<Content> : View where Content : View
ZStack
is generic. That means that ZStack
by itself is not a type. It is a “type constructor”.
The idea of a type constructor is not usually discussed in the Swift community. A type constructor is, essentially, a function that runs at compile time. The function takes one or more types as arguments and returns a type.
ZStack
is a type constructor that takes one argument. If you ‘call’ ZStack
repeatedly with different arguments, it returns different answers. This is what Robert Gummesson shows in his question:
This happens because the first ZStack is this type:
ZStack<ShapeView<Circle, Color>>
and the second is this type:
ZStack<TupleView<(ShapeView<Circle, Color>, ShapeView<Circle, Color>)>>
In the first case, the program ‘calls’ ZStack
with the argument ShapeView<Circle, Color>
and gets back a type as the answer. In the second case, the program ‘calls’ ZStack
with a different argument, TupleView<(ShapeView<Circle, Color>, ShapeView<Circle, Color>)>
, and so it gets back a different type as the answer.
The declaration var body: some View
says that the body
method returns a specific, concrete type (to be deduced by the compiler) that conforms to the View
protocol. Since the two ‘calls’ to ZStack
return different concrete types, we must find a way to convert them both to a single common type. That is the purpose of AnyView
. Note that AnyView
is not generic, which is to say, it is not a type constructor. It is just a plain type.
How to enumerate an enum with String type?
Swift 4.2+
Starting with Swift 4.2 (with Xcode 10), just add protocol conformance to CaseIterable
to benefit from allCases
. To add this protocol conformance, you simply need to write somewhere:
extension Suit: CaseIterable {}
If the enum is your own, you may specify the conformance directly in the declaration:
enum Suit: String, CaseIterable { case spades = "♠"; case hearts = "♥"; case diamonds = "♦"; case clubs = "♣" }
Then the following code will print all possible values:
Suit.allCases.forEach {
print($0.rawValue)
}
Compatibility with earlier Swift versions (3.x and 4.x)
If you need to support Swift 3.x or 4.0, you may mimic the Swift 4.2 implementation by adding the following code:
#if !swift(>=4.2)
public protocol CaseIterable {
associatedtype AllCases: Collection where AllCases.Element == Self
static var allCases: AllCases { get }
}
extension CaseIterable where Self: Hashable {
static var allCases: [Self] {
return [Self](AnySequence { () -> AnyIterator<Self> in
var raw = 0
var first: Self?
return AnyIterator {
let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) }
if raw == 0 {
first = current
} else if current == first {
return nil
}
raw += 1
return current
}
})
}
}
#endif
Model Objects In Swift
A Tuple can be created using the type alias like this
typealias Tuple = (String,Int,Double)
A Tuple Array
typealias TupleArray = [Tuple]
A Dictionary from String to Tuple Arrays
typealias DictionaryOfTuples = [String : TupleArray]
or
typealias DictionaryOfTuples = [String : [Tuple]]
Can be used like this
var array1:[Tuple] = [("1",1,1.0),("1",1,1.0)]
var array2 :[Tuple] = [("1",1,1.0),("1",1,1.0)]
var single :Tuple = array1[0]
var dictionary1 :DictionaryOfTuples = ["A" : array1, "B" : array2]
var dictionary2 :DictionaryOfTuples = ["C" : array1, "D" : array2]
var final_array = [dictionary1,dictionary2]
How to check for Enum types in Swift?
enum Things {
case Thing1
case Thing2
}
let something:Any = Things.Thing1
something.dynamicType == Things.self // true
update based on discussion ..
protocol P {}
enum Things:P {
case Thing1
case Thing2
}
enum Things2:P{
case Things21
}
let something:Any = Things.Thing1
something.dynamicType == Things.self // true
if let p = something as? P {
print(true)
}
let somethingelse: Any = Things2.Things21
if let p = somethingelse as? P {
print(true)
}
Related Topics
Why Does My Swift Bundle Get The Wrong Principal Class
Do Swift Hashable Protocol Hash Functions Need to Return Unique Values
Typecase Regular Swift Function to Curry Function
Firestore - Creating a Copy of a Collection
Calling C++ from Swift - What Is The Equivalent of Std::Vector<T>
Error Validating Cms Signature
How to Stop Firestore Pagination When Searched Data Are Loaded in Tableview
Spritekit and Swiftui, Change Scene a Better Way
Remove Add Calendar Button from Calendar Chooser
Getting The Parameterised Type of a Generic in Swift
Using Font Awesome Dynamically in Swift
How to Call Https Url in UIwebview (Swift)
Calculate Range of String from Word to End of String in Swift
How to Update Nslayoutconstraint in a UItableviewcell of Dynamic Height