You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Any also works with any scalar values ( Class, Int, struct, etc. )
varanyVar:Any=7
anyVar ="Changed value to a string, not good practice, but possible."letanyObjectVar:AnyObject=Int(1)asNSNumber
Collections
Array and Dictionary types are structs
So let and var also indicate that they are mutable (var) or immutable (let) when declaring these types
Array
varshoppingList=["catfish","water","lemons"]varemptyMutableArray=[String]() // empty String array
varexplicitEmptyMutableStringArray:[String]=[] // same as above
Dictionary
varoccupations=["Malcolm":"Captain","kaylee":"Mechanic"]varemptyMutableDictionary=[String: Float]()varexplicitEmptyMutableDictionary:[String:Float]=[:] // same as above
Control Flow
condition
条件语句支持 "," (逗号) 子句, 可以用来帮助处理 optional values
letsomeNumber=Optional<Int>(7)iflet num = someNumber, num >3{print("num is greater than 3")}
Very powerful, support String, object instances, and primitives (Int, Double, etc)
letvegetable="red pepper"switch vegetable {case"cucumber","watercress":letvegetableComment="That would make a good tea sandwich."caselet localScopeValuewhere localScopeValue.hasSuffix("pepper"):letvegetableComment="Is it a spicy \(localScopeValue)?"default: // required (in order to cover all possible input)
letvegetableComment="Everything tastes good in soup."}
Functions
func greet(name:String, day:String)->String{return"Hello \(name), today is \(day)."}greet(name:"Bob", day:"Tuesday")
// 第二个参数表示外部参数名使用 `externalParamName` ,内部参数名使用 `localParamName`
func greet2(name:String, externalParamName localParamName:String)->String{return"Hello \(name), the day is \(localParamName)"}greet2(name:"John", externalParamName:"Sunday")
// returns multiple items in a tuple
func getGasPrices()->(Double,Double,Double){return(3.59,3.69,3.79)}letpricesTuple=getGasPrices()letprice= pricesTuple.2 // 3.79
let(_, price1, _)= pricesTuple // price1 == 3.69
// you can also name those tuple params
func getGasPrices2()->(lowestPrice:Double, highestPrice:Double, midPrice:Double){return(1.77,37.70,7.37)}letpricesTuple2=getGasPrices2()letprice2= pricesTuple2.lowestPrice
guard statements
guards provide early exits or breaks
placing the error handler code near the conditions
it places variables it declares , in the same scope as the guard statement
func testGuard(){guardlet aNumber =Optional<Int>(7)else{return}print("number is \(aNumber)")}
Variadic Args
func setup(numbers:Int...){
// it's an array
let _ =numbers[0]let _ = numbers.count
}
returning functions
func makeIncrementer()->((Int)->Int){func addOne(number:Int)->Int{return1+ number
}return addOne
}
pass by ref
func swapTwoInts(a:inoutInt, b:inoutInt){lettempA= a
a = b
b = tempA
}varsomeIntA=7varsomeIntB=3swapTwoInts(a:&someIntA, b:&someIntB)
Closures
Functions are special case closures ({})
-> separates the arguments and return type
in separates the closure header from the closure body
varnumbers=[1,2,6]
numbers.map({(number:Int)->Intinletresult=3* number
return result
})
// When the type is known ...
numbers.map({ number in3* number }) // kind of lambda ?
// 语法糖, 这种情况下,可以不要 ()
numbers.map{ number in3* number }
Trailing closure
numbers = numbers.sorted{ $0 > $1 }
Tips : Use Closure to drop function parameter name
// Normal Function
func sum(x:Int, y:Int)->Int{return x + y }varsumUsingClosure:(Int,Int)->(Int)={ $0 + $1 }
Tips : 函数式编程
例:获取偶数:
// bad
varnewEvens=[Int]()foriin1...10{if i %2==0{ newEvens.append(i)}}
//========================
// Declarative
varevens=Array(1...10).filter{ $0 %2==0}print(evens) // [2, 4, 6, 8, 10]
Structures
Structures and classes have very similar capabilities
functions marked with throws must be called using try
func fakeFetch(value:Int)throws->String{guard7== value else{throwMyError.ReallyBadValue(msg:"Some really bad value")}return"test"}func testTryStuff(){
// assumes there will be no error thrown,
// otherwise a runtime exception is raised
let _ =try!fakeFetch(value:7)
// if an error is thrown, then it proceeds,
// but if the value is nil, it also wraps every return value in an optional, even if its already optional
let _ =try?fakeFetch(value:7)
// normal try operation that provides error handling via `catch` block
do{tryfakeFetch(value:1)}catchMyError.BadValue(let msg){print("Error message: \(msg)")}catch{
// must be exhaustive
}}
Classes
Classes, structures and its members have three levels of access control
If you just need to store data in a structured object, you should use a struct
internalclassRect:Shape{varsideLength:Int=1
// Custom getter and setter property
privatevarperimeter:Int{get{return4* sideLength
}set{
// `newValue` is an implicit variable available to setters
sideLength = newValue /4}}
// Computed properties must be declared as `var`
// cause' they can change
varsmallestSideLength:Int{returnself.sideLength -1}
// Lazily load a property
// subShape remains nil (uninitialized) until getter called
lazy varsubShape=Rect(sideLength:4)
// If you don't need a custom getter and setter,
// but still want to run code before and after getting or setting a property,
// you can use `willSet` and `didSet`
varidentifier:String="defaultID"{
// the `willSet` arg will be the variable name for the new value
willSet(someIdentifier){print(someIdentifier)}}init(sideLength:Int){self.sideLength = sideLength
// always super.init last when init custom properties
super.init()}
// override
overridefunc getArea()->Int{return sideLength * sideLength
}}
// A simple class `Square` extends `Rect`
classSquare:Rect{convenienceinit(){self.init(sideLength:5)}}varmySquare=Square()
// cast instance
letaShape= mySquare asShape
// Optional init
classCircle:Shape{varradius:Intoverridefunc getArea()->Int{return3* radius * radius
}
// Place a question mark postfix after `init` is an optional init
// which can return nil
init?(radius:Int){self.radius = radius
super.init()if radius <=0{returnnil}}}varmyCircle=Circle(radius:1)print(myCircle?.getArea()) // Optional(3)
print(myCircle!.getArea()) // 3
Enums
Enums can optionally be of a specific type or on their own
Enum values allow short hand syntax, no need to type the enum type
when the variable is explicitly declared
varsuitValue:Suit=.Hearts
String enums can have direct raw value assignments
or their raw values will be derived from the Enum field
enumBookName:String{case John
case Luke ="Luke"}print("Name: \(BookName.John.rawValue)") // John
print("Name: \(BookName.John)") // John
print("Name: \(BookName.Luke.rawValue)") // rawLuke
print("Name: \(BookName.Luke)") // Luke
Enum with associated Values
enumFurniture{
// Associate with Int
case Desk(height:Int)
// Associate with String and Int
case Chair(String,Int)func description()->String{switchself{case.Desk(let height):return"Desk with \(height) cm"case.Chair(let brand,let height):return"Chair of \(brand) with \(height) cm"}}}vardesk:Furniture=.Desk(height:80)print(desk.description()) // "Desk with 80 cm"
varchair=Furniture.Chair("Foo",40)print(chair.description()) // "Chair of Foo with 40 cm"
使用 @objc 声明的协议允许 optional functions , which allow you to check for conformance
这些函数也必须用 @objc 标记。
@objcprotocolTransformShape{@objcoptionalfunc reshape()@objcoptionalfunc canReshape()->Bool}classMyShape:Rect{vardelegate:TransformShape?func grow(){
sideLength +=2
// Place a question mark after an optional property, method, or
// subscript to gracefully ignore a nil value and return nil
// instead of throwing a runtime error ("optional chaining").
iflet reshape =self.delegate?.canReshape?(), reshape {
// test for delegate then for method
self.delegate?.reshape?()}}}
Extension
Add extra functionality to an already existing type
// Tips: Better Version than define a square function
extensionInt{varsquared:Int{returnself*self}}5.squared // 25
5.squared.squared // 625
Generics
Similar to Java and C#
Use the where keyword to specify the requirements of the generics.
func findIndex<T:Equatable>(array:[T], valueToFind:T)->Int?{for(index, value)in array.enumerated(){if value == valueToFind {return index
}}returnnil}letfoundAtIndex=findIndex(array:[1,2,3,4], valueToFind:3)print(foundAtIndex ==2) // true
Operators
Custom operators can start with the characters:
/ = - + * % < > ! & | ^ . ~
or
Unicode math, symbol, arrow, dingbat, and line/box drawing characters
prefix operator !!!
// A prefix operator that triples the side length when used
prefixfunc!!!(shape:inoutSquare)->Square{
shape.sideLength *=3return shape
}
// current value
print(mySquare.sideLength) // 4
!!!mySquare
print(mySquare.sideLength) // 12
// Operators can also be generics
infix operator <->func<-><T:Equatable>(a:inoutT, b:inoutT){letc= a
a = b
b = c
}varfoo:Float=10varbar:Float=20
foo <-> bar
print("foo is \(foo), bar is \(bar)") // "foo is 20.0, bar is 10.0"