Skip to content

A short and intuitive documentation about swift basics & hidden features

Notifications You must be signed in to change notification settings

HaraldBregu/Swift_Hidden_Features

Repository files navigation

Swift Basic & Hidden Features

=====================================================

Hello and Welcome!

As one of the most popular programming languages today, Swift is widely used by developers across the globe to create everything from mobile apps to server-side applications. But did you know that Swift also has a range of hidden or lesser-known features that can help you write more efficient, streamlined, and expressive code? In this post, we'll explore some of these hidden gems of the Swift programming language and show you how to use them to your advantage.

Swift Basics

Playground Example

Using semicolon when writing multiple statement in the same line.

let hello = "Hello"; print(hello); let world = "World"; print(world)

When working with integers swift gives the possibility to get the min and the max of each type of integer.

print(UInt8.min) // 0
print(UInt8.max) // 255
print(Int8.min) // -128
print(Int8.max) // 127
print(Int.min) // minus value
print(Int.max) // maximum value
print(UInt32.max) // 4294967295

Touples are a way to group multiple values to a single compound value.

let toupleYear = (2034, "Future year")
print(toupleYear.0) // Printing first parameter
print(toupleYear.1) // Printing second parameter

let (param0, param1) = toupleYear
print(param0) // Printing first parameter
print(param1) // Printing second parameter

Optionals with shorter spelling to unwrap optional value

let optionalName: String? = nil
if let optionalName {
    print("My name is \(optionalName)")
}

Error handling

enum InfoErrors: Error {
    case wrongName
    case wrongVat
    case wrongAge
}

func insertMyName() throws -> Bool {
    throw InfoErrors.wrongName
}

do {
    try insertMyName()
} catch InfoErrors.wrongName {
    // an error was thrown
} catch InfoErrors.wrongVat {
    // an error was thrown
} catch InfoErrors.wrongAge {
    // an error was thrown
}

Assertions & Preconditions Assertions are checked only in debug builds, but preconditions are checked in both debug and production builds.

let name = "stupid"
assert(name != "stupid", "A person's name can't be unapropriate.")

let age = 18
precondition(age > 17, "Person must be adult.")

String and Characters

// String written in multiline
let multilineString = """
These are the same.
"""

// With wrapped quotation
let softWrappedQuotation = """
The White Rabbit put on his spectacles.  "Where shall I begin, \
please your Majesty?" he asked.

"Begin at the beginning," the King said gravely, "and go on \
till you come to the end; then stop."
"""

let lineBreaks = """

This string starts with a line break.
It also ends with a line break.

"""
// Three double quotation marks
let threeDoubleQuotationMarks = """
Escaping all three quotation marks \"\"\"
"""

// Three more double quotation marks
let threeMoreDoubleQuotationMarks = #"""
Here are three more double quotes: """
"""#

Indices

let greeting = "Guten Tag!"
greeting[greeting.startIndex]
greeting[greeting.index(before: greeting.endIndex)] // G
greeting[greeting.index(after: greeting.startIndex)] // !
let index = greeting.index(greeting.startIndex, offsetBy: 7) // u
greeting[index]

Inserting and Removing

var welcome = "hello world"
welcome.insert("!", at: welcome.endIndex) // welcome now equals "hello world!"
welcome.insert(contentsOf: " whats'up", at: welcome.index(before: welcome.endIndex)) // hello world whats'up!
welcome.remove(at: welcome.index(before: welcome.endIndex))
welcome
let range = welcome.index(welcome.endIndex, offsetBy: -15)..<welcome.endIndex
welcome.removeSubrange(range)
welcome

Substrings

// Substrings
let myNameAndProfession = "Harald Bregu, iOS Developer"
let index = myNameAndProfession.firstIndex(of: ",") ?? greeting.endIndex
let myNameOnly = myNameAndProfession[..<index]
myNameOnly // Harald Bregu
let newString = String(myNameOnly)
newString

Colletion types

Playground Example

Arrays

// Inserting data to an array in 3 ways
var simpleArray = ["Earth", "Moon"]
simpleArray.append("Mars")
simpleArray += ["Mercury"]
simpleArray += ["Venus", "Pluto"]

// Replacing items into array in 2 ways
simpleArray[0] = "Jupiter"
simpleArray[4...5] = ["Earth", "Saturn"]

Set collection type

// Remove duplicated items in an array with Set
var arrayWithDouplicatedItems = ["Apple", "Banana", "Kiwi", "Apple", nil]
var rem = Set(arrayWithDouplicatedItems)

Hidden Feature

Playground Example

Fallthrough

let skill = "programmer"
var description = "My skills are: \(skill), "

switch skill {
case "programmer", "datas cientist":
    description += "developer, "
    description += "data scientist"
    fallthrough
default:
    description += " and also a computer entusiast"
}
print(description)
// Prints "My skills are: programmer, developer, data scientist and also a computer entusiast\"

