一.常量和变量
[代码]
let maximumNumberOfLoginAtAttempts = 10 #用let声明常量
var currentLoginAttempt = 0 #用var声明变量
[类型注释]
声明常量或者变量的时候提供类型注释,明确存储值的类型。常量或者变量名后依次添加 冒号,空格,类型名称来实现。
var welcomeMessage: String
welcomeMessage = "Hello"
其实,可以不适用类型注释,因为在给常量或者变量提供初始值的时候,swift可以推测出他的类型。
[打印]
println(welcomeMessage) #打印变量
#字符串插值 用“ \(变量名) ” 来占位,swift会用变量的值来替换这个占位符
println("The current value of welcomeMessage is \(welcomeMessage)")
二.注释和分号
[注释]
//单行注释
/*多行 注释*/
[分号]
语句结束后不需要;去标志结束
但是如果多个语句写在一行,可以使用分号去分割
三.整数和浮点数
[整数]
swift提供 8 16 32 64位有符号和无符号的整数
Eg.
UInt8 8位无符号整数
Int32 32位有符号整数
let minValue = UInt8.min
let maxValue = UInt8.max
在swift中,UInt , Int类型 与 当前系统的字长相等,
32位系统,Int === Int32
64位系统,Int === Int64
[浮点数]
Double 64位浮点数
Float 32位浮点数
四.类型安全和类型推断
类型安全:编译的时候会进行类型检查,标记不匹配的类型。
类型推断:根据初值推断类型
[数字的字面量]
不带前缀的十进制数
0b前缀的二进制数
0o前缀的八进制数
0x前缀的十六进制数
[指数]
1.25e2 --> 1.25 * (10^2) #10进制基数是以10为底
1.25e-2 --> 1.25 * (10^-2)
0xFp2 --> 15 * (2^2) #16进制基数是以2为底
[数值类型的转化]
整数间的转化demo:
let twoThousand: UInt16 = 2_000 #_不会改变字面值,辅助提高可读性
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one) #加号两边都是UInt16可以相加
浮点数的转化demo
let three = 3
let pointNum = 3.1415
let pi = Double(three) + pointNum
let intPI = Int(pi)
上面这种SomeType(ofInitialValue) [eg. Double(three) ]
是一种调用swift类型构造器的默认方法,我们为他传入初值,比如 UInt16 的构造器可以用来接收UInt8类型的值,
所以可以将UInt8类型的值转化成UInt16,此处必须传UInt16支持的类型,不是随便什么类型都可以的。当然可以通过扩展让构造器支持自定义类型。
[类型别名]
typealias AudioSample = UInt16
var maxUInt16Num = AudioSample.max #UInt16.max
五.布尔值
[声明和初始化]
let oragesAreOrange = true #不需要制指定具体的Bool类型,编 译器会帮助我们推断的
let oragesAreOrange = false
[判断语句与Bool]
错误写法:编译器不允许非bool值替换Bool,这个跟java等其他语言不同
let i = 1
if i {
}
正确写法:
if i==1 {}
六.元组Tuple
多个值组合成一个复合值,元组中的值可以是任何类型,并且可以是相互不同的类型。
场景:比如一个处理访问网页响应的函数,需要返回(Int,String)元组来描述成功失败的结果。
let http404Error = (404,"Not Found") #类型是 (Int , String)
#下标访问
println("The status code is \(http404Error.0)") #The status code is 404
println("The status msg is \(http404Error.1)") #The status msg is Not Found
let http200Status = (statusCode:200,description:"OK")
#元素名称访问
println("The status code is \(http200Status.statusCode)") #The status code is 200
println("The status msg is \(http200Status.description)") #The status msg is OK
let (statusCode,statusMsg) = http404Error
println("The status code is \(statusCode)") #The status code is 404
println("The status msg is \(statusMsg)") #The status msg is Not Found
let (justTheStatueCode, _) = http404Error # 用( _ ) 来忽略不关心的部分
println("The status code is \(justTheStatueCode)") #The status code is 404
七.Optional类型
Optional 类型是swift独有的 ,表示一个基础类型可能有值也可能没有值,当他没有值的时候就是nil。
[Optional定义]
定义一个Optional的值很容易,只需要在类型后面加上问号(?)就行了:
var str : String?
[显式拆包]
Optional类型的值不能被直接使用,当需要用时要显式拆包,以表明我知道这个Optional是一定有值的,拆包用!:
var str: String? = "Hello World!"
str! //Hello World!
ps,Optional类型其实是一个枚举
[隐式拆包]
除了显式拆包,Optional还提供了隐式拆包,通过在声明时的数据类型后面加一个感叹号(!)来实现:
var str: String! = "Hello World!"
str //Hello World!
[可选绑定Optional Binding]
如下两个demo来讲述一下为甚么要Optiona Binding:
看下面这个demo,当count != nil条件成真后接着在上下文中使用count,会被要求进行拆包 String(count!) ,
var count: Int?
count = 100
if count != nil {
"count is " + String(count!) //count is 100
} else {
"nil"
}
为了避免在条件判断语句后执行一次或更多次的拆包,Swift引进了Optional Binding,我们就可以这样做:
var count: Int?
count = 100
if let validCount = count {
"count is " + String(validCount) //count is 100
} else {
"nil"
}
[Optional Chaining]
暂时还没办法秒懂,mark一下,回头看
http://blog.csdn.net/zhangao0086/article/details/38640209
八.断言
用于运行时校验对应条件是否等于true的判断。
let age = -3
assert(age>=0,"A person age can not less than zero")
只有断言的条件 age>=0的时候 才会继续执行,否则 age是负数 断言是false 那么就会触发断言 程序终止。
九.运算符
赋值 let b = 10
算数 + - * /
取余 %
这个符号要特殊说明一下,因为他与别的语言的取模不一样,他表示( a%b) a中包括多少个b 并返回剩余的值,公式是
a = (b * some multiplier) + remainder
9 = (4 * 2) + 1 [9 % 4 = 1]
-9=(4 * -2) + -1 [-9 % 4 = -1] #可见 跟正负号没甚么关系
8 = (2.5 * 3) + 0.5 #浮点数也一样的
自增 ++
自减 --
var a = 0
let b = ++a # b = 1 ; a = 1
let c = a++ # c = 1 ; a = 2
一元减 - 理解成负号
一元加 + 对操作数没甚么变化
复合赋值运算 +=
比较运算符 相等(a==b) 不相等(a!=b) 大于(a>b) 小于(a<b)
大于等于(a>=b) 小于等于(a<=b) 完全等(===) 不完全等(!==)
三元条件 question ? answer1 : answer2
范围运算符 闭合范围运算符
for index in 1...5 {} #[1,5]
半闭合范围运算符
for index in 1..5 {} #[1,5)
逻辑运算符 逻辑非 !a
逻辑与 a &&
逻辑或 a || b
十.字符串和字符
[初始化空字符串]
var emptyString = ""
var anotherEmptyString = String()
if emptyString.isEmpty { #判断字符串为空
emptyString += "给字符串加点内容"
}
string是拷贝类型,即 赋值,参数传递等 string值是生成一个副本的,不是原始的版本。与Cocoa的NSString不同。
[字符]
let yenSign: Character = "¥" #需要类型注释 和 字面量
for character in "一个字符串" {
println(character)
}
#countElements统计字符数,全局函数
let unusualMsg = "slfjasfjslafjasfj"
println("\(countElements(unusualMsg))")
[字符串的比较]
字面值相等 if str1 == str2 { ...... }
前缀相等 if str1.hasPrefix("Act 1") { ........ }
后缀相等 if str1.hasSuffix("Act 1") { ........ }
字符串大写 let strUpper = str.uppercaseString
字符串小写 let strLower = str.lowercaseString
[Unicode]
关于Unicode 和 三种兼容unicode的字符串 自行查找资料进一步学习~
三种兼容字符串是:UTF-8 编码单元集合 for c in str.utf8 { ... }
UTF-16编码单元集合 for c in str.utf16 { ... }
21位Unicode标量值的结合 for c in str.unicodeScalars { ... }
十一.集合
集合有两类:
数组:相同类型的有序列表
字典:相同类型的无序列表
[数组定义]
var shoppingList: String[] = ["Eggs","Milk"]
var shoppingList: Array<String> = ["Eggs","Milk"]
var shoppingList = ["Eggs","Milk"] #类型推断的存在,可以不用定义类型
var someInts = Int[] () #空数组
var someInts = [] #空数组
#构造器,创建有若干默认值的数组
var threeDoubles = Double[] (count:3 ,repeatedValue: 0.0)
var anotherThreeDoubles = Array(count:3 ,repeatedValue: 2.5)
var sixDoubles = threeDoubles + anotherThreeDoubles
[数组操作]
shoppingList.count #元素个数
shoppingList.isEmpty #是否为空
shoppingList.append("flower") #追加元素
shoppingList += "Baking Powder" #添加元素
shoppingList +=["str1","str2"] #添加多个
var firstItem = shoppingList[0] #获取第一个元素
shoppingList[0] = "Egg2016" #修改
shoppingList[4...6] = ["huhu","fafa"] #修改下标4到6的三个元素为 huhu , fafa
shoppingList.insert("tomato",atIndex: 0) #在指定位置插入
let mapleSyrup = shoppingList.removeAtIndex(0) #删除index位置的元素
let apples = shoppingList.removeLast() #删除最后一个元素,他会避免对count属性的查询,推荐使用这个 而不是 removeAtIndex(count-1)
[数组的遍历]
for item in shoppingList { ... }
#enumerate为每个元素返回一个元组
for (index,value) in enumerate(shoppingList) {
println("item \(index+1) : \(value) ")
}
[字典的定义]
var airports: Dictionary<String,String> = ["a":"b","c":"d"]
var airports = ["a":"b","c":"d"]
var airports = Dictionary<Int,String>() #空字典
airports = [:] # 空字典字面量[:],前提是字典已经指定了类型
[字典的操作]
airports["e"] = "f" #追加,如果key不存在
airports["e"] = "g" #修改,如果key存在
#updateValue更新某个key对应的值,返回字典值类型的可选
if let oldValue = airports.updateValue("new value", forKey:"a") {
println("\(oldValue)")
}
#删除键值对
airports["APL"] = nil #通过设置值为nil来删除键值对
if let removedValue = airports.removeValueForKey("a"){
println(" \(removedValue) ")
}else {
println("does not contain value for key a")
}
[字典的遍历]
for (airportCode,airportName) in airports {
}
for airportCode in airports.keys { .... }
for airportName in airports.values { .... }
let airportCodes = Array(airports.keys)
let airportValues = Array(airports.values)
十二.流程控制
[for index in 集合]
for index in 1...5 { ... }
for _ in 1...n { ... } #下划线来占位,前提是 你需要用到集合中的元素值
for arrItem in oneArray { ... }
for (code,msg) in oneDic { ... }
for character in "Hello" { ... }
=================================
[for 循环]
for var index = 0;index < 3; ++index { .... }
=================================
[while 循环]
while a < b {
a++
}
do{
a++
} while a<b
=================================
[if 语句]
if condition {
...
}else if condition {
...
}else {
...
}
=================================
[switch 语句]
swift不需要break去结束一个case执行,当然你也可以写,一个case命中执行后就结束了,不会跳转到下一个case。注意,每个case必须要有至少一条执行语句,不能是空的 会编译报错。
let someCharacter: Character = "e"
switch someCharacter {
case "a","b","c":
println("\(someCharacter) is a vowel")
case "d","e","f":
println("\(someCharacter) is a constant")
default:
println("default")
}
关于case支持的格式:
范围匹配 case 1...3:
元组匹配 let somePoint = (1,1)
switch somePoint {
case (0,0):
println("(0,0) is at the origin")
case (_,0):
println("用_来匹配任何可能的值")
case (-2...2,-2...2):
println("用范围来匹配值")
default:
println("默认命中")
}
值绑定 switch somePoint {
case (let x,0):
println("\(x) 被绑定了横坐标命中的值")
case let(x,y):
println("获取绑定的值 ( \(x),\(y) ) ")
default:
println("默认命中")
}
where分句检测额外条件
switch somePoint {
case let(x,y) where x==y:
println("绑定的值 ( \(x),\(y) ) on the line x == y ")
default:
println("默认命中")
}
=================================
[控制转移语句]
continue 停止现在的工作继续下次迭代
break 终止整个流程
fallthrough switch执行一个case后会结束此次switch,用fall through会执行下一个case
switch m {
case "a":
XXXXXXX
fall through
case "b":
XXXXXXXX
default:
XXXXXXXX
}
标签语句
gameLoop: ******
continue gameLoop
十三.函数
[定义]
# ->指定函数的返回值
func sayHello (personName: String) -> String {
let greeting = "Hello," + personName + "!"
}
[参数]
#多参,返回多个返回值
func count(str: String,str2: String) -> (vowels: Int,consonants: Int,others: Int){
return (vowels, consonants, others)
}
#外参,外部参数名可以在函数调用的时候对于参数有更加直观的认识。即该参数名对外部可见。
import Foundation
func sayHello(username name:String)->String{
let result = "Hello," + name
return result
}
var nickname:String = "Jack"
println(sayHello(username: nickname)) #调用
#同时可以使某个参数名同时是内部参数名和外部参数名:使用#号。
func sayHello(#name:String)->String{
let result = "Hello," + name
return result
}
var nickname:String = "Jack"
println(sayHello(name: nickname))
#默认行参值,swift会给你定义的默认行参提供一个自动外部名,比如joiner 会有一个外部名 joiner,跟加#类似
fun join(str1: String,str2: String,joiner: String = "") -> String {
return str1 + joiner + str2
}
join("hello","world")
#
十四.闭包
十五.枚举
[定义]
enum CompassPoint {
case North
case South
case East
case West
}
var directionToHead = CompassPoint.West #directionToHead就是CompassPoint类型的变量
directionToHead = .East #directionToHead的类型是已知的了,所以你可以忽略它的类型来给他赋值了
[使用Switch语句来匹配枚举值]
directionToHead = .South
switch directionToHead {
case .North:
println("Lots of planets have a north")
case .South:
println("Watch out for penguins")
case .East:
println("Where the sun rises")
case .West:
println("Where the skies are blue")
}
[关联值]
enum Barcode {
case UPCA(Int, Int, Int)
case QRCode(String)
}
定义了一个叫做Barcode的枚举类型,它可以有一个UPCA成员,这个成员关联了一个包含三个整型数值的元组,同时这个枚举类型还有一个QRCode成员,关联了一个字符串。
var productBarcode = Barcode.UPCA(8, 85909_51226, 3) #可以用任意其中一个类型来生成一个新的
productBarcode = .QRCode("ABCDEFGHIJKLMNOP") #还可以被赋值为另一个类型,一旦定义了变量类型,再次赋值的时候不需要带类型Barcode
switch productBarcode
{
case .UPCA(let numberSystem, let identifier, let check): #let可以提前 let .UPCA(numberSystem, identifier, check)
println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
case .QRCode(let productCode): #let .QRCode(productCode)
println("QR code with value of \(productCode).")
}
[原始值]
enum ASCIIControlCharacter: Character {
case Tab = "\t"
case LineFeed = "\n"
case CarriageReturn = "\r"
}
enum Planet: Int {
case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
let earthsOrder = Planet.Earth.toRaw() #toRaw()方法来获取他的原始值,eathsOrder is 3
let possiblePlanet = Planet.fromRaw(7) #fromRaw()方法来尝试通过一个原始值来寻找他所对应的枚举成员
# possiblePlanet is of type Planet? and equals Planet.Uranus”
# possiblePlanet是一个Planet?类型,可能会是nil,因此需要判断:
let positionToFind = 9
if let somePlanet = Planet.fromRaw(positionToFind) { #可选绑定
switch somePlanet {
case .Earth:
println("ostly harmless")
default:
println("Not a safe place for humans")
}
} else {
println("There isn't a planet at position \(positionToFind)") #Planet.fromRaw(positionToFind) 如果是 nil ,那么就会走到这
}
十六.类和结构体
反馈一个问题:
binary operator === can not be applied
[swift语言详解]http://c.biancheng.net/cpp/html/2427.html 在数组的===比较这一块是错误的,恒等用在引用类型上,而数组是值类型,可以看下这个demo:
[定义]
struct Resolution { #Resolution的结构体,用来描述一个显示器的像素分辨率
var width = 0
var heigth = 0
}
class VideoMode { #VideoMode的类,用来描述一个视频显示器的特定模式
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
let someResolution = Resolution()
let vga = resolution(width:640, heigth: 480)
let someVideoMode = VideoMode()
someVideoMode.resolution.width = 12880
print(someResolution.width)
[属性]
存储属性:
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
延迟存储属性:
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用@lazy来标示一个延迟存储属性。
必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。
class DataImporter {
/*
DataImporter 是一个将外部文件中的数据导入的类。
这个类的初始化会消耗不少时间。
*/
var fileName = "data.txt"
// 这是提供数据导入功能
}
class DataManager {
@lazy var importer = DataImporter()
var data = String[]()
// 这是提供数据管理功能
}
let manager = DataManager()
manager.data += "Some data"
manager.data += "Some more data"
// DataImporter 实例的 importer 属性还没有被创建
DataManager的一个功能是从文件导入数据,该功能由DataImporter类提供,DataImporter需要消耗不少时间完成初始化:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。DataManager也可能不从文件中导入数据。所以当DataManager的实例被创建时,没必要创建一个DataImporter的实例,更明智的是当用到DataImporter的时候才去创建它。由于使用了@lazy,importer属性只有在第一次被访问的时候才被创建。比如访问它的属性fileName时:
println(manager.importer.fileName)
// DataImporter 实例的 importer 属性现在被创建了
// 输出 "data.txt”
计算属性:
类、结构体和枚举可以定义计算属性,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) { #(newCenter) 可以省略不写,用默认的newValue
origin.x = newCenter.x - (size.width / 2) #origin.x = newValue.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// 输出 "square.origin is now at (10.0, 10.0)”
属性监视器:
暂时不知道哪里用到,先不说了
类型属性:
略