/* this is the start of the first multiline comment
/* this is the second, nested multiline comment */
this is the end of the first multiline comment */
3. 二进制/八进制/十进制/十六进制
letbinaryInteger=0b10001// 17 in binary notationletoctalInteger=0o21// 17 in octal notationletdecimalInteger=17lethexadecimalInteger=0x11// 17 in hexadecimal notation
var optional: Type? 等同于 var optional: Optional<Type>
var implicit: Type! 等同于 var implicit: ImplicitlyUnwrappedOptional<Type>
10. 处理可选类型:
// a) 强制解析ifconvertedNumber!=nil{println("\(possibleNumber) has an integer value of \(convertedNumber!)")}// b) 可选绑定ifletactualNumber=possibleNumber.toInt(){println("\(possibleNumber) has an integer value of \(actualNumber)")}// c) 隐式解析letassumedString:String!="An implicitly unwrapped optional string."println(assumedString)// 可选绑定陷阱, 可选绑定只判定optional.letbool:Bool?=falseifletvalue=bool{// value = falseprintln("whatever")// 正确的写法需要在这里判别value}
11. 奇葩的保留字使用方式, 使用数字1左侧的’`‘包裹保留字, 访问时另需括号包裹.
var`class`=5(`class`)=6println(`class`)
Basic Operators
1. 返回值
赋值操作(=), 复合赋值操作(+=/-=...)返回Void
2. 空合运算符, 空合运算属于短路运算
a ?? b 等同于 a != nil ? a! : b
3. 区间
1..<5 包含1、2、3、4; 1...5 包含1、2、3、4、5
Strings and Characters
1. String是值类型. var/let决定mutable与否.
2. 插值语法
letmultiplier=3letmessage="\(multiplier) times 2.5 is \(Double(multiplier)*2.5)"// message is "3 times 2.5 is 7.5"
3. 字符计数与书写字簇(extended grapheme clusters)
varword="cafe"println("the number of characters in \(word) is \(countElements(word))")// prints "the number of characters in cafe is 4"word+="\u{301}"// COMBINING ACUTE ACCENT, U+0301println("the number of characters in \(word) is \(countElements(word))")// prints "the number of characters in café is 4"
Extended grapheme clusters can be composed of one or more Unicode scalars. This means that different characters, and different representations of the same character, can require different amounts of memory to store. Because of this, characters in Swift do not each take up the same amount of memory within a string’s representation. As a result, the number of characters in a string cannot be calculated without iterating through the string to determine its extended grapheme cluster boundaries. If you are working with particularly long string values, be aware that the countElements function must iterate over the Unicode scalars in the entire string in order to calculate an accurate character count for that string.
扩展书写字符簇可以组成一个或多个Unicode标量. 这就意味着, 不同字符和相同字符的不同编码都可能导致所需存储空间的不同. 因此, Swift中字符占用的存储空间不等同于string编码所占用的. 于是, string中的字符数必须通过遍历以确定扩展书写字符的边界后才能计算得知. 在使用特别长的字符串时, 需注意countElements函数必须遍历整个string的Unicode标量才能计算出准确的字符数.
Note also that the character count returned by countElements is not always the same as the length property of an NSString that contains the same characters. The length of an NSString is based on the number of 16-bit code units within the string’s UTF-16 representation and not the number of Unicode extended grapheme clusters within the string. To reflect this fact, the length property from NSString is called utf16Count when it is accessed on a Swift String value.
也需注意, 相同字符下, countElements返回的字符数并不总等于NSString的length属性. NSString的length属性基于string的UTF-16编码下的16位编码单元数, 而不是Unicode扩展书写字符簇. 实际上, NSString的length属性就对应了Swift String的utf16Count.
ifletoldValue=dict.updateValue("VALUE",forKey:"KEY"){println("The old value for KEY was \(oldValue).")}
8. 字典枚举
for(key,value)indict{println("\(key): \(value)")}
Control Flow
1. 隐式break; 非隐式fallthrough.
letintegerToDescribe=5vardescription="The number \(integerToDescribe) is"switchintegerToDescribe{case2,3,5,7,11,13,17,19:description+=" a prime number, and also"fallthroughdefault:description+=" an integer."}
letsomePoint=(1,1)switchsomePoint{case(0,0):println("(0, 0) is at the origin")case(letx,0):println("(\(somePoint.0), 0) is on the x-axis")case(0,lety):println("(0, \(y) is on the y-axis")case(-2...2,-2...2):println("(\(somePoint.0), \(somePoint.1)) is inside the box")default:println("(\(somePoint.0), \(somePoint.1)) is outside of the box")}
4. 条件匹配
letyetAnotherPoint=(1,-1)switchyetAnotherPoint{caselet(x,y)wherex==y:println("(\(x), \(y)) is on the line x == y")caselet(x,y)wherex==-y:println("(\(x), \(y)) is on the line x == -y")caselet(x,y):println("(\(x), \(y)) is just some arbitrary point")}
funcsomeFunctionThatTakesAClosure(closure:()->()){// function body goes here}// 普通闭包someFunctionThatTakesAClosure({// closure's body goes here})// 尾随闭包someFunctionThatTakesAClosure(){// trailing closure's body goes here}// 闭包作为函数唯一参数时括号都可以省略someFunctionThatTakesAClosure{// trailing closure's body goes here}
classSuperclass{varvalue:Int!{didSet{self.value// console: 3}}init(value:Int){self.value=value}}classSubclass:Superclass{varsubvalue:Int!{didSet{self.subvalue// not triggered at all}}overrideinit(value:Int){self.subvalue=2super.init(value:value)self.value=3// triggerself.subvalue=4}}varsub=Subclass(value:1)
9. didSet中可以覆盖属性值, 而不会再次触发观察者.
// 这是个反例...classSuperclass{varstoredInt:Int=0varcalculatedInt:Int{get{returnself.storedInt}set{self.storedInt=newValue// called twice with 1, 0}}}classSubclass:Superclass{overridevarcalculatedInt:Int{didSet{self.calculatedIntifself.calculatedInt>0{self.calculatedInt-=1;// called twice with 1, 0}}}}varinstance=Subclass()instance.calculatedInt=1
// a) designated initializer, 每个类至少有一个, 需初始化所有class引入的存储属性, 并调用父类的构造器以完成链式构造. init(...){// first phase - initialize ALL stored propertyself.storedProperty=...// if default value is not providedsuper.init(...)// delegate up// second phase - customize stored propertyself.storedProperty=...super.storedProperty=...}// b) convenience initializer, 数量不限, 处理输入并调用class的designated initializer以委托构造.convenienceinit(parameters){// first phase - initialize ALL stored propertyself.init(...)// delegate across, should be a designated initializer// second phase - customize stored propertyself.storedProperty=...super.storedProperty=...}
first phase
a) 调用designated initializer或convenience initializer
b) 为新实例分配内存, 此时内存未初始化
c) 初始化类引入的所有存储属性
d) 逐层调用父类构造器, 完成后first phase完成, 所有存储属性都已初始化
second phase
a) 自定向下定制实例. 构造器职能在second phase中调用实例方法/读取实例属性/使用self.
a) 当子类未实现任何designated initializer时, 继承父类所有的designated initializer.
b) 当子类实现/继承了父类的所有designated initializer时(可以改写为convenience initializer), 继承父类所有的convenience initializer.
c) 除此之外, Swift默认不继承构造器以免子类不完整构造.
classSomeClass{letsomeProperty:SomeType={// create a default value for someProperty inside this closure// someValue must be of the same type as SomeTypereturnsomeValue}()}
lazyvarsomeClosure:()->String={[unownedself,weaksomeInstance=self.somewhat]in// closure body goes here}
Optional Chaining
1. 可选链与Objective-C中的nil相似, 但额外提供检测成功失败的功能.
classPerson{varresidence:Residence?}classResidence{varnumberOfRooms=1funcprintNumberOfRooms(){println("The number of rooms is \(numberOfRooms)")}}// 由于存在可选链, 即使numberOfRooms的推断类型为Int, number的类型也会是Int?. // 可选性质不受链内可选节点数影响. // 链内任意节点为nil都会导致整条链失败. letnumber=consumers.first?.residence?.numberOfRooms// 当方法有返回值时, 处理方式与访问属性相同. // 当方法返回类型为Void时, 其本质是空元组(), 则可选链的返回类型为()?.// 可以通过返回值判定调用是否成功.letsucc:()?=consumers.first?.residence?.printNumberOfRooms()ifsucc!=nil{println("It was possible to print the number of rooms.")}// 赋值语句类似于方法调用if(consumers.first?.residence?.numberOfRooms=3)==nil{println("Failed in setting the number of rooms.")}
2. 下标脚本也可以是可选链的一部分, 但需特别留意’?’需要置于’[]’之前.
vartestScores=["Dave":[86,82,84],"Bev":[79,94,81]]testScores["Dave"]?[0]=91// settestScores["Bev"]?[0]++// get
Type Casting
1. 使用’is’做类型检查
ifitemisMovie{++movieCount}
2. 使用’as’编译期安全转型, 如向上转型或bridge; ‘as?’可选转型, 转型失败时返回nil; ‘as!’强制转型, 失败时触发运行时错误. x as! T 等同于 (x as? T)!.
// as! exampleformovieinlibraryas![Movie]{println("Movie: '\(movie.name)', dir. \(movie.director)")}// as? exampleforobjectinsomeObjects{ifletmovie=objectas?Movie{println("Movie: '\(movie.name)', dir. \(movie.director)")}}// 在switch中使用as, 而非as?, 以检查类型. forthinginthings{switchthing{// 0值判别case0asInt:println("zero as an Int")case0asDouble:println("zero as a Double")// Int 判别caseletsomeIntasInt:println("an integer value of \(someInt)")// Double 正数判别caseletsomeDoubleasDoublewheresomeDouble>0:println("a positive double value of \(someDouble)")// Double 负数判别caseisDouble:println("some other double value that I don't want to print")// String 判别caseletsomeStringasString:println("a string value of \"\(someString)\"")// 元组值绑定caselet(x,y)as(Double,Double):println("an (x, y) point at \(x), \(y)")// func 判别caseletstringConverterasString->String:println(stringConverter("Michael"))default:println("something else")}}
structCard{enumSuit:Character{caseSpades="♠",Hearts="♡",Diamonds="♢",Clubs="♣"}enumRank:Int{caseTwo=2,Three,Four,Five,Six,Seven,Eight,Nine,TencaseJack,Queen,King,Ace}}enumRank:Int{caseTwo=2,Three,Four,Five,Six,Seven,Eight,Nine,TencaseJack,Queen,King,Ace}letr1=Rank.Twoletr2=Card.Rank.Twoletr3=Card.Rank.Twoifr1==r2{// compile errorprintln("equals")}ifr2==r3{println("equals")// prints equal}
Extensions
1. Extension可以,
a) 添加实例/类型计算属性, 但不能添加存储属性, 也不能添加属性观察者.
b) 添加实例/类型方法, 可以添加mutating方法, 但不能override方法.
c) 添加新的convenience构造器, 但不能添加designated构造器, 在extension中添加构造器不会影响默认构造器和成员构造器的自动生成.
d) 添加新的下标脚本.
e) 添加新的嵌套类型, 不限于class/struct/enum.
f) 使类型符合指定协议.
Protocols
1. Protocol可以,
a) 要求类型提供实例/类型属性, 及读写特性(get/set), 但不能限定属性的实现方式(存储/计算). 类型属性无论class/struct/enum, 一律用class标识.
funcallItemsMatch<C1:Container,C2:ContainerwhereC1.ItemType==C2.ItemType,C1.ItemType:Equatable>(someContainer:C1,anotherContainer:C2)->Bool{// check that both containers contain the same number of itemsifsomeContainer.count!=anotherContainer.count{returnfalse}// check each pair of items to see if they are equivalentforiin0..<someContainer.count{ifsomeContainer[i]!=anotherContainer[i]{returnfalse}}// all items match, so return truereturntrue}
5. 协议与关联类型
protocolContainer{typealiasItemTypemutatingfuncappend(item:ItemType)varcount:Int{get}subscript(i:Int)->ItemType{get}}structStack<T>:Container{// original Stack<T> implementationvaritems=[T]()mutatingfuncpush(item:T){items.append(item)}mutatingfuncpop()->T{returnitems.removeLast()}// conformance to the Container protocoltypealiasItemType=Tmutatingfuncappend(item:T){self.push(item)}varcount:Int{returnitems.count}subscript(i:Int)->T{returnitems[i]}}
@property(nonatomic)UIEdgeInsetslayoutMarginsNS_AVAILABLE_IOS(8_0);@property(nonatomic)BOOLpreservesSuperviewLayoutMarginsNS_AVAILABLE_IOS(8_0);// default is NO - set to enable pass-through or cascading behavior of margins from this view’s parent to its children
-(void)layoutMarginsDidChangeNS_AVAILABLE_IOS(8_0);