IngmarBoddington
8/2/2017 - 4:16 PM

Swift

Swift notes from iOS dev learning - assumes Java knowledge. Test apps are here: https://github.com/IngmarBoddington/XcodeProjects

General
======
- Strongly typed, object oriented
- Semi-colons are optional to end statements
- // or /* */ for comments
- Used across Apple platforms
- Execution starts in main.swift
- Libraries imported using import statements
- Can use any unicode character in names
- Short circuits evaluations of conditional statements
- Functions and tuples are unnamed compound types (all others are named types)
- Any names type can have methods (classes, structs, enums)

Variables + Simple Types / Operators
=====
All variables are value types, except objects which are reference types

Standard Types
    String (Double quoted)
    Int (Also Int8, Int16... and UInt8, UInt16...)
    Double (inferred by default over Float)
    Float
    Boolean
    
Integer literals
    Decimal, e.g. 234
    Binary, e.g. 0b101
    Octal, e.g. 0o76
    Hexadecimal, e.g. 0xA3
        
Floating-point literals
    Decimal, e.g. 32.4
    Exponent, e.g. 1.5e2
    Hexadecimal, e.g. 0x1Fp2

Use var for variables or let for constants
    var <identifier> = <value>
    let <identifier> = <value>

//define explicit type using ':' - This is generally not required for simple types
var string: String = "I am a string"
  
//Can mix on same line
var varOne = 1, varTwo = 2, varThree: Int
  
Can define without initialising (but must be initialised before use)
  
Variables can generally be cast by using initialisers for the various types:
    Int(<value>) //Will truncate floating point numbers
    String(<value>)
    etc 
  
Standard Maths Operators / logic
    = //Does not return any value on assignment / fail
    +,-,*,/,%
    <,>,<=,>=,==
    ||,&&,!
    ===, !==
    ( condition ? A : B )
    x...y //Range, Ints only
    x..<y //Range (not including value of y), Ints only

Can use _ to represent a temp variable which is not used (e.g iterator in for loop)

Strings
=====
var str = "Hello";
  
//Iterate over characters and print
for character in newString.characters {
  print(character, "Can", "add", "more (spaces are added automatically)");
}

//Optionally add separator / terminator
print("hello", "this is", "a", "test", separator: "||", terminator: "***")
  
//Create a string with manipulation methods
var newTypeString = NSString(string: newString);
  
//Substring
NSString(string: newTypeString.substring(from: 6)).substring(to: 4);

//Substring
newTypeString.substring(with: NSRange(location: 6, length: 4));

//Matching
if newTypeString.contains("Dave") {
  print("String contains Dave");
}

//Split into array
newTypeString.components(separatedBy: " ");

//Case
newTypeString.uppercased
newTypeString.lowercased

//Interpolate in Strings, concatenate strings
var string = "My age is \(age)" + ", more"

Collections
=====
    //Arrays - stupid number of ways to create
    //Value type (but only copied when needed as an optimisation)
    var a1:[Int] = [Int]()
    var a2:[Int] = [Int](repeating: 10, count: 4)
    var myArray:Array<Int> = Array<Int>()
    vara3:Array<Int> = Array<Int>(repeating: 0, count: 5)
    var myArray = [1, 2, 3, 4]
    let myArray: [Int] = Array(1...50);
    myArray[1] === 2
    myArray[1...3] = [3,4,5,6,7] //Can do daft range expansion
    array.count
    array.isEmpty
    array.removeLast()
    array.append(<value>)
    array.remove(at: <index>)
    
    //Dictionaries
    varenglishFrench: Dictionary<String,String>
    var myDic = ["key" : "value", "key2" : "value"]
    myDic["newKey"] = <value>
    myDic.removeValue(forkey: "key")
    myDic.updateValue(forkey: "key") //Will add and return null if didn't exist
    myDic.keys
    myDic.values   
  
    //Sets
    //A set can only store types that conform to the Hashableprotocol and an implementation of ==(the “is equal to” operator) (Most types are hashableby default)
    var myCustomers= Set<String>()
    var myFriends: Set<String> = Set<String>()
    myFriends.insert("John"); myFriends.insert("Duncan"); myFriends.insert("Pam")
    var yourFriends: Set = ["Pam", "Paul", "Keith"]
    var numbers: Set<Int> = [10,20,30]
    numbers = [] // numbers is now an empty set  
    let setA: Set = [1,2,3,4]
    let setB: Set = [3,4,5,6]
    var res = setA.union(setB) // [1,2,3,4,5,6]
    res = setA.subtracting(setB) // [1,2]
    res = setA.intersection(setB) // [3,4]
    res = setA.symmetricDifference(setB) // [1,2,5,6]
  
    //All collections must have types, var / let determine if mutable
    var myArray : [<type>]
    var myDic : [<keyType> : <valueType>]
    QOWDJIOQWJDOIW

