Swift by example classes

import Foundation

class Example {
    var a = 0
    var b: String

    init(a: Int) { // Constructor
        self.a = a
        b = "name"                  // An error if a declared property isn't initialized
    }
}

External param names are required...
let eg = Example(a: 1)
print(eg.a)              // 1


...Unless the params are declared with leading underscores.

class Example2 {
    var a = 0
    var b = 0

    init(_ a: Int, _ b: Int) {
        self.a = a
        self.b = b
    }
}

let eg2 = Example2(1, 2)
print(eg2.a)            // 1
print(eg2.b)            // 2


# Lazy properties

 
Lazy properties' initial value aren't
 
initialized until the first time the
 
property is accessed.

class Podcast {
    lazy var episode = Episode() // `var` declaration is required.
}

class Episode {
    var audio = "somefile.mp3"
}

var podcast = Podcast()          // episode has not been initialized yet.
print(podcast.episode.audio)   // somefile.mp3

# Computed properties

 
Computed properties don't store a value. Instead, getters / setters
 
are provided to retrieve and set _other_ properties.

class Window {
    var x = 0.0, y = 0.0
    var width = 100.0, height = 100.0

    var center: (Double, Double) {
        get {
            return (width / 2, height / 2)
        }

        set(newVal) {
            x = newVal.0 - (width / 2)
            y = newVal.1 - (height / 2)
        }
    }
}

var win = Window()
print(win.center)               // (50.0, 50.0)
win.center = (0.0, 10.0)
print(win.x)                    // -50.0
print(win.y)                    // -40.0

The param to set can be omitted and a magic "newValue"
 
can be used to referenced the new value.
/*
set {
x = newValue.0 - (width / 2)
}
*/

# Read-only computed properties


class Song {
    var title = ""
    var duration = 0.0
    var metaInfo: [String:String] {
        return [
            "title": self.title,
            "duration": NSString(format: "%.2f", self.duration) as String,
        ]
    }
}

var song = Song()
song.title = "Rootshine Revival"
song.duration = 2.01
print(song.metaInfo["title"]!)    // Rootshine Revival
print(song.metaInfo["duration"]!) // 2.01

# Property Observers

 
Property observers can be added onto any properties
 
(including inherited) except for lazy computed props.

class Website {
    var visitors: Int = 0 {             // An explicit type is required
        willSet(newVisitorCount) {          // Called before the prop is set
            visitors = newVisitorCount + 1  // Warning. Can't set within its own willSet
        }
        didSet {                            // Called after a new val is set
            print(visitors - oldValue)    // oldValue is magically defined
        }
    }
}

var site = Website()
site.visitors = 1
print(site.visitors)                 // 1

# Type Properties

 
AKA class variables
class Body {
    /*    class var age = 0                 // error: class variables not yet supported */
    // Computed type property
    class var size: Int {
        return 10
    }
}
print(Body.size)                     // 10

# Type Methods

 
AKA class methods
class Banana {
    var color = "green"
    class func genus() -> String {
        return "Musa"
    }
}
print(Banana.genus())                // Musa

# Instance methods


class Month {
    var name: String

    init(name: String) {
        self.name = name
    }

    func shortened() -> String {
        return name[name.startIndex..<advance(name.startIndex, 3)]
    }
}
print(Month(name: "January").shortened())    // Jan

# Inheritance

 
Swift classes do not inherit from a universal base class.

class Bicycle {
    var tireWidth: Double
    var topSpeed: Double
    var name: String
    var gears: Int
    // Marking a method/property with `@final` prevents it from being overridden
    final var color = "green"

    init() {
        tireWidth = 30.5
        topSpeed = 10.0
        name = "regular ol' bike"
        gears = 3
    }

    func go(distance: Double) {
        print("Went \(distance) at a top speed of \(topSpeed) in my \(name)")
    }
}

class MountainBike : Bicycle {
    /* var tireWidth = 64.0 // Cannot override property in the declaration */
    override init() {
        super.init()

        tireWidth = 64.0
        name = "mountain bike"
        gears = 12
    }
    // Override parent's methods via `override` keyword
    override func go(distance: Double) {
        super.go(distance)
        print("Did \(distance) on a mountain bike")
    }

    // A getter/setter override can _any_ inherited property.
    override var topSpeed: Double {
        get {
            return super.topSpeed - 4.0
        }
        set {
            super.topSpeed = newValue
        }
    }

    // Property observer
    override var gears: Int {
        didSet {
            print("Gears was changed to \(gears)")
        }
    }
}

var mountainBike = MountainBike()              // Gears was changed to 12
mountainBike.topSpeed = 6.0
print(mountainBike.topSpeed)                 // 2.0
mountainBike.go(12.0)                          // Went 12.0 at a top speed of 10.0 in my mountain bike
Did 12.0 on a mountain bike
 

# Initializers

 
'Convenience' initializers overload empty
 
initializers that populate the params
 
in 'designated' initializers.

class iOS {
    var version: String

    init(version: String) {
        self.version = version
    }

    convenience init() {
        self.init(version: "8.0.0")
    }
}

var os = iOS()
print(os.version)                          // 8.0.0

# ARC and reference cycles

 
Strong reference cycles happen when two objects
 
hold strong references to each other so that neither
 
can be deallocated (à la memory leaks in garbage collected langs)
 
Strong references can be resolved by declaring
 
references as weak or unowned
 
Use a weak reference whenever it's valid for the reference
 
to be nil at any point. These are optional types.

class Driver {
    weak var car: Car? // Strong reference to car.

    deinit {
        print("Driver deinitialized")
    }
}

class Car {
    weak var driver: Driver? // Weak reference to driver.

    deinit {
        print("Car deinitialized")
    }
}

var driver: Driver?
var car: Car?

driver = Driver()
car = Car()
driver!.car = car
car!.driver = driver

driver = nil               // No more strong references to driver.
car = nil                  // No more strong references to car.

Unowned references are like weak references except they always
 
refer to a value, so they're non-nil.

class Artist {
    var instrument: Instrument?  // Strong reference to instrument.
}

class Instrument {
    unowned let artist: Artist   // Unowned reference to artist.
    init (artist: Artist) {
        self.artist = artist
    }
}

var artist: Artist?
artist = Artist()
artist!.instrument = Instrument(artist: artist!)

artist = nil        // Both objects are deallocated since there are no more strong references.

# Access control

 
Access control in Swift is very much package-based.
 
private: Can only be accessed from the same source file that it's defined
 
internal: Can be accessed anywhere in the target it's defined
 
public: Accessible anywhere in the target and anywhere its module is imported
 
Defaults to internal if not explicitly declared.

internal class Image { // Accessible in the same target
    internal var name : String

    private var mime : String {     // Accessible only in this file. Never settable.
        get {
            return "image/\(name.pathExtension)"
        }
    }

    init(name: String) {
        self.name = name
    }
}
var img = Image(name: "foo.png")

public class Webpage {
    public var title : String
    public var created : NSDate
    private(set) var images : [Image] // Readable within the same target but only writable in this file
    var slug : String {
        return created.description + title
    }

    init(title: String) {
        self.title = title
        self.created = NSDate()
        self.images = []
    }
}

var webPage = Webpage(title: "blog post")
webPage.images.append(Image(name:"panda.gif"))