Swift 4
JaxARCSIG January 2018
Jyoti couldn't be here tonight
About Me
- David Fekke
- Chief Mobile Architect for Swyft Mobile
- Co-Organizer for JaxNode User Group
Chris Lattner
About Swift Lang
- Created by Chris Lattner at Apple
- Released in 2014
- Open Sourced in 2015
- Meant to make it easier for Apple Dev
- Runs on macOS, iOS, Linux and Windows 10
Swift Goals
- One language to Rule Them All
- Alternative to Objective-C and C++
- Easy to learn
- Can be used to build an OS
- statically typed and has type inference
- Uses LLVM compiler
- Has functional features like Scala
Swift History
- Started after Clang finished in 2010 in secret
- publicly released 2014, v1.0
- 2015 Swift 2 released, open sourced
- IBM announced support
- 2016 Swift 3.0 released, not backwards compatible
- Swift 4.0, backwards compatible with 3.0
- Added better String support, Codable
- Swift 5.0, ABI compatibility
Swift Tools
- Xcode and LLVM
- REPL
- Swift Package Manager (SPM)
OS Support
- macOS, iOS, watchOS and tvOS
- Linux (Ubuntu)
- Windows 10
Hello World !
print("Hello World!")
Variable assignment
// Use var for mutable values
var name = "David"
var age = 29
// change values
name = "Dave"
age = 30
// Use let for immutable values
let myName = "Bob"
let myAge = 41
// trying to change the assignment
myName = "Bobby" // will return an error
Type Safe
- Swift is type safe
- Swift compiler will infer the type if not specified
- Type can be specified in variable declaration
let str1 = "David"
var str2: String = "David"
str2 = "Dave"
// Use ! or ? to make type optional
var str3: String? = "David"
str3 = nil
str3 = "Dave"
Collection types
// Basic Array
let myArray = ["Dog", "Cat", "Bird", "Snake"]
// Dictionary
let myDict = ["Bob": 42, "Joe": 40, "Karen": 39, "John": 35]
// Empty Array
var emptyArray: [String]
emptyArray = myArray
// emptyDictionary
var emptyDict: [String:Int]
emptyDict = myDict
Control Flow
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
Control Flow cont.
var elevator = 0
let topFloor = 11
while elevator < topFloor {
print("Elevator is on the \(elevator) floor")
elevator += 1
}
// ++ is an illegal unary operator in Swift
Ranges
for i in 1...9 {
print("Number \(i)")
}
// the same as
for i in 1..<10 {
print("Number \(i)")
}
// Can also increment by more than 1 at a time
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
print("render the \(tickMark) every 3 hours") // (3, 6, 9, 12)
}
Conditionals
let myNumber: Int = 32
if myNumber <= 33 {
print("under or equal to 33")
} else {
print("Older than 33")
}
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
Optionals
class Starship {
var prefix: String?
}
let ncc1701 = Starship(prefix: "USS")
let prefix: String = ncc1701.prefix
// Will get a type error because prefix is an optional
let prefix: String = ncc1701.prefix!
// force unwrap will work if there is a value, but considered a bad practice
if let prefix: String = ncc1701.prefix {
print(prefix) // USS
}
guard let prefix2 = ncc1701.prefix else {
print("prefix2 could not be set")
}
Error handling
func someThrowingFunction() throws -> Int {
// ...
}
let x = try? someThrowingFunction()
let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}
Functions
func printThisValue(_ param: String) {
print("Printing value \(param)")
}
printThisValue("Gato")
// "Printing value Gato"
func say(this param: String) {
print(param)
}
say(this: "Hello Jax ARCSIG")
// "Hello Jax ARCSIG"
Functions Cont.
func adder(_ first: Int, add second: Int) -> Int {
return first + second
}
let addedValue = adder(32, add:49)
print("Added value \(addedValue)")
Generics
func swapTwoStrings(_ a: inout String, _ b: inout String) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
let temporaryA = a
a = b
b = temporaryA
}
// Be changed to one function
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
var bob = "Bob"
var doug = "Doug"
swapTwoValues(&bob, &doug)
print(bob) // Doug
Closures
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
var reversedNames = names.sorted(by: backward)
// reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]”
reversedNames = names.sorted(by: { (string1: String, string2: String) -> Bool
in return string1 > string2 })
reversedNames = names.sorted(by: { (string1, string2) in return string1 > string2 })
reversedNames = names.sorted(by: { (string1, string2) in string1 > string2 })
reversedNames = names.sorted(by: { $0 > $1 })
reversedNames = names.sorted(by:) { $0 > $1 }
reversedNames = names.sorted(by:>)
Structs
struct Rectangle {
let width: Float
let height: Float
}
let myRect = Rectangle(width: 40.0, height: 30.0)
print("the width of the rect is \(myRect.width)")
Structs Cont.
struct RectangleWithArea {
var width: Float
var height: Float
var area: Float {
return width * height
}
}
let myRect2 = RectangleWithArea(width: 40.0, height: 30.0)
print("the area of the rect is \(myRect2.area)")
Structs can have Methods
struct Person {
let name: String
func sayName() {
print("This person's name is \(name)")
}
}
let debbie = Person(name: "Debbie")
debbie.sayName()
Classes
class Person {
var firstName: String
var lastName: String
var age: Int
init(first firstName: String, last lastName: String, age: Int) {
self.firstName = firstName
self.lastName = lastName
self.age = age
}
func describePerson() -> String {
return "\(self.firstName) \(self.lastName) is \(self.age) years old"
}
}
let john = Person(first: "John", last: "Lyons", age: 42)
let personDesc = john.describePerson() // "John Lyons is 42 years old
Inheritance
class Employee : PersonComponent {
var employeeId: Int?
init(first firstName: String, last lastName: String, age: Int, id employeeId: Int?) {
self.employeeId = employeeId
super.init(first: firstName, last: lastName, age: age)
}
convenience init() {
self.init(first: "firstName", last: "lastName", age: 0, id: nil)
}
}
let rich = Employee(first: "Richard", last: "Dutton", age: 62, id: 8907890)
let empDesc = rich.describePerson()
print(empDesc)
Enums
enum CompassPoint {
case north
case south
case east
case west
}
var directionToHead = CompassPoint.west
switch directionToHead {
case .north:
print("Lots of planets have a north")
case .south:
print("Watch out for penguins")
case .east:
print("Where the sun rises")
case .west:
print("Where the skies are blue")
}
// Prints "Where the skies are blue"
Extentions
extension Double {
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is \(oneInch) meters")
// Prints "One inch is 0.0254 meters”
Protocols
protocol FullyNamed {
var fullName: String { get }
}
struct Person: FullyNamed {
var fullName: String {
return name
}
}
let johnApple = Person(fullName: "John Appleseed")
class Starship: FullyNamed {
var prefix: String?
var name: String
init(name: String, prefix: String? = nil) {
self.name = name
self.prefix = prefix
}
var fullName: String {
return (prefix != nil ? prefix! + " " : "") + name
}
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
Codable
struct Swifter: Decodable {
let fullName: String
let id: Int
let twitter: URL
}
let json = """
{
"fullName": "Federico Zanetello",
"id": 123456,
"twitter": "http://twitter.com/zntfdr"
}
""".data(using: .utf8)! // our data in native (JSON) format
let myStruct = try JSONDecoder().decode(Swifter.self, from: json)
// Decoding our data
print(myStruct.fullName) // decoded!!!!!
Swift 5
- Async manifesto
- Async and Await keywords
- ABI stability
Memory Management
- Apple used to have Garbage Collection
- GC not allowed in iOS, removed from macOS
- Obj-C may contain retain and release methods
- Apple introduced ARC in 2012
- What is ARC?
Automatic Referencing Counting
- LLVM adds retain and release
- Automatically Strong
- weak keyword
- unowned keyword
- important to use weak with closures
Access Modifiers
- public
- open
- private
- internal
- fileprivate
- final
Method modifiers
- override
- convenience init
- mutating if modifying value in struct
Why use Swift
outside of Apple?
- Advantages over Java, .NET and others
- programs are compiled into machine code
- Performance cost to JITing code
- Several Web application frameworks
- Vapor and Kitura (IBM)
- Ideal for Micro-Service architecture
Installing Vapor
- On macOS, use homebrew
- Install xcode
- $ eval "$(curl -sL check.vapor.sh)"
- brew tap vapor/homebrew-tap
- brew update
- brew install vapor
Vapor CLI
- $ vapor new Hello --template=api
- $ vapor xcode
- $ vapor build
- $ vapor build --release
- $ vapor run serve
- $ curl localhost:8080/plaintext
Vapor Hosting
- Heroku support
- IBM Bluemix
- Vapor Cloud on AWS
- Roll your own with Docker
Demo
Questions?
Resources
- swift.org
- vapor.codes
- gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782
Contact Me
- Twitter: @davidfekke
- Skype: davidfekke
- david fekke at gmail dot com
Swyft 4
By David Fekke
Swyft 4
Swift 4 language and Server Side Swift
- 1,507