Control Structures
==================
Use break to exit a loop
Use continue to skip to next loop

//If
if <condition> {
  //If true
}

//If / else
if <condition> {
  //If true
} else {
  //if False
}

//If / else-if
if <condition> {
  //If true
} else if <condition> {
  //if true
} else {
  //if False
}

//While loop
while <condition> {
  //Stuff
}

//Do-While loop
do {
    //Stuff
} while <condition>

//Iterate over array or a range
for <identifier> in <arrayIdentifier|range> {
  //Stuff with <identifier>
}

//Iterate over dictionary tuples
for (<indexIdentifier>, <valueIdentifier>) in <arrayIdentifier>.enumerate() {
  //Stuff with <indexIdentifier> / <valueIdentifier>
}

//Switch statement - must be exhaustive (e.g. Int switch will have to have a default)
//Skips rest of case statements on match
switch variable {
    case value1:
        //Stuff
    case value2:
        //Stuff
    case x...y: //Can use ranges
        //Stuff
    case x, y, z:
        //Stuff
    case var m where m < 0 || m > 100: //Can use a where clause with temp variable
        //Stuff
    default:
        //Stuff
}

//Loops can be labelled to allow for use of break at parent levels
outerLoop: for i in 1...5 {
    for j in 1...5 {
        if i == 3 && j == 2 {
            break outerLoop
        } else {
            print("i is \(i) and j is \(j)")
        }
    }
}

Functions
=====
Return definition required if the function has a return statement

//Func with return and two params (one with a defined external naming which overrides the internal name when invoking function)
//Can use _ as external name which means that no parameter naming is required when invoking function
func funcName (varInternalName: Int, varExternalName varInternalNameTwo: String) -> resultType {
    statements
    return value:resultType
}

//With a default value
func funcName (varInternalName: Int = 8) -> resultType {
    statements
    return value:resultType
}

//Variadic parameters
func myFunc(something: Int...) {
    //Stuff
}
myFunc(1,2,3,4)

//Pass by reference
func swapNums(num1:inout Int, num2:inout Int) {
    let temp = num1
    num1 = num2
    num2 = temp
}
swap(&x, &y)

//Type description
(Type, Type, Etc) ()
(Type, Type, Etc) -> Type
(Type, Type, Etc) -> (Type, Etc)

//Can set to var
var sillyFunc = { (a: Int, b: Int) -> Bool in a > b) }

//SHhrtest closure form example - params are zero index, types and return have been inferred
sortedNumList= numList.sorted(by: { $1 < $0 })
sortedNumList= numList.sorted(){ $1 < $0 }

Optionals
=====
- Values which can be nil / not set
- To force unwrap use exclamation mark after variable - reverts to type from optional

//Define:
var variable: Type?
let variable: Type?

//Can test with standard nil checks or:
if let variable = optional {
  /...
} else {
  /...
}

Tuples
======
Simple unnamed strongly typed data structure
  Can be nested
  e.g. var myTuple = ("I Am A Tuple", (10, 5))
  Access using zero index
    myTuple.0 //I Am A Tuple