Functions with touple

func firstAndLastLetterOfMyName(string: String) -> (first: String, last: String)  {
    return (String(string.prefix(1)), String(string.suffix(1)))
}

firstAndLastLetterOfMyName(string: "Harald").first
firstAndLastLetterOfMyName(string: "Harald").last

In-Out Parameters

func swapTwoWords(_ a: inout String, _ b: inout String) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var myName = "Bregu"
var mySurName = "Harald"
print("My full name is: \(myName) \(mySurName)")
swapTwoWords(&myName, &mySurName)
print("My full name is: \(myName) \(mySurName)")

Closures

//There are 3 ways to use a closure
func sendCommand(callbackClosure: () -> Void) {

    // After sending command call closure
    callbackClosure()
}

sendCommand() {}

sendCommand {}

sendCommand(callbackClosure: {})

Enums

// Iterable and raw value
enum Nations: String, CaseIterable {
    case italy = "IT", germany = "DE", france = "FR"
}

// Get the count of the cases
print("\(Nations.allCases.count) nations")

// Print Raw Value
print(Nations.italy.rawValue)

// Get type by raw value
let possibleNation = Nations(rawValue: "IT")
if let possibleNation {
    
    print(possibleNation)
}

// Recursive enumeration
indirect enum StarSystem {
    case planets(Int)
    case star(Int)
    case satelites(Int)
    case add(StarSystem, StarSystem)
}

let numStars = StarSystem.star(2)
let numNearPlanets = StarSystem.planets(5)
let numSatelites = StarSystem.satelites(24)
let product = StarSystem.add(numStars, StarSystem.add(numNearPlanets, numSatelites))

switch product {
case .add(let first, let second):
    print(first)
    print(second)
    break
case .planets(_): break
case .star(_): break
case .satelites(_): break
}

Structures and Classes

Features Struct Classes
Define properties to store values
Define methods to provide functionality
Define subscripts to provide access to their values using subscript syntax
Define initializers to set up their initial state
Be extended to expand their functionality beyond a default implementation
Conform to protocols to provide standard functionality of a certain kind
Inheritance enables one class to inherit the characteristics of another
Type casting enables you to check and interpret the type of a class instance at runtime
Deinitializers enable an instance of a class to free up any resources it has assigned
Reference counting allows more than one reference to a class instance

Properties

There are 5 type of properties

  • Stored Properties
  • Lazy Stored Properties
  • Computed Properties
  • Read-Only Computed Properties
  • Property Observers
  • Property Wrappers

Property Wrappers

@propertyWrapper
struct SpeedLimit {
    private var number: Int
    private var maximum: Int
    private(set) var projectedValue: String
    var wrappedValue: Int {
        get { return number }
        set {
            if newValue < 50 && newValue >= 20 {
                number = newValue
                projectedValue = "Is on urban limits speed"
            } else if newValue < 20 {
                projectedValue = "Is very slow"
                number = newValue
            }  else if newValue > maximum {
                projectedValue = "Is faster than max limit"
                number = min(newValue, maximum)
            } else {
                projectedValue = "Is very fast"
                number = newValue
            }
        }
    }
    
    init() {
        projectedValue = "Is off"
        number = 40
        maximum = 300
    }
}

struct Car {
    @SpeedLimit var speed: Int
}

var myBMWCar = Car()
print(myBMWCar.$speed) // Prints "is off"
 
myBMWCar.speed = 40
print(myBMWCar.speed) // Prints "40"
print(myBMWCar.$speed) // Prints "Is on urban limits speed"

myBMWCar.speed = 100
print(myBMWCar.speed) // Prints "100"
print(myBMWCar.$speed) // Prints "is very fast"

myBMWCar.speed = 454
print(myBMWCar.speed) // Prints "300"
print(myBMWCar.$speed) // Prints "Is faster than max limit"

Subscript Syntax

struct CarPower {
    let powerkw: Double
    subscript(index: Double) -> Double {
        return powerkw * index
    }
}
let carPower = CarPower(powerkw: 80)
print("CarPower in horsepower is: \(carPower[1.35962])")

enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    static subscript(n: Int) -> Planet {
        return Planet(rawValue: n)!
    }
}

print(Planet[4])

Concurrency

import UIKit
import PlaygroundSupport
import _Concurrency

PlaygroundPage.current.needsIndefiniteExecution = true

func showSomeResults() async -> [Int] {
    (0..<99).map { _ in .random(in: 1...20) }
}

var result = await showSomeResults()

print(result)
PlaygroundPage.current.finishExecution()

About

A short and intuitive documentation about swift basics & hidden features

Topics

Resources

Stars

Watchers

Forks

Languages