Syntax
// variable
var number = 6
var title: String?
// const value, should be initialized before use it, can't be changed after its definition
let speed = 200
let name: String? = nil
// array
var str: [Character] = ["d", "o", "g"]
Base data type
Type | Desc |
---|---|
UInt8 | UInt8.min is 0, UInt8.max is 255 |
Int | On the 32-bit platform, it’s as Int32; On the 64-bit platform, it’s as Int64. |
Uint | On the 32-bit platform, it’s as UInt32; On the 64-bit platform, it’s as UInt64. |
Double | 64-bit floating-point number |
Float | 32-bit floating-point number |
Boolean | true or false |
Numeric
/* Numeric Literals */
// They are the same number, in another word, their values are the same.
let decimalInteger = 17
let binaryInteger = 0b10001
let octalInteger = 0o21
let hexadecimalInteger = 0x11
// Optional exponent (exp)
1.25e2
1.25e-2
// pad with extra zeros and underscores to make them easier to read.
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneBillion = 1_000_000.000_000_1
/* Numeric Type Conversion */
// Type automatic convert
let a: UInt16 = 2000
let b: UInt8 = 1 // Different type can't be sum together
let c = a + b // Here, system use b to create a new UInt16 object, so this new object can sum with a.
// Type force convert
let three = 3
let num = 0.14159
let pi = Double(three) + num // conversions between integer and floating-point numeric types must be made explict.
// Truncate
let integerPi = Int(pi)
// The rules for combining numeric constants and variable are different from the rules for numeric literals.
// Number literals don’t have an explicit type in and of themselves.
Type Aliases
typealias MyInt16 = UInt16
var num: MyInt16 = MyInt16.min // it's actually calls the UInt16.min
Tuples
let http404Error = (404, " Not Found") // compose a tuple
let (statusCode, statusMessage) = http404Error // decompose a tuple
let (justTheStatusCode, _) = http404Error // use a underscore(_) to ignore other values
let statusCodeByIndex = http404Error.0 // get the tuple's individual element value by index, start at 0
// name the tuple's individual element
let http200Status = (statusCode : 200, description : "OK")
let status200 = http200Status.statusCode
let description200 = http200Status.description
Optional : variable can be a value or nil. Just add a ?
after the variable’s type. nil
meaning “the absence of a valid object.”
only optional type can be nil
.
const value should not be nil
, it has no specific meaning in application.
var name: String? = "Hello"
// Because the initializer might be fail, it returns an optional Int (Int?), rather than an Int.
let num = Int("123")
var answer: Int? // the answer is automatically set to nil.
// In Objective-C, nil is a pointer to a nonexistent object.
// In Swift, nil isn’t a pointer—it’s the absence of a value of a certain type.
// Include multiple condition
// If any of the values in the optional bindings are nil or any Boolean condition evaluates to false, the whole if statement’s condition is considered to be false.
if let firstNum = Int("4"), let secondNum = Int("5"), firstNum < secondNum && secondNum < 100 {
print("\(firstNum) < \(secondNum) < 100")
}
let hobby: String? // ordinary optional
let myHobby = hobby! // must require a exclaimation point to unwrap the object.
// An implicitly unwrapped optional as giving permission for the optional to be force-unwrapped if needed
let address: String! // implicitly option. the name can be accessed when it is nil and without exclaimation point.
let hisAddress = address // it is permitted, no need for an exclaimation point.
// we are recommanded to use the ordinary optional in development.
// because the implicitly optional can easily be out of control.
// ######## error #########
// this will trigger a runtime error
var str: String! = nil
print(str.count)
// this will trigger a runtime error
var bag: String?
print(str!.count). // 'str!' is nil, so it can't be accessed.
// this will trigger a compiler error
var pack: String?
print(str.count) // str is an ordinary option, need an unwrap(!).
// #######################
Function’s argument and its label
use parameter label
func addTwo(arg1 a : Int, arg2 b : Int) -> Int { let c = a + b return c } let sum = addTwo(arg1: 4, arg2: 28)
Tell parameter’s name apparently(Recommended when the method has multi-parameter)
func addTwo(a : Int, b : Int) -> Int { let c = a + _b return c } let sum = addTwo(a: 4, b: 28)
use [ _ ] to pass over the label (Recommended when the method has only one parameter)
func addTwo(_ a : Int, _ b : Int) -> Int { let c = a + b return c } let sum = addTwo(4, 28)
Function’s define and invoke no need to be sequenced. It can be invoked before its define.
// invoke function goToSchool( //function definition func goToSchool() { print("I go to school.") }
Object Oriented
Class
class Person {
var name = "neo"
var age = 0
init () {}
init (_ name: String, _ age: Int) {
self.name = name
self.age = age
}
}
// use different init function to create object.
var a = Person()
var b = Person("Mike", 26)
print(a.name + " " + String(a.age))
print(b.name + " " + String(b.age))
Optional
class BlogPost {
// title can be String or nil
var title : String?
}
let post = BlogPost()
print(post.body + " hello!")
//post.title = "yo"
// Optional Binding
if let actualTitle = post.title {
print(actualTitle + " Hey")
}
else {
print("post.title is \(post.title)")
}
// Testting for nil
if post.title != nil {
print(post.title! + " not nil") // exclaimation '!' means force unbox
}
if post.title == nil {
print("It's nil")
}
// Implicity optional
var name: String! = "Amy" // '!' means that implicity optional
if name != nil {
// no need to use '!'
print(name + " not nil")
}
Initializer
The rule of initializer
A designated initializer must call the designated initializer from the immediately superclass.
class Worker: Person { override init () { super.init() print("subclass's designated initializer") } // it has no conflict with the superclass's convenience method. init (customName: String, age: Int) { // designated initializer call the designated initializer from superclass. super.init(name: customName) self.age = age print("subclass's designated initializer with two parameters") } } class Person { var name = "neo" var age = 0 init () { age = 3 name = "ha" } init (name: String) { self.name = name } convenience init (customName: String, age: Int) { self.init(name: customName) self.age = age } }
A convenience initializer must call another designated initializer from the same class.
A convenience initializer must ultimately call a designated initializer.
designated initializer
init () { age = 3 name = "ha" }
init(_ name: String, _ age: Int) { self.name = name self.age = age }
convenience initializer
if we want to invoke the designated initializer self.init() in a newly init method, we should add a keyword ‘convenience’ to decorate this newly method. (The reason why we use the ‘convenience’ keyword)
convenience init(name: String) { self.init() // rule 3 of the rules we talk before. self.name = name }
Inheritance
Swift only permit single inheritance
class Car { var topSpeed = 200 func drive() { print("Drive at \(topSpeed)") } } // inheritance class FutureCar: Car() { // the method belong to current class func fly() { print("Fly at \(topSpeed + 20)") } } let myRide = Car() // create an instance from the class 'Car'. myRide.drive() let hisCar = FutureCar() hisCar.fly() // method create by the subclass.
Polymorphism
Override
The method has the same name but the arguments’ type or count are different.
If we call with different types or count of arguments , the phenomenons(results) are different.
class Car { var speed = 200 func drive() { print("Drive at \(speed)") // the 'speed' can be use in this class 'Car' } func drive(_ speed: Int) { print("Drive at \(speed)") // the 'speed' can be only used in this func } } let myCar = Car() myCar.drive() myCar.drive(160)
// another case goToSchool() goToSchool("Mike") goToSchool("Micle", "Jhon") goToSchool(15) func goToSchool() { print("I go to school.") } func goToSchool(_ peoleA: String) { print("I go to school with \(peoleA).") } func goToSchool(_ peopleA: String, _ peopleB: String) { print("I go to school with " + peopleA + " and " + peopleB + ".") } func goToSchool(_ speed: Int) { print("I go to school in a speed of \(speed).") }
The subclass define a same method already in the superclass, but the implement of this method is different from that implemented in the superclass. Use the key word ‘override’
class Car { var speed = 200 func drive() { print("Drive at \(speed)") } } // inheritance class FutureCar: Car() { // override the method from the superclass. override func drive() { print("Drive at \(speed + 5)") } } let myRide = Car()//create an instance from the class 'Car'. myRide.drive() let hisCar = FutureCar() hisCar.drive() //method override by the subclass.
Error Handling
Two way to solve the error on runtime
throws
func doSomething() throws { // Here may or may not throw an error }
do try catch
do the right things to face the error.
do { try makeSandwich() // no error was thrown eatSandwich() } catch SandwichError.outOfCleanDishes { // an error was thrown washDish() } catch SandwichError.missingIngredients(let ingredients) { // an error was thrown buyGroceries(ingredients) } catch { // catch other errors }
Assertion & Precondition
A assertion or precondition indicates an invalid program state, there’s no way to catch a failed assertion.
// Assertion let age = -3 assert(age >= 0, "Age can't be less than 0") // (the condition, the message to be shown when the condition is false) assert(age >= 0) // omit the message, it's ok. if age < 0 { assertionFailure("Age can't be less than 0") // when the code already check the failure, use the assertionFailure to show message directly. } // Precondition let index = -1 precondition(index >= 0, "Index must be greater than 0") precondition(index >= 0) preconditionFailure("Index must be greater than 0") // If you compile in unchecked mode (-Ounchecked), preconditions aren’t checked.But the assertion still check. // Assertion check in debug environment, not check in realease environment. // Precondition check in debug environment and release environment. // Use fatalError(_ :file:line:) to halt execution // During prototyping and early development to create stubs for functionality that hasn’t been implemented yet, write a fatalError as the stub implementation. // if the code use the functionality which hasn't been implemented, that will result in a fatal error. It will remind us to implement the function or method. fatalError("Unimplemented")