Can use in switch statement
  switch myTuple {
    case ("Meh", (10, 5):
      //No match
    case (_, let(first, second)):
      //Hit and disregards first value in tuple and inits first and second vars
    case (_, let(first, second)) where <logic>
      //etc
    default <etc>
      //etc
  }

Access Modifiers
=====
Access (to variables and types) can be controlled with the keywords open, public, private, fileprivate, and internal
Default is internal
Open access and public access enable entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. You typically use open or public access when specifying the public interface to a framework.
Internal access enables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure.
File-private access restricts the use of an entity to its own defining source file. Use file-private access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.
Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.

Classes
====================
All classes must have a designated initialiser (a constructor)
Any other (optional) initialisers must be marked as "convenience" and call the designated initialiser
One is provided if no parameters or all parameters have default
All parameters must either have a default or be set by the designated initialiser
Can declare properties or method as static

class ClassName {
    var property
  
    //"Designated" initialiser
    init(property: Int){
        //
    }
    
    //Optional "Convenience" initiliser
    convenience init()
        self.init(property: 5)
    }

    func method(vars) {
        //....
    }
}

var class = ClassName(5)
class.method(vars)

Methods can have same name, different parameter types / names /  defaults
Classes can have a deinit destructor method with no args too
Properties can be marked as lazy (only calculated when needed)
    lazy var value = Expensive()
Properties can be normal "stored" properties or "computed" properties

//Computed property (get / set)
var value: Int {
    get {
        //
    }
    set (valueName) {
        //will get newValue if no valueName given
    }
//

//Get only, do not need to include block:
var value: Int {
    //
}

Can "adopt" protocols or inherit from parent classes
Methods which override an existing parent method must start with 'override' keyword

class myClass: parentClassOrProtocol {
    init() {
        self.stuff()
        super.stuff()
    }
}

Protocols
=====
Interfaces, basically. Classes can adopt as many as they like

protocol {
    func funcName() -> Type
    var variable: Int
}

Extensions
=====
Add to source without altering original code
Cannot use stored properties
Can adopt a protocol to make a class adopt it

extension classBeingExtended {
    //Code
}

Structures
======
Extremely similar to classes in definition (includes all of the above syntax)
Value type, not reference like object
Cannot use inheritance
A default initializer and a memberwiseinitializer are automatically generated (if none defined)
Memberwise is simply ordered constructor with all params of the struct
Methods which change state must be marked as mutating (as value types should be immutable)
    mutating method(vars) {
        //can replace entire instance
        self = ckass(changesVars)
    }
Can aggregate further structs (can access using chained dot operators)
    parent.child.parameter

Enumerations
=====
Extremely similar to classes in definition (includes all of the above syntax) - but defines a set

//Example with days of week and 1 -> 7 as rawValues (access Key)
enum WeekDay:Int {
    case Monday=1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}

var day = enum.Monday
let todayNum= day.rawValue
varday4 = WeekDay(rawValue: 4) //Returns an optional

//Can shortcut when used in switch statements:
switch day {
    case .Monday:
        //Stuff
    case .Tuesday:
        //Stuff
    ...
    default:
        //Stuff
}

//Can also have different states as tuples
enum State {
    case Start(String)
    case DoWork(Int, Int, Int)
    case End(String, Int)
}
vartheState: State = State.Start("about to start the work")
theState = State.DoWork(3,4,5)
theState = State.End("Finished", result)

Error Handling
=====
Enums which implement "Error" can be thrown and caught
Code must state (using try) when calling a method which may throw

enum myError: Error {
    case IllegalArgs(args: [String])
    case ...
}

func funcWhichCanThrow() {
    throw myError.IllegalArgs(["Meh"])
}

do {
    try funcWhichCanThrow
} catch myError.IllegalArgs {
    //
}

//Will always be executed even if error in surrounding block
defer {
    //
}}

//Converts result to null on exception throw
let var = try? func()

//Error suppression! :(
try! func()

//Guard statements (inverse if for error catching generally)
guard <condition> else {
    //code, throw maybe
}

Generics
=====
Generally use T symbol but can use anything

class sillyClass<T> {
    init() {
        //Do stuff with type T
    }
    
    ...
}

//Forcing adherence to type
class sillyClass<T: Type> {
    init() {
        //Do stuff with type T
    }
    
    ...
}

func genericSwap<T>(_ item1 : inoutT, _ item2 : inoutT) {
    let temp = item1
    item1 = item2
    item2 = temp
}

