-->

Swift Notes - The Basics

dev ios, swift

When I started learning Swift for iOS development I also started to compile some notes along the way. This post is the first instalment of my notes. First some basic concepts (in no particular order):

REPL

  • Swift supports REPL (Read Evaluate Print Loop) and you can write code and get feedback very quickly this way by using XCode Playground or command line.

As seen in the screenshot there is no need to explicitly print the values, they are automatically displayed on the right-hand side of the screen.

It can also be executed without specifying the interpreter by adding #!/usr/bin/swift at the top of the file.

Comments

Swift supports C-style comments like // for single-line comments and /* */ for multi-line comments.

The great thing about the multi-line comments is that you can nest them. For example the following is a valid comment:

/* This is a 
    /* valid mult-line */
    comment that is not available in C#
*/

Considering how many times Visual Studio punished me while trying to comment out a block of code that had multi-line comments in it, this feature looks fantastic!

It also supports doc comments (///) and supports markdown. It even supports emojis (Ctrl + Cmd + Space for the emoji keyboard)

Imports

Standard libraries are imported automatically but the main frameworks such as Foundation, UIKit need to be imported explicitly.

Swift 2 supports a new type of import which is preceded by @testable keyword.

@testable import CustomFramework

It allows to access non-public members of a class. So that you can access them externally from a unit test project. Before this they all needed to be public in order to be testable.

Strings

Built-in string type is String. There is also NSString in the Foundation framework. They can be used interchangably sometimes, for example you can assign a String to a NSString but the opposite is not valid. You have cast it explicitly to String first:

import Foundation

var string : String = "swiftString"
var nsString : NSString = "foundationString"

nsString = string // Works fine
string = nsString as String // Wouldn't work without the cast
  • startIndex is not an int but an object. To get the next character

s[s.startIndex.successor()]

To get the last character

s[s.startIndex.predecessor()]

For a specific position s[advance(s.startIndex, 1)]

let vs. var

Values created with let keyword are immutable. So let is used to create constants. Variables can be created with var keyword. If you create a value

let x1 = 7
x1 = 8 // won't compile

var x2 = 10
x2 = 11 // this works

The same principle applies to arrays:

let x3 = [1, 2, 3]
x3.append(4) // no go!

Type conversion

Types are inferred and there is no need to declare them while declaring a variable.

let someInt = 10
let someDouble = 10.0
let x = someDouble + Double(someInt)

Structs and Classes

  • Structs are value objects and a copy of the value is passed around. Classess are reference objects.

  • Constructors are called initializers and they are special methods named init. Must specify an init method or default values when declaring the class.

class Person {
  var name: String = ""
  var age: Int = 0

  init (name: String, age: Int) {
    self.name = name
    self.age = age
  }
}
  • There is no new operator. So declaring a new object looks simply like this:
let p = Person()
  • The equivalent of destructor is deinit method. Only classes can have deinitializers.

Collections

Array: An ordered list of items

  • An empty array xan be declared in a verbose way such as

      var n = Array<Int>()
    

    or with the shorthand notation

      var n = [Int]()
    
  • An array with items can be intialized with

      var n = [1, 2, 3]
    
  • Arrays can be concatenated with +=

      n += [4, 5, 6]
    
  • Items can be added by append method

      n.append(7)
    
  • Items can be inserted to a specific index

      n.insert(8, atIndex: 3)
      print(n) // -> "[1, 2, 3, 8, 4, 5, 6, 7]"
    
  • Items can be deleted by removeAtIndex

      n.removeAtIndex(6)
      print(n) // -> "[1, 2, 3, 8, 4, 5, 7]"
    
  • Items can be accessed by their index

      let aNumber = n[2]
    
  • A range of items can be replaced at once

      var n = [1 ,2, 3, 4]
      n[1...2] = [5, 6, 7]
      print(n) // prints [1, 5, 6, 7, 4]"
    
  • 2-dimensional arrays can be declared as elements as arrays and multiple subscripts can be used to access sub items

      var n = [ [1, 2, 3], [4, 5, 6] ]
      n[0][1] // value 2
    

Dictionary: A collection of key-value pairs

  • Can be initialized without items

      var dict = [String:Int]()
    

    or with items

      var dict = ["key1": 5, "key2": 3, "key3": 4]
    
  • To add items, assign a value to a key using subscript syntax

      dict["key4"] = 666
    
  • To remove an item, assign nil

      dict["key2"] = nil
      print(dict) // prints ["key1": 5, "key4": 666, "key3": 4]"
    
  • To update a value, subscript can be used as adding the item or updateValue method can be called.

    updateValue returns an optional. If it didn’t update anything the optional has nil in it. So it can be used to check the value was actually updated or not.

      var result = dict.updateValue(45, forKey: "key2")
      if let r = result {
          print (dict["key2"])
      } else {
          print ("could not update") // --> This line would be printed
      }	
    

    The interesting behaviour is that if it can’t update it, it will add the new value.

      var dict = ["key1":5, "key2":3, "key3":4]
      var result = dict.updateValue(45, forKey: "key4")
      if let r = result {
          print (dict["key4"])
      } else {
          print ("could not update")
      }
    	
      print(dict) // prints "["key1": 5, "key4": 45, "key2": 3, "key3": 4]"
                    // key4 has been added after calling updateValue
    

    After a successful update it would return the old value

      result = dict.updateValue(45, forKey: "key1")
      if let r = result {
          print (r) // --> This would run and print "5"
      } else {
          print ("could not update")
      }
    

    This is consistent with the unsuccessful update returning nil. It always returns the former value.

  • To get a value subscript syntax is used

      var i = dict["key1"] // 45
    

Set: An unordered list of distinct values

  • Initialization notation is similar to the others

      var emo : Set<Character> = [ "😡", "😎", "😬" ]
    
  • If duplicate items are added it doesn’t throw an error but prunes the list automatically

      var emo : Set<Character> = [ "😡", "😎", "😬", "😬" ]
      emo.count // prints 3
    
  • New items can be added with insert method

      var emo : Set<Character> = [ "😡", "😎", "😬", "😬" ]
      emo.insert("😱")
      emo.insert("🤔")
      print(emo) // prints "["😱", "😎", "🤔", "😬", "😡"]"
    

    There is no atIndex parameter like array and the index is unpredicatable as shown above

Among the three, only arrays have ordered and can have repeated values.

Miscellaneous

  • Semi-colons are not required at the end of each line

  • Supports string interpolation

  • Swift uses reference counting and there is garbage collection.

  • Curly braces are required even if there is only one statement inside the body. For instance the following block wouldn’t compile:

      let x = 10
      if x == 10
          print("Ten!")
    
  • println function has been renamed to print. print adds a new line to the end automatically. This behaviour can be overriden by explicitly specfying appendNewLine attribute

      print ("Hello, world without a new line", appendNewLine: false)
    
  • #available can be used to check compatibility

      if #available(iOS 9, *) {
          // use NSDataAsset
      } else {
          // Panic!
      }
    
  • Range can be checked with … and ~= operators. For example:

      let x = 10
    	
      if 1...100 ~= x {
          print(x)
      }
    

    The variable is on the right in this expression. It wouldn’t compile the other way around.

  • There is Range object that can be used to define, well, ranges!

      var ageRange = 18...45
      print(ageRange) // prints "18..<46"
      print(ageRange.count) // prints "28"
    

    The other range operator is ..< which doesn’t include the end value

      var ageRange = 18..<45
      ageRange.contains(45) // prints "false"
    

Resources