🌈 简介
Swift 是一种支持多编程范式和编译式的开源编程语言,苹果于2014年WWDC(苹果开发者大会)发布, 用于开发 iOS, OS X 和 watchOS 应用程序。
Swift 结合了 C 和 Objective-C 的优点并且不受 C 兼容性的限制。
Swift 在 Mac OS 和 iOS 平台可以和 Object-C 使用相同的运行环境。
2015年6月8日, 苹果于WWDC 2015上宣布, Swift将开放源代码, 包括编译器和标准库。
🍎 环境搭建
电脑:
官方网站
IDE
Xcode - 直接在AppStore里面搜索并下载
🍎 Hello World
print("Hello world!")
🍎 变量
// 整型
var a = 100
// 浮点型
var b = 1000.0
// 字符串
var c = "Objcat"
// 数组
var d = [1, 2, 3]
// 字典
let e = ["name": "objcat", "age": "18"]
// 元组
let f = (1, 2, 3)
let g = (name: "张三", age: "16")
var 表示变量 let 表示常量
🍎 函数
🌲 无参数无返回值
func hello() {
print("hello world!")
}
🌲 有参数无返回值
func hello(text: String) {
print(text)
}
hello(text: "hello world!")
🌲 有参数有返回值
func hello(text: String) -> String {
return text
}
var result = hello(text: "hello world!")
print(result)
🍎 字符串
🌲 定义字符串
var my_str = "123"
🌲 获取字符串
// 从头截取两个字符
my_str[my_str.index(my_str.startIndex, offsetBy: 0) ... my_str.index(my_str.startIndex, offsetBy: 1)] // 12
// 从头截取两个字符
my_str[...my_str.index(my_str.startIndex, offsetBy: 1)] // 12
// 截取完整字符串
my_str[stmy_strr.index(my_str.startIndex, offsetBy: 0)...my_str.index(my_str.endIndex, offsetBy: -1)] // 123
// 或
my_str[my_str.index(my_str.startIndex, offsetBy: 0)...]
// 或
my_str[...]
🌲 拼接字符串
// 加号拼接
my_str2 = my_str + "456" // 123456
// 数组拼接
my_str2 = ["123", "456", "789"].joined() // 123456789
// format
var my_str2 = "\(my_str)456" // 123456
🌲 替换字符串
// 将第一个字符替换成12
my_str.replaceSubrange(my_str.index(my_str.startIndex, offsetBy: 0)...my_str.index(my_str.startIndex, offsetBy: 0), with: "12") // 1223
🌲 查找字符串位置
print(my_str.range(of: "2"))
// Optional(Range(Swift.String.Index(_rawBits: 65536)..<Swift.String.Index(_rawBits: 131072)))
🌲 遍历字符串
for s in my_str {
print(s)
}
🍎 数组
🌲 定义数组
var my_arr = [1, 2, 3]
🌲 获取元素
// 通过下标获取 下标从0开始
print(my_arr[0]) // [1, 2, 3]
🌲 添加元素
my_arr.append(4)
print(my_arr) // [1, 2, 3, 4]
🌲 删除元素
// 移除第三个元素
my_arr.remove(at: 3)
print(my_arr) // [1, 2, 3]
🌲 截取元素
// 截取第一个元素
my_arr[0...0] // [1]
或
my_arr[0..<1] // [1]
// 某一个位置截取到最后
my_arr[0...] // [1, 2, 3]
my_arr[1...] // [2, 3]
// 从开始截取到某一个位置
my_arr[...0] // [1]
my_arr[...(my_arr.count - 1)] // [1, 2, 3]
// 截取所有元素
my_arr[...]
🌲 拼接数组
my_arr.append(contentsOf: [4, 5, 6]) // [1, 2, 3, 4, 5, 6]
🍎 字典
🌲 定义字典
var my_dic = ["name": "张三", "age": "18"]
🌲 获取元素
var name = my_dic["name"]
print(name ?? "") // 张三
🌲 添加元素
my_dic["gender"] = "男"
print(my_dic) // ["gender": "男", "age": "18", "name": "张三"]
🌲 删除元素
my_dic.removeValue(forKey: "name")
print(my_dic) // ["age": "18"]
🌲 截取字典
无法截取
🌲 拼接字典
无法拼接
🍎 元组
🌲 定义元组
var my_tuple = (0, "66", 2)
var my_tuple2 = (name: "张三", age: 18)
🌲 获取元素
# 通过下标获取 下标从0开始
print(my_tuple.0) // 0
print(my_tuple2.name) // 张三
🌲 添加元素
元组不能修改, 所以无法添加
🌲 删除元素
元组不能修改, 所以无法删除
🌲 截取元素
无法截取
🌲 拼接元组
无法拼接
🍎 集合
🌲 定义集合
var my_set: Set = [1, 2, 3, 1] // [3, 2, 1] 无序
var my_set2 = Set([1, 2, 3, 2]) // [2, 1, 3] 无序
🌲 获取元素
# 集合不能获取元素 但可以先转成数组再操作
var my_arr = my_set.sorted()
print(my_arr[0])
🌲 添加元素
my_set.insert(4)
print(my_set) // [3, 1, 4, 2] 无序
🌲 删除元素
my_set.remove(1)
print(my_set) // [3, 4, 2] 无序
🌲 截取元素
无法截取 - 可以转化成数组后截取
🌲 拼接集合
var my_set: Set = [1, 2, 3]
var my_set2 = Set([1, 2, 3, 4])
// 交集
print(my_set.intersection(my_set2)) // [1, 2, 3] 无序
// 并集
my_set.formUnion(my_set2)
print(my_set) // [1, 2, 3, 4] 无序
// 补集 前者补给后者的值 - - 颠倒过来后返回是 [] 因为没有可补的
print(my_set2.subtracting(my_set)) // [4]
🍎 条件语句
🌲 if
let a = 1
// 如果a等于1 执行条件
if a == 1 {
print("a等于1")
}
🌲 if - else if
let a = 2
// 如果a等于1执行1 如果a等于2执行2
if a == 1 {
print("a等于1")
} else if a == 2 {
print("a等于2")
}
🌲 if - else if - else
let a = 3
# 如果都不等 执行else
if a == 1 {
print("a等于1")
} else if a == 2 {
print("a等于2")
} else {
print("a既不等于1也不等于2")
}
🍎 循环语句
🌲 for
for i in [1, 2, 3] {
print(i) // 1 2 3
}
for i in 0...3 {
print(i) // 0 1 2 3
}
[1, 2, 3].forEach({item in
print(item)
}) // 1 2 3
🌲 while
var i = 0
while i < 3 {
print(i) // 0 1 2
i += 1
}
🍎 Block
🌲 无参数无返回值
let testBlock = { () -> Void in
print("无参数无返回值")
}
// 或
let testBlock = { () in
print("无参数无返回值")
}
// 或
let testBlock = {
print("无参数无返回值")
}
// 执行
testBlock()
// 直接执行: 末位加括号 下文略
{
print("无参数无返回值")
}()
🌲 有参数无返回值(单参数, 多参数)
let testBlock = { (a: String) -> Void in
print(a)
}
// 或
let testBlock = { a in
print(a)
}
// 执行
testBlock("有参数无返回值") // 有参数无返回值
// 多参数 两个或两个以上必须加括号 而且第二个参数类型不可推导 只能定义类型
let testBlock = { (a, b: String) in
print(a)
}
testBlock(123, "123") // 123
🌲 有参数有返回值
let testBlock = { (a: String) -> String in
return a
}
// 或
let testBlock = { a -> String in
return a
}
print(testBlock("有参数有返回值"))
🌲 回调
func hello(a: String, block: @escaping () -> Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + 2, execute: {
block()
})
}
// 执行
hello(a: "123", block: {
print("回调结束")
})
// 或
hello(a: "123") {
print("回调结束")
}
print("执行完毕")
/**
执行完毕
回调结束
*/
// 两个Block参数
func hello(a: String, block: @escaping () -> Void, block2: @escaping () -> Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + 2, execute: {
block()
block2()
})
}
// 执行 使用方法的时候 Xcode会自动提示这种写法
hello(a: "123") {
} block2: {
}
// Block参数后面还有参数
func hello(a: String, block: @escaping () -> Void, block2: @escaping () -> Void, b: String) {
DispatchQueue.global().asyncAfter(deadline: .now() + 2, execute: {
block()
block2()
})
}
// 执行 同样Xcode会自动提示这种写法
hello(a: "123", block: {
}, block2: {
}, b: "145456")
🌲 排序
// 从小到大
let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
let sortNumbers = numbers.sorted(by: { a, b in a < b })
print("numbers - " + "\(sortNumbers)") // [1, 2, 3, 4, 5, 6, 7, 8]
// 或
let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
let sortNumbers = numbers.sorted(by: { return $0 < $1 })
print("numbers - " + "\(sortNumbers)") // [1, 2, 3, 4, 5, 6, 7, 8]
// 或
let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
let sortNumbers = numbers.sorted(by: { $0 < $1 })
print("numbers - " + "\(sortNumbers)") // [1, 2, 3, 4, 5, 6, 7, 8]
// 或
let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
let sortNumbers = numbers.sorted(by: < )
print("numbers - " + "\(sortNumbers)") // [1, 2, 3, 4, 5, 6, 7, 8]
//从大到小 - 修改符号即可
let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
let sortNumbers = numbers.sorted(by: > )
print("numbers - " + "\(sortNumbers)") // // [1, 2, 3, 4, 5, 6, 7, 8]
🌲 筛选
let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
let filterNumbers = numbers.filter({ $0 % 2 == 0 })
print(filterNumbers)
🍎 类和对象
🌲 类
class Persion {
}
🌲 定义成员变量
class Persion {
var name: String? // 可选类型
var age: Int = 0 // 普通变量
}
🌲 定义初始化方法
class Persion {
var name: String?
var age: Int = 0
// 初始化方法
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
# 初始化
# 方法1
var per = Persion(name: "张三", age: 16)
# 方法2
var per2 = Persion.init(name: "李四", age: 18)
🌲 定义方法
class Persion {
var name: String?
var age: Int = 0
init(name: String, age: Int) {
self.name = name
self.age = age
}
func say() {
print("人说")
}
static func say() {
print("人类说")
}
}
# 调用
var per = Persion(name: "张三", age: 16)
per.say() // 人说
Persion.say() // 人类说
🌲 继承
class Student: Persion {
override func say() {
print("学生说")
}
}
let stu = Student(name: "学生0", age: 18)
stu.say() // 学生说
🍎 类型转换
🌲 String & Int (Double/Float通用)
// String -> Int
let a = "123"
let b = Int(a)
print(b ?? "")
// Int -> String
let a = 123
let b = String(a)
print(b)
// Double
let a = "123"
let b = Double(a)
print(b ?? "")
// Float
let a = "123"
let b = Float(a)
print(b ?? "")
🍎 反射
var mirror: Mirror? = Mirror(reflecting: stu);
repeat {
mirror?.children.forEach({child in
print(child.label ?? "")
print(type(of: child.value))
})
mirror = mirror?.superclassMirror ?? nil
} while (mirror != nil)
/**
id
Optional<String>
name
Optional<String>
age
Int
*/
🍎 GCD
🌲 主队列 / 全局队列
// 主队列
DispatchQueue.main
// 全局队列
DispatchQueue.global()
执行任务是用抛的方式 把xx任务抛到某个队列中 队列会分配合适的线程去执行任务
- 抛到主队列中的任务由主线程执行
- 抛到全局队列中的任务 可能由主线程执行 也可能由子线程执行
🌲 线程阻塞
即主线程中执行`耗时任务`或`等待`
`耗时任务`: 例如从1循环到1亿
`等待`: 例如 sleep(5)
🌲 串行并行
串行: 按顺序执行
并行: 同时执行
常见的串行队列
DispatchQueue.main
常见的并行队列
DispatchQueue.global()
🌲 主队列执行任务(同步)
DispatchQueue.main.sync {
print("主线程中同步执行任务")
print(Thread.current)
}
print("执行完毕")
/**
崩溃
该方法不能在主线程中执行 因为会阻塞
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
*/
🌲 主队列执行任务(异步)
DispatchQueue.main.async {
print("主线程中异步执行任务")
print(Thread.current)
}
print("执行完毕")
/**
执行完毕
主线程中异步执行任务
<NSThread: 0x60000174c380>{number = 1, name = main}
*/
🌲 全局队列执行任务(同步)
可以看到虽然把任务抛到了global队列 但任务还是在主线程执行的
DispatchQueue.global().sync {
print("主线程中同步执行任务")
print(Thread.current)
}
print("执行完毕")
/**
子线程中同步执行任务
<NSThread: 0x60000039c240>{number = 1, name = main}
执行完毕
*/
🌲 全局队列执行任务(异步)
DispatchQueue.global().async {
print("子线程中异步执行任务")
print(Thread.current)
}
print("执行完毕")
/**
执行完毕
子线程中异步执行任务
<NSThread: 0x600000e57240>{number = 3, name = (null)}
*/
🌲 全局队列回到同步主队列
DispatchQueue.global().sync {
// 全局队列的同步在主线程执行
print("主线程中同步执行任务")
print(Thread.current)
DispatchQueue.main.sync {
print("主线程中同步执行任务")
print(Thread.current)
}
print("子线程执行完毕")
print(Thread.current)
}
print("执行完毕")
/**
主线程中同步执行任务
<NSThread: 0x6000000b86c0>{number = 1, name = main}
(lldb)
崩溃:
*/
🌲 全局队列回到异步主队列
DispatchQueue.global().async {
print("子线程中异步执行任务")
print(Thread.current)
DispatchQueue.main.sync {
print("主线程中同步执行任务")
print(Thread.current)
}
print("子线程执行完毕")
print(Thread.current)
}
print("执行完毕")
/**
执行完毕
子线程中异步执行任务
<NSThread: 0x6000016a2000>{number = 4, name = (null)}
主线程中同步执行任务
<NSThread: 0x60000169c200>{number = 1, name = main}
子线程执行完毕
<NSThread: 0x6000016a2000>{number = 4, name = (null)}
*/
DispatchQueue.global().async {
print("子线程中异步执行任务")
print(Thread.current)
DispatchQueue.main.async {
print("主线程中异步执行任务")
print(Thread.current)
}
print("子线程执行完毕")
print(Thread.current)
}
print("执行完毕")
/**
执行完毕
子线程中异步执行任务
<NSThread: 0x60000332a200>{number = 9, name = (null)}
子线程执行完毕
<NSThread: 0x60000332a200>{number = 9, name = (null)}
主线程中异步执行任务
<NSThread: 0x60000336c240>{number = 1, name = main}
*/
🌲 连续全局队列任务(异步)
for i in 1...5 {
DispatchQueue.global().async {
print("子线程异步任务\(i)")
}
}
print("执行完毕")
> 顺序不固定
/**
执行完毕
子线程异步任务2
子线程异步任务3
子线程异步任务4
子线程异步任务5
子线程异步任务1
/**
🌲 连续全局队列任务(同步)
for i in 1...5 {
DispatchQueue.global().sync {
// 全局队列的同步在主线程执行
print("主线程同步任务\(i)")
}
}
print("执行完毕")
> 顺序固定
// 主线程同步任务1
// 主线程同步任务2
// 主线程同步任务3
// 主线程同步任务4
// 主线程同步任务5
// 执行完毕
🌲 自定义队列
let queue = DispatchQueue(label: "my_queue", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
queue.async {
}
attributes
- .concurrent 并行
- .initiallyInactive 崩溃
- DispatchQueue.Attributes() 串行
DispatchQoS
- .userInteractive 需要用户交互的, 优先级最高, 和主线程一样
- .userInitiated 即将需要, 用户期望优先级, 优先级高比较高
- .default 默认优先级
- .utility 需要执行一段时间后, 再通知用户, 优先级低
- *.background 后台执行的, 优先级比较低
- *.unspecified 不指定优先级, 最低
autoreleaseFrequency
- .inherit 表示不确定, 之前默认的行为也是现在的默认值
- .workItem 表示为每个执行的项目创建和排除自动释放池, 项目完成时清理临时对象
- .never 表示GCD不为您管理自动释放池
target
- 传入nil默认子线程
- 传入 DispatchQueue.main 则为主线程
🌲 串行队列
// 快速创建串行队列
let queue = DispatchQueue(label: "my_serial_queue");
for i in 0...100 {
queue.async {
print("\(i)");
}
}
// 0
// 1
// ...
// 100
🌲 延时(After)
DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
print(Thread.current)
print("延迟3s")
})
/**
<NSThread: 0x600000ef83c0>{number = 1, name = main}
延迟3s
*/
DispatchQueue.global().asyncAfter(deadline: .now() + 3, execute: {
print(Thread.current)
print("延迟3s")
})
/**
<NSThread: 0x600000eb04c0>{number = 5, name = (null)}
延迟3s
*/
🌲 并行同步group_notiify(分组通知)
并行同步: 任务同时执行 每个任务中执行的程序是同步按顺序执行的
let group = DispatchGroup()
let queue = DispatchQueue.main
queue.async(group: group, execute: {
print(Thread.current)
print("任务1")
})
queue.async(group: group, execute: {
print(Thread.current)
print("任务2")
})
group.notify(queue: queue, execute: {
print(Thread.current)
print("任务执行完毕")
})
/**
<NSThread: 0x600002304740>{number = 1, name = main}
任务1
<NSThread: 0x600002304740>{number = 1, name = main}
任务2
<NSThread: 0x600002304740>{number = 1, name = main}
任务执行完毕
*/
let group = DispatchGroup()
let queue = DispatchQueue.global()
queue.async(group: group, execute: {
print(Thread.current)
print("任务1")
})
queue.async(group: group, execute: {
print(Thread.current)
print("任务2")
})
group.notify(queue: queue, execute: {
print(Thread.current)
print("任务执行完毕")
})
/**
<NSThread: 0x600003318cc0>{number = 8, name = (null)}
<NSThread: 0x600003330780>{number = 9, name = (null)}
任务1
任务2
<NSThread: 0x600003330780>{number = 9, name = (null)}
任务执行完毕
*/
🌲 并行异步group_notiify(分组通知)
并行异步: 任务同时执行 每个任务中执行的程序有可能是异步的 比如网络请求 说不定什么时间执行完
let group = DispatchGroup()
let queue = DispatchQueue.global()
group.enter()
queue.async {
print("简单任务1")
group.leave()
}
group.enter()
queue.async {
queue.asyncAfter(deadline: .now() + 3, execute: {
print("耗时任务2")
group.leave()
})
}
group.notify(queue: DispatchQueue.main, execute: {
print("完成")
})
并行同步的分组通知可以监测并行同步程序的同时结束 但是对于并行异步程序就不能准确收到执行结束的通知 如果要判断异步的结束 需要使用 enter() 和 leave() 当所有enter被leave之后 程序才会调用notify
🌲 信号量
信号量wait会阻塞线程 直到收到signal才放开阻塞 利用这一点可以来顺序执行代码 group.enter 底层就是信号量
let sem = DispatchSemaphore(value: 1)
sem.wait()
DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
print("任务1")
sem.signal()
})
sem.wait()
DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
print("任务2")
sem.signal()
})
sem.wait()
DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
print("任务3")
sem.signal()
})
print("执行完毕")
value: 每次执行几个任务 如果为2 会自动执行 2个wait 后面的代码
/**
任务1
任务2
执行完毕
任务3
注: 你可能会有一个疑问 为什么`执行完毕`会先于`任务3`执行 因为async是异步 同步要比异步执行的快 sem.wait执行后系统会阻塞线程并开始执行后面的代码直到收到sem.signal才放开阻塞
*/
但是上面的写法是在主线程中使用信号量 如果执行耗时任务会造成阻塞 导致界面卡顿 所以一般情况下不这么使用
所以还是在子线程中使用比较好 不会阻塞
// 异步
let sem = DispatchSemaphore(value: 1)
DispatchQueue.global().async {
sem.wait()
DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
print("任务1")
sem.signal()
})
sem.wait()
DispatchQueue.global().asyncAfter(deadline: .now() + 3, execute: {
print("任务2")
sem.signal()
})
sem.wait()
DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
print("任务3")
sem.signal()
})
sem.wait()
DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
print("任务4")
sem.signal()
})
print("执行完毕")
}
🌲 信号量 - 让程序不结束
let semaphore = DispatchSemaphore(value: 0).wait(timeout: .now() + 100)
🍎 异常处理
🌲 try
// 常规try 异常中断并执行catch
do {
let data = try Data(contentsOf: URL(string: "https://www.baidu.com")!)
let str = String(data: data, encoding: .utf8)
debugPrint(str ?? "")
} catch let err {
debugPrint(err)
}
// 不打印
do {
let data = try Data(contentsOf: URL(string: "https://www.baidu.com")!)
let str = String(data: data, encoding: .utf8)
print(str ?? "")
} catch {
}
// 不捕获 - 报错直接崩溃
let data = try Data(contentsOf: URL(string: "https://www.baidu.com")!)
let str = String(data: data, encoding: .utf8)
print(str ?? "")
🌲 try?
// 问try 异常即return
guard let data = try? Data(contentsOf: URL.init(string: "htt123ps://www.baidu.com")!) else {
return
}
let str = String(data: data, encoding: .utf8)
debugPrint(str ?? "")
🌲 try!
// `强try` 异常即崩溃
let data = try! Data(contentsOf: URL.init(string: "https://www.baidu.com")!)
let str = String(data: data, encoding: .utf8)
debugPrint(str ?? "")
网友评论