官方文档The Swift Programming Language官方文档 & 可选 《The Swift Programming Language》
一 工具及环境
1、工具
- Xcode
- AppCode
2、编写运行方式
(1)REPL
① 在终端输入:swift,可以看到版本情况,如下:
② 接下来即可进行代码编写
(2)Playground
① 通过 : File -> New -> Playground,打开Playground:
② 打开Xcode—>create a new project—>OS X Application—>Command Line Tool—>Language(Swift)
(3)使用swiftc命令
① 在终端使用:vi HelloWorld.swift
② 编写代码:
import Foundation
var str = "Hello World"
print(str)
③ 通过esc
,输入指令退出编写::wq
④ 使用swiftc命令编译:swiftc HelloWorld.swift
⑤ 编译没有问题的情况下,可看到在同路径下生成同名的可执行文件(exec文件)
<三>使用“Markdown方言”编写代码注释
- 设置快捷方式:Xcode -> Preferences -> Key Bindings -> 在下方 1 处设置一个自己的名称(如:
My
) -> 在 2 处输入:Show rendered
-> 在 3 处设置想要用的快捷键(如:option + M
)
① exam_01
- 输入
//: # Heading1
/*:
* item1
* item2
*/
- option + M,可见:
② demo_02
- 输入
/// A demo function ✨
func demo() {}
- 将光标放在demo方法名上,option+command+2,可以在quick help看到对该方法的注释,如下:
- option
③ demo_03(含参数说明)
更多优雅高效使用Xcode参见官网或Playground Secrets and Power Tips
二 基本语法
1、var / let
1、理解区分概念
(1)关键字、标识符
① mutating的使用
(2)常量、变量
(3)let、var
传统上,每种语言都用Hello World作为首程序,那么,我们也以此开始Swift学习之旅吧!
打开Xcode—>create a new project—>OS X Application—>Command Line Tool—>Language(Swift)
main.swift
println("Hello, World")
1.生成的文件名:以.swift作为扩展名
2.从上面的程序可知:
①Swift不需要导入头文件
②Swift不需要main函数
③Swift不需要每一语句都以;结束
此外,在编写Swift程序的时候,可以通过Xcode 的playground来进行查看程序运行的结果,工欲善其事必先利其器,如何使用playground,http://blog.csdn.net/yang_chengfeng/article/details/50587577,这是个人的一个小总结,下面所讲的程序都将在playground中进行
01-变量和常量
用 var定义变量,let定义常量
var myVariable = 42
myVariable = 50
let myConstant = 42
但是,无论是变量还是常量,好像都不知道所定义的数据类型。其实不是这样的,编译器会根据所赋值默认变量的数据类型,可以如下:
let implicitInteger = 70
let implicitDouble = 70.0 // ①
对于①,如果是Float类型(注:在Swift中,数据类型名首字母大写),是否跟C语言一样写成70.0f?不是的:
let explicitFloat : Float = 70.0
// ②
如何证明呢?
可以在②处输入explicitFloat,Xcode会有提示,提示可以看到:Float explicitFloat
练习:
定义一个数据类型为Float的常量
let num: Float = 4
一种数据类型的数可以通过强制转换成另一种数据类型
02-字符串
let label = "The width is "
let width = 94
let labelWidth = label + String(94) // + :具有拼接两个字符串的作用
输出结果:
“The width is 94”
如果要在字符串中显示变量,可以:(变量名)
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples"
let fruitSummary = "I have \(apples + oranges) pieces of fruit"
练习:
let name = "chengfeng_Yang"
let a: Float = 12.2
let b: Float = 12.2
let greeting = "Hello, \(name). \(a) + \(b) = \(a+b)"
03-数组和字典
空数组用[], 空字典用:[:]
let emptyArray = [String]() // ①
let emptyDictionary = DIctionary<String, Float>()
对于①,原来是:let emptyArray = String[]()
:不过运行过程出现:Array types are now written with the brackets around the element type, 并且此时编译器会提示:Fix-it String[->[String 或 Fix-it Insert [
var shoppingList = ["catfish", "water", "tulips"]
shoppingList[1] = "bottle of water"
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic"
]
occupations["Jayne"] = "Public Relations"
04-控制流
let individualScore = [75, 43, 103, 87,12]
var teamScore = 0
for score in individualScore{
if score > 50{ // if后面应该是Bool类型
teamScore += 3
} else {
teamScore += 1
}
}
teamScore
如无特殊说明,下面的程序的输出结果作为注释,注在 // 后
用?标记optional type , 用nil表示此类型数据丢失
var optionalSrting: String? = "Hello" // Hello
optionalSrting == nil // false
if语句:
var optionalName: String? = "John"
var greeting1 = "Hello"
if let name = optionalName{
greeting1 = "Hello, \(name)"
}
switch语句:
1.一定要讨论到所有情况(即:default在大部分情况下是不能省略的)
2.where的作用:用来增加判断条件
3.case用法
4.不需要break也可以执行完对应的内容自动对出程序
let vegetable = "red pepper"
switch vegetable {
case "celery":
let vegetableComment = "Add1"
case "cucuber", "watercress":
let vegetableComment = "Add2"
case let x where x.hasSuffix("pepper"):
let vegetableComment = "\(x)"
default:
let vegetableComment = "nothing"
}
for-in的使用:
let interestingNumbers = [
"Prime":[2, 3, 5, 7, 11, 13],
"Fibonacci":[1, 1, 2, 3, 5, 8],
"Square":[1, 4, 9, 16, 25],
]
var largest = 0
for(kind, numbers) in interestingNumbers{
for number in numbers{
if number > largest{
largest = number
}
}
}
largest // 25
var firstLoop = 0
for i in 0...3{
firstLoop += i
}
firstLoop // 6
其中,0…3是[0, 3]的取值范围
var secondForLoop = 0
for var i = 0; i < 3; ++i{
secondForLoop += 1
}
secondForLoop // 3
while 与 do…while
var n = 2
while n < 100 {
n = n * 2
}
n // 128
var m = 2
do{
m = m * 2
} while m < 100
m // 128
7、控制语句:
(6)where语句:
① switch
② for
let numbers = [1, 2, 3, 4]
for item in numbers where item>2 {
print("Count is: \(item)")
}
2、Collection
① 数组
- 引用:
func collectionFunc() {
var arr = [1, 2, 3]
let tempArr = arr
print(self.getBufferAddress(array: arr)) // UnsafeBufferPointer(start: 0x0000600000478e20, count: 3)
print(self.getBufferAddress(array: tempArr)) // UnsafeBufferPointer(start: 0x0000600000478e20, count: 3)
arr.append(4)
print(self.getBufferAddress(array: arr)) // UnsafeBufferPointer(start: 0x0000600000297ae0, count: 4)
print(self.getBufferAddress(array: tempArr)) // UnsafeBufferPointer(start: 0x0000600000478e20, count: 3)
}
func getBufferAddress<T>(array: [T]) -> String {
return array.withUnsafeBufferPointer {
return String(describing: $0)
}
}
- copy:
let b = NSMutableArray(array: [1, 2, 3])
let copyB:NSArray = b
let deepCopyB = b.copy() as! NSArray
b.insert(0, at: 0)
print(copyB) // (0, 1, 2, 3)
print(deepCopyB) // (1, 2, 3)
- popLast() & removeLast()
var arr = [1, 2, 3]
arr.forEach { print($0) } // 逐个打印
let firstNum = arr.index { $0 == 1}
print(firstNum) // Optional(0)
print(arr.filter { $0 % 2 == 0 }) // [2]
print(type(of: arr.last)) // Optional<Int>
print(type(of: arr.removeLast())) // Int
print(type(of: arr.popLast())) // Optional<Int>
- 排序
var arr = [3, 2, 6, 1, 9, 5]
print(arr.sorted()) // [1, 2, 3, 5, 6, 9]
print(arr.sorted(by: >)) // [9, 6, 5, 3, 2, 1]
print(arr.sorted(by: <)) // [1, 2, 3, 5, 6, 9]
var fibonacci = [0, 1, 1, 2, 3]
let pivot = fibonacci.partition(by: { $0 < 1 })
print(fibonacci) // [3, 1, 1, 2, 0]
print(pivot) // 4
print(fibonacci[0..<pivot]) // [3, 1, 1, 2]
print(fibonacci[pivot..<fibonacci.endIndex]) // [0]
②字典
8、原生集合类型
(1)数组(Array)
① 有序、可重复
② swift数组类型Array,属于结构体类型;Foundation框架中NSArray数组,是一个类,非结构体,两者可通过“零开销桥接技术”互相转化
// 声明并初始化
var studentList1: Array<String> = ["张三", "李四"]
var studentList2: [String] = ["张三", "李四"]
let studentList3: [String] = ["张三"]
var studentList4 = [String]()
③ 不可变数组访问速率比可变数组高
④ 数组的增删改查
var studentList: [String] = ["张三", "李四"]
print(studentList)
// append追加一个元素, += 追加多个元素
studentList.append("王五")
print(studentList)
studentList += ["董六"]
print(studentList)
studentList.insert("刘备", at: studentList.count)
print(studentList)
let removeStu = studentList.remove(at: 0)
print(studentList)
studentList[0] = "张飞"
print(studentList)
⑤ 遍历
for item in studentList {
print(item)
}
for (index, value) in studentList.enumerated() {
print("Item \(index+1) : \(value)")
}
(2)集合(Dictionary)
① 键值对,无序性
var studentDictionary1 = Dictionary<Int, String>()
var studentDictionary2 = [Int: String]()
var studentDictionary3: Dictionary<Int, String> = [101: "张三", 102: "李四"]
var studentDictionary4 = [101: "张三", 102: "李四"]
② 删改
studentDictionary4[101] = "董六"
print("班级人数:\(studentDictionary4.count)")
let dismissStu = studentDictionary4.removeValue(forKey: 102)
let replaceStu = studentDictionary4.updateValue("王五", forKey: 101)
③ 遍历
for stuID in studentDictionary4.keys {
print("学号:\(stuID)")
}
for stuName in studentDictionary4.values {
print("姓名: \(stuName)")
}
for (stuId, stuName) in studentDictionary4 {
print("学号-姓名:\(stuId) - \(stuName)")
}
(3)Set
① 无序,不重复
let A: Set<String> = ["a", "b", "c", "d"]
let B: Set<String> = ["d", "c", "e", "f"]
print("交集:\(A.intersection(B))")
print("并集:\(A.union(B))")
print("异或集合:\(A.symmetricDifference(B))")
print("差集:\(A.subtracting(B))")
print("是否子集:\(A.isSubset(of: B))")
9、函数
(1)函数参数
① 使用参数标签
func rectangleArea(W width:Double, H height: Double) -> Double {
let area = width * height
return area
}
print("面积:\(rectangleArea(W: 320, H: 480))")
② 省略参数标签
func rectangleArea(_ width:Double, H height:Double) -> Double {
let area = width * height
return area
}
print("面积:\(rectangleArea(100, H: 2))")
③ 参数默认
func makeCoffee(type: String = "卡布奇诺") -> String {
return "制作一杯\(type)咖啡"
}
let coffee = makeCoffee()
print(coffee)
④ 可变参数
func sum(numbers:Double...) -> Double {
var total:Double = 0
for num in numbers {
total += num
}
return total
}
print(sum(numbers: 30, 40))
⑤ 值类型参数的引用传递
swift提供inout关键字帮助实现将一个值类型参数以引用方式传递
func increment(value: inout Double, amount: Double = 1.0) {
value += amount
}
var value: Double = 10.0
increment(value: &value)
print(value) // 11.0
increment(value: &value, amount: 100.0)
print(value) // 111.0
(2)函数返回值
① 无返回值
func nothingForItOne() {
}
func nothingForItTwo() -> () {
}
func nothingForItThree() -> Void {
}
② 多返回值
func position(dt:Double, speed:(x: Int, y: Int)) -> (x: Int, y: Int) {
let posx: Int = speed.x * Int(dt)
let posy: Int = speed.y * Int(dt)
return(posx, posy)
}
let move = position(dt: 60.0, speed: (10, -5))
print("物体位移:\(move.x), \(move.y)")
(3)函数嵌套
func calculate(opr: String) -> (Int, Int) -> Int {
var result: (Int, Int) -> Int
func add(a: Int, b: Int) -> Int {
return a+b
}
func sub(a: Int, b: Int) -> Int {
return a-b
}
switch (opr) {
case "+":
result = sub
default:
result = add
}
return result
}
10、闭包
对于上述嵌套函数的示例,可用下面代码替代:
func calculate(opr: String) -> (Int, Int) -> Int {
var result: (Int, Int) -> Int
switch (opr) {
case "+":
result = { // 闭包
(a: Int, b: Int) -> Int in
return a+b
}
default:
result = { // 闭包
(a: Int, b: Int) -> Int in
return a-b
}
}
return result
}
(1)示例:
// 嵌套函数
func makeArray() -> (String) -> [String] {
var ary: [String] = [String]()
func addElement(element: String) -> [String] { // ①
ary.append(element)
return ary
}
return addElement
}
let f1 = makeArray()
print(f1("张三"))
// 闭包
func makeArray() -> (String) -> [String] {
var ary: [String] = [String]()
return {(element: String) -> [String] in // ①
ary.append(element)
return ary
}
}
let f1 = makeArray()
print(f1("张三"))
(2)尾随闭包
① 注意:闭包必须是参数列表最后一个参数
② 提供参数名缩写功能:可以直接通过$0
和$1
等来表示闭包中的第一个、第二个参数
func calculate(opr: String, funN:(Int, Int) -> Int) {
switch(opr) {
case "+":
print("10 + 5 = \(funN(10, 5))")
default:
print("10 - 5 = \(funN(10, 5))")
}
}
calculate(opr: "+", funN: {(a: Int, b: Int) -> Int in return a + b})
calculate(opr: "+"){(a: Int, b: Int) -> Int in return a + b}
calculate(opr: "+"){$0 + $1}
calculate(opr: "-") {
(a: Int, b: Int) -> Int in
return a - b
}
calculate(opr: "-") {
$0 - $1
}
(3)隐藏return关键字
func calculate(opr: String) -> (Int, Int) -> Int {
var funN: (Int, Int) -> Int
switch(opr) {
case "+":
funN = {a, b in a + b}
default:
funN = {a, b in a - b}
}
return funN
}
(4)使用闭包返回值
let c1: Int = {(a: Int, b: Int) -> Int in
return a + b
}(10, 5)
print("10 + 5 = \(c1)")
(5)逃逸闭包&非逃逸闭包
11、面向对象
(1)基本特性:封装、继承、多态
(2)数据类型:类、结构体、枚举
示例代码11-1:
enum WeekDay{
case Monday, Tuosday, Wednesday, Thursday, Friday
}
var day = WeekDay.Monday
day = WeekDay.Friday
day = .Wednesday
func writeGreeting(day: WeekDay) {
switch day {
case .Monday:
print("周一")
default:
print("非周一")
}
}
① 枚举
示例代码11-2
// 原始值类型声明
enum WeekDays: Int {
case Monday = 0
case Tuesday = 1
case Wednesday = 2
case Thursday = 3
case Friday = 4
}
// 取出原始值
enum WeekDay: Int {
case Monday = 0, Tuesday, Wednesday, Thursday, Friday
}
print("周三的原始值:\(WeekDay.Wednesday.rawValue)")
示例代码11-3
enum Figure {
case Rectangle(Int, Int)
case Circle(Int)
}
func printFugure(figure: Figure) {
switch figure {
case .Rectangle(let width, let height):
print("矩形宽高:\(width),\(height)")
case .Circle(let radius):
print("圆形半径:\(radius)")
}
}
var figure = Figure.Circle(2)
printFugure(figure: figure)
示例代码11-4
// 关于类和结构体
class Employee {
var no: Int = 0
var name: String = ""
var job: String?
var salary: Double = 0
var dept: Department?
}
struct Department {
var no: Int = 0
var name: String = ""
}
② 结构体
③ 类
这里写代码片
12、属性与下标
(1)属性与成员变量 & 计算属性与存储属性
① 存储属性 :常量属性和变量属性;适用于类和结构体,不适用于枚举类型
注:常量值类型,无论是结构体还是枚举类型都不能修改
② 延迟存储属性
示例代码 12-1:
class Employee {
var no: Int = 0
var name: String = ""
var job: String?
var salary: Double = 0
lazy var dept: Department = Department() // 延迟加载:dept属性只有在第一次访问时才加载,如果永远不访问,就不会创建,可以减少内存占用
}
struct Department {
let no: Int = 0
var name: String = ""
}
let emp = Employee()
③ 计算属性:类、结构体、枚举都可以定义计算属性;计算属性提供了Getter和Setter
示例代码 12-2:
class Employee {
var no: Int = 0
var firstName: String = "Menior"
var lastName: String = "Ly"
var job: String?
var salary: Double = 0
lazy var dept: Department = Department()
var fullName: String { // ① Setter和Getter
get {
return firstName + lastName
}
set (newFullName){
var name = newFullName.components(separatedBy: ".")
firstName = name[0]
lastName = name[1]
}
}
}
struct Department {
let no: Int = 0
var name: String = ""
}
let emp = Employee()
print(emp.fullName)
emp.fullName = "Her.Ben"
print(emp.fullName)
④ 只读计算属性
示例代码 12-3
// 将示例代码 12-2 中 ① 改为只读计算属性
var fullName: String {
return firstName + lastName // 只读计算属性
}
⑤ 结构体和枚举的计算属性
示例代码 12-4
struct Department {
let no: Int = 0
var name: String = "SALES"
var fullName: String {
return "Love" + name + "Department"
}
}
enum WeekDays: String {
case Monday = "Mon."
case TuesDay = "Tue."
case Wednesday = "Wed."
case Thursday = "Thu."
case Friday = "Fri."
var message: String {
return "Today is " + self.rawValue
}
}
let dept = Department()
print(dept.fullName)
let day = WeekDays.Monday
print(day.message)
⑥ 属性观察者
注:属性观察者不能监听延迟存储属性和常量存储属性的变化
// swift - newValue、oldValue
willSet() {
}
didSet() {
}
// OC - KVO - NSKeyValueObserving
- (void)willChangeValueForKey:(NSString *)key;
- (void)didChangeValueForKey:(NSString *)key;
示例代码 12-5
class Employee {
var no: Int = 0
var name: String = "Monior" {
willSet(newName) {
print("员工新名:\(newName)")
}
didSet(oldName) {
print("员工新名:\(oldName)")
}
}
var job: String?
var salary: Double = 0
var dept: Department?
}
struct Department {
var no: Int = 0 {
willSet {
print("新编号:\(newValue)")
}
didSet {
print("旧编号:\(oldValue)")
}
}
var name: String = ""
}
示例代码 12-6
class Employee {
var no: Int = 0
var name: String = "Monior" {
willSet(newName) {
print("员工新名:\(newName)") // Smith
}
didSet(oldName) {
print("员工新名:\(oldName)") // Monior
}
}
var job: String?
var salary: Double = 0
var dept: Department?
}
struct Department {
var no: Int = 0 {
willSet {
print("新编号:\(newValue)") // 30
}
didSet {
print("旧编号:\(oldValue)") // 0
}
}
var name: String = "RESEARCH"
}
let emp = Employee()
emp.no = 100
emp.name = "Smith"
var dept = Department()
dept.no = 30
13、方法
18、泛型
(1)什么是泛型?
(2)作用:最大限度重用代码、保护类型的安全、提高性能
(3)如何使用?
① 基本使用
示例代码 18-1
func isEqual<T: Comparable>(a: T, b: T) -> Bool { // T:占位符
return (a == b)
}
示例代码 18-2
struct StringQueue { // 缺点:只能放置String类型的元素
var items = [String]()
mutating func queue(item: String) {
items.append(item)
}
mutating func deQueue() -> String? {
if items.isEmpty {
return nil
} else {
return items.remove(at: 0)
}
}
}
var strQueue = StringQueue()
strQueue.queue(item: "张三")
strQueue.queue(item: "李四")
strQueue.queue(item: "王五")
strQueue.queue(item: "董六")
print(strQueue.deQueue()!)
print(strQueue.deQueue()!)
print(strQueue.deQueue()!)
示例代码 18-3
struct Queue<T> {
var items = [T]()
mutating func queue(item: T) {
items.append(item)
}
mutating func deQueue() -> T? {
if items.isEmpty {
return nil
} else {
return items.remove(at: 0)
}
}
}
var genericQueue = Queue<Int>()
genericQueue.queue(item: 0)
genericQueue.queue(item: 1)
genericQueue.queue(item: 2)
genericQueue.queue(item: 3)
print(genericQueue.deQueue()!) // 0
print(genericQueue.deQueue()!) // 1
print(genericQueue.deQueue()!) // 2
print(genericQueue) // Queue<Int>(items: [3])
② 泛型扩展
示例代码 18-4
struct Queue<T> {
var items = [T]()
mutating func queue(item: T) {
items.append(item)
}
mutating func deQueue() -> T? {
if items.isEmpty {
return nil
} else {
return items.remove(at: 0)
}
}
}
extension Queue {
func peek(position: Int) -> T? {
if position < 0 || position > items.count {
return nil
} else {
return items[position]
}
}
}
var genericQueue = Queue<Double>()
genericQueue.queue(item: 0.22)
genericQueue.queue(item: 1.43)
genericQueue.queue(item: 2.55)
genericQueue.queue(item: 3.98)
print(genericQueue.peek(position: 2)!) // 2.55
print(genericQueue.peek(position: 1)!) // 1.43
print(genericQueue) // Queue<Double>(items: [0.22, 1.4299999999999999, 2.5499999999999998, 3.98])
三、进阶篇
1、内存管理
2、错误处理
3、Foundation框架
(1) NSNumber
① 基本使用
示例代码 四-3-1
import Foundation
var intSwift = 80
var intNumber = NSNumber(value: intSwift)
var floatNumber = NSNumber(value: 80.0)
let myInt = intNumber.intValue
let myFloat = floatNumber.floatValue
② 比较大小
// 比较方式一
func isEqual(_ object: Any) -> Bool
// 比较方式二
func compare(_ other: Date) -> ComparisonResult
(10)正则表达式
① 即:regular expression;简写:regex、regexp、RE
② 相关类:NSRegularExpression
、NSPredicate
、NSTextCheckingResult
等
a、NSPredicate:func evaluate(with: Any?)
,目的是验证字符串的有效性,缺点是不能过滤、检索、替换等,只能进行判断;无法处理错误
import Foundation
let pattern = "^\\W+@[a-zA-Z_]+?\\.[a-zA-Z]{2,3}$"
let predicate = NSPredicate(format: "SELF MATCHES %@", pattern)
let str = "guangdongsheng@gmail.com"
if predicate.evaluate(with: str) {
print("格式有效")
} else {
print("格式无效")
}
b、NSRegularExpression:解决了NSPredicate问题