Swift Has Tuple
It is a very common use case where we want to return two values from a method, which can be either of the same data types or can be of different data types. Typically within this case, we would either create various local variables if the method is of the same class and set those variables from the method and consume them in the place where needed or we could create a struct and return that struct object from the method.
This approach works fine but is it worth defining a new struct every time when we return value(s) from a method. As great as that may sound consider this then if you have several methods which also return value(s) but each method returns the value(s) of different data types. I suppose in said case you could create a separate struct for each of the methods but it isn’t practical and comes on just terrible programming.
Got a Solution?
As the title of this article should have implied Swift has a type called Tuple which is used to group various values in a single compound value. Storing or returning two values of the same or different data types is child play for a tuple. here can or cannot be any relation between both the values.
Using Tuple
It is initialized in two ways:
- unnamed variables
- where the names are not defined within the tuple and use their position to access it
var tuple = ("football", "basketball")
print(tuple.0)
print(tuple.1)
- named variables
- where the names are defined within the tuple and use the names that were defined for them
var tuple = (atk : 2500, def : 2100) print(tuple.atk) print(tuple.def)
- Published in iOS, Programming Languages, Swift
“Structs vs Classes” and using them
This is because it plays a significant role in choosing the right abstraction mechanism keeping both performance and modeling in mind. As you can only imagine this topic is simply the tip of the iceberg. Many advanced concepts and questions of classes and structs in swift. With that being, I have broken this topic into two parts.
Structs & Classes — What are they?
Consider them like templates or guidebook that contains variables and methods used to all object of the said kind. In short, they assist in keeping the code organized for future maintenance and reusability.
Class features over structs
- Inheritance
- inherit the characteristics of another class
- Type-casting
- checks and interprets the type of a class instance at runtime
- Deinitializers
- enable an instance of a class to free up any resources it has assigned
- Reference Count
- allows multiple references to a class instance
Value & reference types
- Value types
- each instance keeps an independent copy of its data
- example: structs, enums, or tuples
- changing one instance will have no effect on the other
- each instance keeps an independent copy of its data
- reference type
- Instances share a single copy of the data.
- changing data in one instance will change the data for all instance pointing to the same instance
- example: classes
Deciding to class or struct
when deciding on a new model we, as developers, should carefully contemplate the use cases of the model. With that stated, you should decide between structs and classes.
using classes:
class Network {
var url:String
init(url:String) {
self.url = url
}
}
var req = Network(url: "https://daurislittle.com")
var newReq = req
newReq.url = "https://facebook.com"
if req === newReq {
print(req.url)
print(newReq.url)
}
- comparing instance identity with “===” makes sense
- Creating a shared and mutable state
- if your intent is to share the state among the threads and variables use classes
using structs:
You will note the code below compare the value of the Network URLs and not the memory addresses.
struct Network {
var url:String
}
extension Network:Equatable{}
let req = Network(url: "https://daurislittle.com")
let newReq = Network(url: "https://facebook.com")
if req == newReq {
print("Both the request contains the same address")
}
- comparing instance data with “==” makes sense
- data needs to be compared and the memory locations of these data are not important
Now you can see that both the requests have different URLs as each request have a different copy of the URLs
struct Network {
var url:String
}
extension Network:Equatable{}
var req = Network(url: "https://daurislittle.com")
var newReq = req
newReq.url = "https://facebook.com"
print(req.url) //https://daurislittle.com
print(newReq.url) //https://facebook.com
Now you can see that both the requests have different URLs as each request have a different copy of the URLs
- Data can be used in code across multiple threads
- when passing and copying value types in a multi-threaded environment we can be sure that each context will have a separate unique copy which will not impact the others
- This helps avoid a lot of unintentional bugs
- when passing and copying value types in a multi-threaded environment we can be sure that each context will have a separate unique copy which will not impact the others
Memory Allocation w/structs and classes
structs are allocated in the stack memory. References of the class objects can be created on the stack but all the properties of the class’s object will be kept in the heap
Reference counting
As stated above classes support heap allocations they need to maintain reference counts for allocation and deallocating objects. On the other hand, structs do not need reference counting. However, if structs contain references then they would incur twice the number of reference counting overhead as compared to a class.
Method Dispatching
Classes use method dispatch but if a class is marked as “final“, the compiler will use static dispatch. Stucts uses “static” dispatch.
Memberwise initializers
Memberwise initializers are those initializers which the compiler generates automatically for structs. We can initialize a struct’s object using these initializers even though we have not provided any custom initializers.
enum RequestType {
case get, post, delete
}
struct Network {
val url:String
var type:RequestType
//Memberwise init generated by the compiler
}
var req = Network(url:"https://daurislittle.com", type: .get)
Note: order arguments in these initializers are decided by the order of the declared properties in struct.
However, as a developer we can write any custom initializer, the compiler now though will not generate the memberwise initializer. You can use both generated memberwise and custom initializers, just need to add the custom initializer within the extension of the struct.
enum RequestType {
case get, post, delete
}
struct Network {
val url:String
var type:RequestType //Memberwise init generated by the compiler
}
extension Network {
initi(URL:String) {
self = Network.init(url: url, type: .get)
}
}
var req = Network.init(url:"https://daurislittle.com")
Keyword “mutating” and when to use it
When changing the property of any struct, using the keyword “mutating” before the “func” keyword when defining a method. This is because the self parameter that’s implicitly passed into every method is immutable by default.
extension Network {
mutating func updateUrl(url:String) {
self.url = url
}
}
//self is passed as a var
The “mutating” keyword allows the compiler to decide which methods can’t be called on let constants. If we try to call a mutating method on a “let” constants. If we try to call the mutating method on a let variable, the compiler shows an error.
- Published in blog, iOS, Programming Languages, Swift
Using let or var within Swift
I know I know I know before you say anything I understand this statement is probably ridiculous. However, this topic could aid someone or more likely open the floor to discuss concepts in general so without hesitation, we will dive into it.
let and var so what are they and their differences
As you probably already know both let and var are for creating variables within Swift. Now with let it helps create an immutable variable(s) so consider it a constant but var is used for creating a mutable variable(s). Nonetheless, a variable created by either of them holds a reference or a value.
The difference between the two is that when a developer creates a constant with let the value must be assigned before you can use it. While when you declare a variable with var it can be used before or after an assignment or never use it as well as reassigning it on the fly.
Mutate function parms
function parameters are constants by default. Trying to change their value within the function body results in a compile-time error.
func pokedex(for name: String) {
name = "charmander"
}
pokedex(for: "mex")
//Line 2 cannot assign to value is let constant
Test: Build & Compile
struct Pokemon {
var name: String
let weakness: String
}
let trainerAPokemon = Pokemon(name: "Charmander", weakness: "water")
trainerAPokemon .name = "Bulbasaur"
trainerAPokemon .weakness = "fire"
var trainerBPokemon = Pokemon(name: "Pikachu", weakness: "rock")
trainerBPokemon.name = "Squirtle"
trainerBPokemon.weakness = "electricity"
In the example above we are using a struct. Whenever you try to muate them they get copied with mutation applied to them and reassigned back.
Now let’s review everything within the block. The let variable within the struct cant is mutated as it would mean you are mutating the value of an immutable variable. However, our friend the var variable within the struct can be mutated.
- Line 7
- cannot assign to the property trainerAPokemon because it is a let constant
- Line 8 & 12
- cannot assign to the property weakness because it is a let constant
Test: Build & Compile
class Pokedex {
var name: Int
let num: String
init(name: String, num: Int) {
self.name = name
self.num = num
}
}
let trainerA = Pokedex(name: "Lucario", num: 448)
trainerA.name = "Squirtle"
trainerA.num = 7
var trainerB = Pokedex(name: "Bulbasaur", num: 1)
trainerB.name = "Gengar"
trainerB.num = 94
In the example above we are now using a classes. When attempting to mutate them, the object stored elsewhere in memory gets mutated while the reference to it remains the same.
You can modify a class’s members whether or not the variable referencing it is mutable
- Line 13 & 17
- cannot assign to property num because it is a let constant
- Published in blog, iOS, Programming Languages, Swift
Using Enum w/Swift
understand enum is nothing fancy and all languages have their version of it. Let’s first understand what is enumeration which is a data type consisting of a set of named values also referred to as members. Apple definition states:
An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.
Swift makes enumerations (enums) very flexible and does not have to provide a value for each case. If a “raw” value is provided for each enumeration case, the value can be a string, a character, integer or floating-point type.
Enum Syntax
implementing enumerations is done with enum keyword and place the definition within your implementation.
enum EnumImplementation {
// place enum definition
}
//Enum Type Example
enum PokemonGender :String {
case male
case female
}
//Enum No Type Example
enum PokemonGender {
case male
case female
}
We have created some defined values within the enumeration which are Male and Female and they are now enumeration cases. Use the case keyword to introduce new enumeration cases.
Note: alternative implementation does exist.
Each enumeration definition defines a brand new type. Obviously naming conventions should be respects so names starting with capital letter.
Moving on we can now set a variable to the enum case: var gender: PokemonGender = PokemonGender.male or we can shorten it to var gender = PokemonGender.male
Enums Partying w/Switch Statements
Note: When using enums with switch statements there is no need to use a default case because all the possible enums members are taken care of. This way our enums just needs to be checked an and if all the membeers of the enum are exhuasted then create a default case.
switch gender {
case .male: print("Gender is male")
case .female: print("Gender is female")
//a default case is not needed
}
Defined Values:
Enum case cannot have a raw value if the enum doesn’t have a raw type
Note: enum defined type cannot have other datatypes within the cases
enum PokemonGender {
//wrong(error): enum case cannot have a raw value if the enum does not have a raw type
case male = 1
//correct
case female
}
You could use enum with defined values if enum is having a “raw” type:
enum PokemonType: Int{
case Fire = 1, Water, Grass
}
This now enumerates the values and assigns the pokemon their type. Note that with this declaration we have also added the var type after the name enum. To get the value stored in that in the enum member, you need to access its rawValue property as println("Result -> \(type.Water.rawValue)") //prints "2"
Now let’s consider the above enum of Pokemon Type. If fire equals 1, water is given a value of 3, and if grass is not given any value, then the raw value of grass will give you 4
Enum PokemonType: Int {
case Fire = 1, Water = 3, Grass
}
print(PokemonType.Grass) //prints "4"
Methods and Enum
You may be thinking that enums and methods are foreign friends but that is not the case. Enums can have methods that use enum cases:
enum DOTW:String {
case Sunday
case Monday
case Tuesday
case Wednesday
case Thursday
case Friday
case Saturday
func day() ->String {
return self.rawValue
}
}
print(DOTW.Monday.day()) //prints Monday
Important: Enums can have methods, subscripts, and computed properties. But it cannot have stored properties
- Published in iOS, Programming Languages, Swift
Using forEach, forEnumerated, forIn within Swift
Swift provides us with multiple ways to loop through items in a collection, they are:
for pokemon in pokemons {
print(pokemon)
}
pokemons.forEach { (pokemon) in
print("Pokemon", pokemon)
}
for (index, element) in pokemons.enumerated() {
print("Number:", index, "Pokemon:", element)
}
Using for in
many programming languages the for in loo is called for-each. Standard loop statement in other languages uses this format:
for (i = 0; i < n; i++) {
///some fancy collecion to loop thur
}
Please note: Swift 3 no longer supports c-style for-loops
Now when using swift this approach is a little different, the rationale of this for-in syntax is it can be used to loop over ranges, iterators, strings, sequences, and collections with the same syntax.
let pokemons = ["Pikachu", "Charmander", "Squirtle", "Bulbasaur"]
for i in 0...< pokemons.count {
print("Pokemon \(i+1):" pokemons[i])
}
//output:
Pokemon 1: Pikachu
Pokemon 2: Charmander
Pokemon 3: Squirtle
Pokemon 4: Bulbasaur
Within Swift the use of object types like arrays, dictionaries, and sets are known as collection. Any collection can be iterated with a for-in loop. For example with dictionary:
let pokedex = ["Electric":"Pikachu","Water":"Squirtle","Fire":"Charmander","Grass":"Bulbasaur"]
for (type, pokemon) in pokedex {
print("The \(type)'s Pokemon is \(pokemon))
}
//output
The Electric's Pokemon is Pikachu
The Water's Pokemon is Squirtle
The Fire's Pokemon is Charmander
The Grass's Pokemon is Bulbasaur
In addition, Swift also provided two range operators lowerBound...upperBound as a shortcut for expressing a range of values.
Take note: lowebound is greater than upperBound the code will crash
for i in 0...5 {
print(i)
}
//output
0
1
2
3
4
5
for i in 0..<5 {
print(i)
}
//output
0
1
2
3
4
If interested in reversing the range while looping, we can easily achieve that using reversed
for i in (0...5).reversed() {
print(i)
}
//output
5
4
3
2
1
0
Stride
As I referenced before, C-Style for loops are no longer supported within Swift 3, so you’re probably asking how to acquire the ‘increment of the counter’ (i++). We accomplished this by using stride, and this helps us to move from one value to another using any incremental value, we can also specify whether the upperBound is inclusive or exclusive.
for i in stride(from 0, to: 10, by: 2) {
print(i)
}
//output
0
2
4
6
8
Using for each
pokemons.forEach {
print("Pokemon", pokemon)
}
//output
Pokemon Mewtwo
Pokemon Snorlax
Pokemon Eevee
Swift provides a dedicated method forEach for specific, unlike the above forIn this method can’t break the loop partway (at some point). It has to loop over each item in the sequence. It has to loop over each item in the sequence. This helps people reading your code to figure out your intent: that you want to act on all items, and won’t stop in the middle.
Please note:
breakstops execution in a loop immediately and continues directly after the loop.
continueonly exits the current iteration of the loop — it will jump back to the top of the loop and resumes up from there for next iteration
var oddNumbers = [Int]()
for numbers in (0...100) {
guard oddNumbers.count < 15 else {
break
}
guard numbers % 3 == 0 else {
continue
}
oddNumbers.append(numbers)
print(oddNumbers)
}
the same cannot be achieved in forEach with break and continue, so we need something like:
let oddNumbers = (0...100).filter {numbers -> Bool in
return numbers % 3 == 0
}.prefix(10)
print(oddNumbers)
Using for enumerated
This Swift loop iterates to each of the items by also telling the index of it. In case if we need to iterate the elements and need their index also, then forEnumerated is the perfect loop for us.
Nested for loops:
var pokedex = ["001", "002", "003"]
var pokemons = ["Bulbasaur", "Ivysaur", "Venusaur"]
for i in 0..< pokedex.count {
var string = "\(pokedex[i]) is "
for _ in 1...3 {
string += "\(pokemons[i])"
}
print(string)
}
//output
001 is Bulbasaur
002 is Ivysaur
003 is Venusaur
While:
// a while loop performs a set of statements until a condition becomes false
while condition {
//statements
}
var index = 0
while index < pokemons.count {
print(pokemon[index])
index += 1
}
//output
Bulbasaur
Ivysaur
Venusaur
Repeat:
//repeat while loop is similar to do while loops in other languages
repeat {
statements
} while condition
var index = 0
repeat {
print (pokemons[index])
index += 1
} while index < pokemons.count
//output
Bulbasaur
Ivysaur
Venusaur
It is similar to the above while loop but the major difference is that this loop evaluates the condition after running the statements. Either way, both while and repeat are best used in the loops where the numbers of steps are unknown.
- Published in blog, iOS, Programming Languages, Swift
Gradient Views w/Swift
When you want to give the background color to the view, but you want to add more colors and get the gradient effect, you need to add a layer to view,
which we are going to create, in few lines of code.
- Create a CAGradientLayer
var gradientLayer: CAGradientLayer = {
let gradientLayer =CAGradientLayer()
gradientLayer.colors = [#Color1, #Color2] //note: colors you want to use
gradientLayer.startPoint = CGPoint(x:0 y:0)
gradientLayer.endPoint = CGPoint(x:1 y:1)
gradientLayer.frame= CGRect.zero
return gradientLayer
} ()
- Add gradientLayer to the view layer
currentView.layer.addSublayer(gradientLayer)
- Set frame of the gradientLayer
gradientLayer.frame = currentView.bounds
- Published in blog, iOS, Programming Languages, Swift
Working w/Environments in Swift
According to Wikipedia, an Environment Variable is a dynamic-named value that can affect the way running processes will behave on a computer. They are part of the environment in which a process runs. Basically, many developers create 3 environments
- Dev
- Preprod
- Prod
Sometimes we need to separate the base URL and do the initial work which should be done for the following state or condition only.
Create enum for environments
if you need a refresher on enum check out the following article
enum Environment {
case dev
case preprod
case prod
}
Environment Variable
let currentEnvironment = Environment.dev
Execute using a switch statement
switch currentEnvironment {
case .dev:
print("execute only if the environment is development")
case .preprod:
print("execute only if the environment is preprod")
case .prod:
print("execute only if the environment is prod")
default:
break
}
Execute code now
First, we initialize the currentEnvironment variable and using conditions use it. Now we can change the baseUrl in AppDelegate along with other interesting code.
- Published in blog, iOS, Programming Languages, Swift