//Adding further constraints
func myFunc<T1: Sequence where T1.Generator.Element : Person>(theList: T1) -> T1.Generator.Element? {
    //Stuff
}

Other Stuff
-----
arc4random_uniform(<limit>) //Random nums

--------------------------------------------------------------
iOS APIs / XCode

View Controllers
=====
Common methods:
  viewDidLoad - Initial load delegate method
  viewDidAppear - User navigated to view delegate method
  didReceiveMemoryWarning - 

Actions
=====
A method which is invoked by an event (managed / brough in through the storyboard
  @IBAction <definition>

Outlets
=======
A property representing a view item which can be manipulated
  @IBOutlet <definition>
  
Table Views
=====
Need to extend UITableViewDelegate, UITableViewDataSource and implement:

  public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
  -> Return number of rows in table view
  public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
  -> Return content of a cell

Use <tableView>.reloadData(); to update the table with any changes

An example delete swipe:

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        
        if editingStyle == UITableViewCellEditingStyle.delete {
            items.remove(at: indexPath.row);
            UserDefaults.standard.set(items, forKey: "list")
            self.tableList.reloadData();
        }
    }
    
Web View
=====
Example load URL in webview:
  let url = URL(string: "http://www.stackoverflow.com")!;
  <webviewOutlet>.loadRequest(URLRequest(url: url));
  
Example load HTML:
  <webviewOutlet>.loadHTMLString("<h1>Hello World!</h1>", baseURL: nil);

Note (if insecure content error, can add exception):
  https://stackoverflow.com/questions/31254725/transport-security-has-blocked-a-cleartext-http
  
Example scrape (asynchonous):

  if let url = URL(string: "http://www.stackoverflow.com") {
      
      let request = URLRequest(url: url);
      
      let task = URLSession.shared.dataTask(with: request) {
          data, response, error in
          
          if error != nil {
              print(error!);
          } else {
              if let unwrappedData = data {
                  let dataString = NSString(data: unwrappedData, encoding: String.Encoding.utf8.rawValue);
                  print(dataString!);
              }
          }
      }
      
      task.resume();
  }

Persistant Storage
=====
UserDefaults
  UserDefaults.standard.set(<value>, forKey: <key>);
  - Save a value
  let <object> = UserDefaults.standard.object(forKey: <key>);
  - Fetch a value object
  
Use a let check to ensure a value is set before use when fetching from store

Keyboard Control
=====
To close keyboard when user taps off the keyboard:
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true);
    }
    
To close keyboard on return tap, need to extend UITextFieldDelegate and 
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder();
        return true;
    }
    
Timers
======
Set a timer using normally
  Timer.scheduledTimer(timeInterval: <#T##TimeInterval#>, target: <#T##Any#>, selector: <#T##Selector#>, userInfo: <#T##Any?#>, repeats: <#T##Bool#>)
  
Stop a timer using:
  <Timer>.invalidate();
  
e.g.
  if (self.started == false) {
      self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.tickerFunction), userInfo: nil, repeats: true)
      self.buttonText.setTitle("Stop!", for: .normal);
  } else {
      self.timer.invalidate();
      self.buttonText.setTitle("Start!", for: .normal);
  }
  
Animation
=====
(Use above timer methods)
Set a new image for an UIImageView:
  self.image.image = UIImage(named: <string>);
  
Simple fade in example:
    @IBAction func fadeIn(_ sender: Any) {
        <image>.alpha = 0;
        UIView.animate(withDuration: <time>, animations: {
            <image>.alpha = 1;
        })
    }
    
Simple slide in example (from left):
    @IBAction func slideIn(_ sender: Any) {
        <image>.center = CGPoint(x: image.center.x - <offscreenValue>, y: image.center.y);
        UIView.animate(withDuration: <time>, animations: {
            <image>.center = CGPoint(x: self.image.center.x + <offscreenValue>, y: self.image.center.y)
        })
    }

Simple grow example (from top left)
    @IBAction func grow(_ sender: Any) {
        <image>.frame = CGRect(x: 0, y: 0, width: 0, height: 0);
        UIView.animate(withDuration: 5, animations: {
            <image>.frame = CGRect(x: 0, y: 0, width: 200, height: 200);
        })
    }