Swift NOTES
第一章. 创建第一个Swift程序
1.1 创建一个Swift程序
创建步骤
- 打开Xcode. 选择macOS的版本(而不是IOS版本)的Playground, 显示如下模版代码.
import Cocoa
var str = "Hello, playground"
- 先不理解代码的含义,观察Playground编辑器的布局
- 左上方是代码编辑区域
- 右侧是运行结果侧边栏,其会显示所有的代码变化后的结果,类似于调试状态,其会显示变量的信息即使此变量没有输出
- 下方是控制台,使用print()可以输出到控制台中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oaiv3cyc-1598882745272)(media/15893816482781.jpg)]
- 现看自动生成的模版代码
- import Cocoa:Cocoa是苹果公司为Mac OS X所创建的原生面向对象的API
- var str = “Hello, playground” : 定义变量str值为Hello, playground
1.2 拼接字符串
var str = "Hello, world"
str = str + "123"
str += "123"
print(str) // Hello, world123321
- 使用str = str + “124” 和 str += “123” 都可以实现拼接字符串的效果
1.3 输出到控制台
import Cocoa
var str = "Hello, world"
print(str)
- print() 可以输出变量的值到控制台,其会默认输出变量并且换行
1.4 常量和变量
- 常量: 不能修改的量值(使用var 声明)
- 变量: 可以变化的量值(使用let 声明)
import Cocoa
var varString = "123"
print(varString) // 123
varString = "321"
print(varString) // 321
let constString = "123"
print(constString) // 123
// change 'let' to 'var' to make it mutable
// constString = "321"
// print(constString)
1.5 类型
如何指明值的类型呢?
- var varName: [TYPE] = [Value]
import Cocoa
var varString: String = "string"
var varInt: Int = 123
- 需要注意String类型需要使用
""
包裹起来才行 - 类型转换:
var varInt: Int = "124"
ANDvar varString: String = 123
会出现错误
1.6 字符串插值
如何在一串字符中插入变量呢?
- 在
""
中使用\()
占位符来访问实例的值,将实例的值放入紫妇产中
import Cocoa
var name: String = "pig";
var varString: String = "My name is \(name)"
print(varString) // My name is pig
第二章. 基础知识
2.1 条件语句
swift 中的
if/else
语句是怎么样的?
import Cocoa
var num1: Int = 123
var num2: Int = 123
if num1 < num2 {
print("Yes")
} else if num1 == num2 {
print("No")
} else {
print("No")
}
if (num1 < num2) {
print("Yes")
} else if (num1 == num2) {
print("No")
} else {
print("No")
}
var varString1: String = "123"
var varString2: String = "124"
if varString1 != varString2 {
if varString1 < varString2 {
print("Yes")
} else {
print("No")
}
}
- 可以有括号也可以没有括号
2.2 比较运算符
符号 | 含义 |
---|---|
< | 小于 |
> | 大于 |
<= | 小于等于 |
>= | 大于等于 |
== | 等于 |
!= | 不等于 |
=== | 是否指向同一个实例 |
!== | 是否不指向同一个实例 |
- 结果都是Yes
import Cocoa
var varString1: String = "123"
var varString2: String = "123"
if varString1 == varString2 {
print("Yes")
} else {
print("No")
}
varString1 = "abc"
varString2 = "
"
if varString1 > varString2 {
print("Yes")
} else {
print("No")
}
var num1: Int = 1
var num2: Int = 2
if num1 < num2 {
print("Yes")
} else {
print("No")
}
num1 = 11
num2 = 11
if num1 <= num2 {
print("Yes")
} else {
print("No")
}
num1 = 11
num2 = 11
if num1 >= num2 {
print("Yes")
} else {
print("No")
}
num1 = 12
num2 = 13
if num1 != num2 {
print("Yes")
} else {
print("No")
}
2.3 数
-
Int的类别:
- Int8
- UInt8
- Int16
- UInt16
- Int32
- UInt32
- Int64
- UInt64
- Int8
-
使用U开头的都是无符号类型,只能表示正数
-
每个类型都有其范围,一旦超过范围,或者使用无符号类型来表示负数都会报错
2.3.1 整数加法
import Cocoa
var num: Int = 1
var num1: Int = 2
print(num + num1) // 3
2.3.2 整数减法
import Cocoa
var num: Int = 1
var num1: Int = 2
print(num - num1) // -1
2.3.3 整数除法
import Cocoa
var num: Int = 1
var num1: Int = 2
print(num / num1) // 0
print(num1 / num) // 2
2.3.4 整数乘法
import Cocoa
var num: Int = 1
var num1: Int = 2
print(num * num1) // 2
2.3.5 整数余数
- 正数余负数等价于正数余正数
- 负数余正数等价于正数余正数的结果添负号
import Cocoa
print(-9 % 4) // -1
print(9 % 4) // 1
print(9 % -4) // 1
print(-9 % -4) // -1
2.4 溢出操作符
- 相比较与其他语言Swift对于数的溢出是默认回报错的,例如Int8的数据类型最大为127,当数超过127就会报错,而不是像其他语言一样127 + 1 = -128(默认情况下)
- 但是使用
&+
操作符就可以达成一样的效果
- 但是使用
2.5 转换类型
- Int 类型默认是Int64
- 明确的数据类型之间的运算只能使用同类型的
- 没有明确类型的运算可以进行
- 可以使用Int16(b)进行对b进行Int16类型的转换
import Cocoa
print(Int.max) // 9223372036854775807
var num: Int8 = 10
var num2: Int8 = 11
print(num + num2) // 21
var num3: Int16 = 12
print(num3 + 13) // 25
print(num3 + Int16(num2)) // 23
2.6 浮点数
- 浮点数是不精确的,不要使用浮点数进行比较
import Cocoa
var num: Double = 1.1
var num1: Float = 1.1
2.7 switch语句
- switch分支可以有多个值
- switch分支执行完会默认跳出switch,而不是继续执行下一个分支
- fallthrough与其他语言的break相反,其作用是让分支执行完可以继续执行下一个分支
import Cocoa
var state: Int = 400
switch (state) {
case 400, 401:
print("400")
fallthrough
case 404:
print("404")
case 500:
print("500")
default:
print("error")
}
// 400
// 404
2.7.1 区间
switch分支可以使用多个值,那么如果要使用100-200之间的值,将要写100个值吗
- 使用
...
来表示区间(闭区间)
import Cocoa
var state: Int = 450
switch (state) {
case 400...500:
print(state)
default:
print("error")
}
2.7.2 值绑定
- 需要知道的是switch语句是从上到下进行匹配
- default的代替做法,使用
case var varState:
其会将传入的状态值赋值给varState,和default一样它会匹配所有 - 它们的区别在于default只能在末尾使用,而
case var varState:
可以在任意地方使用,虽然它们要是做的都是default要做的事那么没区别,但要是想要在此之前进行处理什么的,那么就会有帮助
2.8 where 子句
- 使用值绑定的时候,还可以对变量进行更精一步使用where语句筛选
- 需要注意的是,switch语句有个前提条件是,一定要全覆盖,简单的说就是一个switch语句必然要有一个分支被执行,当我们使用where子句的时候就有可能会有的地方没有执行到就无法成功
import Cocoa
var state: Int = 100
switch (state) {
case 401...500:
print(state)
case var unknow where (state <= 100):
print(state)
default:
print("error")
}
// 100
2.9 创建元组
- 元组为存储数的组合?
- 元组中的数据可以使用下标来表示
- 元组中的数据可以使用名称来命名和访问
import Cocoa
var error = (1, 2)
print(error.0)
print(error.1)
var errorString = (errorCode: 404, errorMsg: "not found")
print(errorString.errorCode)
print(errorString.errorMsg)
2.9.1 使用元组来配合使用switch
- 例如我们将要匹配多个错误状态,而且要根据不同的填写状态来区分情况
- 还可以使用
(_, _)
来表示匹配元组中任意值, 同样也适用于单个的参数
import Cocoa
var errorFirst = (FirstCode: 20, SecondCode: 20)
var errorSecond = (FirstCode: 200, SecondCode: 404)
var errorNot = (FirstCode: 200, SecondCode: 200)
var errorBoth = (FirstCode: 404, SecondCode: 404)
switch errorFirst {
case (404, 404):
print("both")
case (200, 404):
print("Second error")
case (404, 200):
print("First error")
case (200, 200):
print("Not")
case let errorlist where errorlist.FirstCode < 100 && errorlist.SecondCode < 100:
print("var")
case (_, 404):
print("Second error")
case (404, _):
print("First error")
default:
print("other error")
}
2.10 if-case 语句
- 相对于switch而言此语句不需要default, 适用于多条件的单个匹配,其实和if语句类似
- num 在100到200区间,并且num小于150
import Cocoa
var num: Int = 100
if case 100...200 = num, num < 150 {
print("Yes")
}
// Yes
2.11 循环
- 使用
_
来代替i
import Cocoa
for i in 1...5 {
print(i)
}
for _ in 1...5 {
print("1")
}
- 配合where使用
import Cocoa
for i in 1...5 where i % 2 == 0 {
print(i)
}
- 需要注意的是我们在for中使用了变量i,但是没有指定i是Int类型,这里其自动的推断出了类型,完整的语句应该是这样:
for i: Int in 1...5 {}
2.12 while 循环
import Cocoa
var i: Int = 0
while i < 6 {
i += 1
}
2.13 repeat-while 循环
- 类似于
do while
语句
import Cocoa
var i: Int = 0
repeat {
print(i)
i += 1
} while i < 10
2.14 continue, break
- …
2.15 字符串
2.15.1 获取指定位置字符
- swift中的字符串无法直接通过下标直接访问到,其使用Index的类型作为索引
import Cocoa
var varString = "12345"
let start = varString.startIndex
let end = varString.index(start, offsetBy: 4)
let chara = varString[end]
print(chara)
// 5
2.15.2 获取字符串区间
import Cocoa
var varString = "12345"
let start = varString.startIndex
let end = varString.index(start, offsetBy: 2)
let range = start...end
let chara = varString[range]
print(chara)
// 123
- 可以使用startIndex和endIndex来判断字符串是不是空的
import Cocoa
let empty = ""
let start = empty.startIndex
let end = empty.endIndex
if start == end {
print("empty")
} else {
print("no")
}
2.16 可空类型
- 可空类型用于指定某个实例可能没有值
- 如果一个可空类型没有值,那么其输出则为nil
- 在类型的后面加上一个
?
表示其实可空类型 - 需要注意的是可空类型确实是个类型,而不只是一个可空的字符串而已(如果修饰String)
- 使用
!
来强制的打开可空类型中的值,不使用叹号则是将这个对象赋值给别人
import Cocoa
var varString: String?
varString = "123"
var tmpType = varString
var tmpValue = varString!
print(tmpType) // Optional("123")
print(tmpValue)// "123"
2.16.1 可空实例绑定
- 可以使用一下语法,就可以将可空类型的中的值复制到变量中,而不需要使用!来拿值, 当为空的时候if语句会判断为false状态
import Cocoa
var varString: String?
varString = "404"
if let tmp = varString {
print(tmp)
}
2.16.2 隐式展开可空类型
- 隐式的区别在于,其赋值无需使用!进行
- 隐式类型的初始化和赋值给别人等都需要显式的声明为隐式类型才行
import Cocoa
var varString: String! = "404"
var tmpString: String = varString // 无需使用!
var tmpString1 = varString // temString1为普通可空类型
2.16.3 可空链式调用
- 用于对可空类型进行是否包含值判断
import Cocoa
var key1: String? = "123"
var word: String? = "\(key1!)"
var pp = word?.uppercased()
print(pp!)
2.16.4 原地修改可空类型
- 使用append()函数对可空类型进行数据的新增
import Cocoa
var varString: String?
varString = "name"
varString?.append(" is pig") // varString 不是nil就会添加
2.16.5 nil合并运算符
- 使用
?? ""
语句,其所用类似于可空类型的三目运算符,当可空类型是nil的时候则返回默认值,否则就返回可空类型内的值
import Cocoa
var varString: String?
varString = "1"
var tmp = varString ?? "no error"
print(tmp) // 1
第三章. 容器和函数
3.1 创建数组
- 创建数组有二种方式
- 数组和元组的区别之一在于元组能放多种类型的数据,但数据只能放同一类型的数据
import Cocoa
var stringArray: Array<String> = ["1", "2", "3"]
var stringArray1: [String] = ["1", "2", "3"]
var stringArray2 = ["1", "2", "3"] // 使用自动识别类型
3.1.1 添加数据
import Cocoa
var stringVar: Array<String> = ["1", "2", "3"]
stringVar.append("4")
3.1.2 删除数据
- 删除数据后,删除的位置将会被后面的数据填上
import Cocoa
var stringVar: Array<String> = ["1", "2", "3"]
stringVar.remove(at: 2) // 删除索引为2的元素
3.1.3 获取元素的个数
import Cocoa
var stringVar: Array<String> = ["1", "2", "3"]
print(stringVar.count) // 3
3.1.4 输出区间
import Cocoa
var stringVar: Array<String> = ["1", "2", "3"]
print(stringVar[0...1]) // ["1", "2"]
3.1.5 添加数组
import Cocoa
var stringVar: Array<String> = ["1", "2", "3"]
var StringVar1: Array<String> = ["4", "5", "6"]
stringVar += StringVar1
print(stringVar)
// ["1", "2", "3", "4", "5", "6"]
3.1.6 插入新目标
import Cocoa
var stringVar: Array<String> = ["1", "2", "3"]
stringVar.insert("4", at: 2)
print(stringVar)
// ["1", "2", "4", "3"]
3.1.7 数组相等
- 数组是有序的,所以顺序不同也不相等
import Cocoa
var stringVar: Array<String> = ["1", "2", "3"]
var stringVar1: Array<String> = ["1", "2", "3"]
if stringVar == stringVar1 {
print("Yes")
} else {
print("No")
}
3.1.8 不可变数组
import Cocoa
import Cocoa
let stringVar: Array<String> = ["1", "2", "3"]-
3.2 字典
3.2.1 创建字典
- 创建字典的四种方式
import Cocoa
var dict: Dictionary<String, String>
var dict1 = Dictionary<String, String>()
var dict2: [String:String] = [:]
var dict3 = [String:String]()
3.2.2 填充字典
- 利用类型推断初始化字典
import Cocoa
var dict = ["Name":"tom", "age":"12"]
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
3.2.3 访问和修改字典
- 使用key来获取字典中的值,其返回的是一个对应类型的可空类型,而不是指定的value的类型
import Cocoa
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
let name = dict1["Name"]
print(dict1.count) // 2
print(name) // Optional("321")
- 修改值
import Cocoa
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
dict1["Name"] = "111"
print(dict1["Name"]) // Optional("111")
- 更新值
import Cocoa
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
dict1.updateValue("111", forKey: "Name")
print(dict1["Name"]) // Optional("111")
3.2.4 增加和删除值
- 增加
import Cocoa
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
dict1["sex"] = "1"
print(dict1) // ["Name": "321", "age": "11", "sex": "1"]
- 删除,并返回其Value(可空类型)
import Cocoa
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
let value = dict1.removeValue(forKey: "Name")
print(value) // Optional("321")
print(dict1) //["age": "11"]
- 将一个键的值设为nil等同于删除,但是不会返回value
import Cocoa
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
dict1["Name"] = nil
print(dict1) // ["age": "11"]
3.2.5 循环
- 同时访问键和值
import Cocoa
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
for (key, value) in dict1 {
print("key:" + key + " value: " + value)
}
// key:Name value: 321
// key:age value: 11
- 只访问键
import Cocoa
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
for key in dict1.keys {
print("key:" + key)
}
// key:Name
// key:age
- 只访问值
import Cocoa
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
for value in dict1.values {
print("value:" + value)
}
// value:321
// value:11
3.2.6 把字典转换为数组
import Cocoa
var dict1: Dictionary<String, String> = ["Name":"321", "age":"11"]
var list: Array<String> = Array(dict1.keys)
print(list) // ["Name", "age"]
3.3 集合
- 无序, 存储的是单个元素不是键值对,唯一
import Cocoa
// create set
var myset = Set<String>()
// insert setMember
myset.insert("fd")
myset.insert("fd1")
print(myset)
// iterator set
for i in myset {
print(i)
}
// create set by Array
var myset1: Set = ["1", "1"]
// only one var, because set can save
for i in myset1 {
print(i)
}
3.3.1 判断是否包含元素
import Cocoa
var myset: Set = ["1", "2"]
// Yes
print(myset.contains("1") ? "Yes" : "No")
3.3.2 并集
- 将二个set的元素合并,由于set的特性合并后的set不会有重复的元素
import Cocoa
var myset: Set = ["1", "2"]
var otherset = Set(["1", "2", "3"])
print(myset.union(otherset))
// ["2", "1", "3"]
3.3.3 交集
- intersection返回二个集合共有的元素
import Cocoa
var myset: Set = ["1", "2"]
var otherset = Set(["1", "2", "3"])
print(myset.intersection(otherset))
3.3.4 判断是否不相交
- 使用isDisjoint来判断二个集合是否有交集
import Cocoa
var myset: Set = ["1", "2"]
var otherset = Set(["1", "2", "3"])
let flg = myset.isDisjoint(with: otherset)
print(flg)
// false
3.4 函数
3.4.1 定义函数
- 传递参数的时候需要指定参数的名字
- 即使指定了参数的名字,也不能换位置传递参数
- 传递进去的参数不能修改,默认是let定义的
import Cocoa
func printTest(name: String, age: Int) {
print("\(name) and \(age)")
}
printTest(name: "ds", age: 1)
3.4.2 使用外部参数名
- 外部参数名用于调用函数者使用,便于理解,函数内部还是使用其内部参数名
- 简而言之就是取一个别名供调用者更好的使用
- 外部参数名取名为
_
就可以使调用函数的时候无需传入参数
import Cocoa
func printTest(say name: String, age: Int) {
print("\(name) and \(age)")
}
printTest(say : "dsas", age: 1)
// dsas and 1
3.4.3 变长参数
import Cocoa
func printTest(to name: String...) {
for i in name {
print("\(i)")
}
}
printTest(to: "1", "2", "3", "4")
3.4.4 默认参数值
import Cocoa
func printTest(name: String, end: String = ".") {
print("my name is \(name) \(end)")
}
printTest(name: "ccc")
printTest(name: "ccc", end: "!")
// my name is ccc .
// my name is ccc !
3.4.5 in-out参数
- 当函数需要修改实参时,就需要用到此参数
- in-out参数不能有默认值
- 变长参数不能标记为inout
- inout标识在类型之前, 传入的参数需要加入&
import Cocoa
var count: Int = 0
func printTest(count: inout Int) {
count += 1
}
printTest(count: &count)
print(count)
3.4.6 函数返回值
import Cocoa
var count: Int = 0
func printTest() -> String {
return "1"
}
var back = printTest()
print(back)
3.4.7 嵌套函数和作用域
import Cocoa
func cal(case1: String, num: Double, num2: Double) -> Double {
func add() -> Double {
return num + num2
}
var ans: Double
switch case1 {
case "1":
ans = add()
default:
ans = 0
}
return ans
}
var ans: Double = cal(case1: "1", num: 1.2, num2: 1.3)
print(ans)
3.4.8 返回可空类型
import Cocoa
func backMiddleName(name: (String, String?, String)) -> String? {
return name.1
}
var middleName = backMiddleName(name: ("com", nil, "chenx"))
if var name = middleName {
print(middleName!)
}
// print(middleName)
3.4.9 提前退出函数
- guard语句用于判定表达式是不是true然后执行操作,和if/else类似
- guard 不能配合使用代码块,必须要有退出
import Cocoa
var varString: String? = "123"
func test() {
guard var temp = varString else {
print("No")
return
}
}
3.4.10 函数类型
- 和String等类型一样,一个定义的函数也是有其类型的
- 例如无参数无返回值的类型就是
() -> ()
- 同样可以使用变量来接收函数
import Cocoa
func test() {
print("Yes")
}
var function: () -> () = test
function()
3.4.11 Void
- 其实没有返回值也是有返回值的,那就是Void,只是没有显示表示
- Void 是 () 的别名, ()表示空元组
import Cocoa
func test() {
}
func test1() -> Void {
}
func test2() -> () {
}
3.5 闭包
- 所有的函数都是闭包
import Cocoa
var list = [1, 2, 3, 4, 5, 8, 6]
func sortCompare(_ i: Int, _ j: Int) -> Bool {
return i > j
}
var list1 = list.sorted(by: sortCompare)
print(list1)
3.5.1 闭包表达式语法
- 将上面的sortCompare函数修改为闭包表达式以达到更简洁的语法
import Cocoa
var list = [1, 2, 3, 4, 5, 8, 6]
var list1 = list.sorted(by: {(_ i: Int, _ j: Int) -> Bool in
return i < j
})
print(list1)
- 使用更简洁的语法
import Cocoa
var list = [1, 2, 3, 4, 5, 8, 6]
var list1 = list.sorted(by: {
i, j in i < j
})
print(list1)
- 使用更为简洁的语法
import Cocoa
var list = [1, 2, 3, 4, 5, 8, 6]
var list1 = list.sorted(by: {
$0 < $1
})
print(list1)
- 使用尾部闭包法再简洁一点
import Cocoa
var list = [1, 2, 3, 4, 5, 8, 6]
func compare(_ i: Int, _ j: Int) -> Bool {
return i < j
}
func test(mothed: (Int, Int) -> Bool) -> Bool {
var i = -1
var j = 2
return mothed(i, j)
}
print(test{ $0 < $1})
3.5.2 函数作为返回值
import Cocoa
func backFunc() -> ((Int)->Bool) {
func isTrue(num: Int) -> Bool {
return num == 1
}
return isTrue
}
var isFunc = backFunc()
print(isFunc(2))
3.5.3 函数作为参数
import Cocoa
var list = [1, 2, 3, 4, 5, 8, 6]
func compare(_ i: Int, _ j: Int) -> Bool {
return i < j
}
func test(mothed: (Int, Int) -> Bool) -> Bool {
var i = -1
var j = 2
return mothed(i, j)
}
print(test{ $0 < $1})
3.5.3 闭包能捕获变量
- 调用一个A函数的同时传递一个参数X进去,返回一个函数B,此B函数中对参数X进行累加,并在其中反映到参数X上,参数X的值会不断的增加
import Cocoa
func main(num: Int) -> (Int) -> Int {
var count = num
func grew(add: Int) -> Int {
count += add
return count
}
return grew
}
var count = 0
var grew = main(num: count)
grew(100)
grew(200)
count = grew(100)
print(count)
// 400
3.5.4 闭包是引用类型
- 返回的函数其实是一个引用,将其赋值给别的对象,它们操作的是用一个作用域
- 但是如果重新调用函数将会获得一个新的函数对象,作用域将是不同的
import Cocoa
func main(num: Int) -> (Int) -> Int {
var count = num
func grew(add: Int) -> Int {
count += add
return count
}
return grew
}
var count = 0
var grew = main(num: count)
grew(100)
grew(200)
count = grew(100)
var grew1 = grew
count = grew1(200)
print(count)
3.5.5 函数式编程
- map(), filter(), reduce() 函数的使用
map(_:)
会将里面的函数应用到每一个值上filter(_:)
会使用函数过滤reduce(_:_:)
传入二个参数,一个是默认初始化的值,另一个是函数,参数一是上一次处理结果的值,参数二是当前的参数值
import Cocoa
func mapFunc(num: Int) -> Int {
return num + 1
}
var list = [1, 2, 3, 4]
var maplist = list
maplist = maplist.map(mapFunc)
print(maplist)
func filterFunc(num: Int) -> Bool {
return num > 3
}
var filterlist = list
filterlist = filterlist.filter(filterFunc)
print(filterlist)
func reduceFunc(num1: Int, num2: Int) -> Int{
return num1 + num2
}
var reducelist = list
var pp = reducelist.reduce(0, reduceFunc)
print(pp)
// [2, 3, 4, 5]
// [4]
// 10
第四章. 枚举、结构体、类
4.1 基本枚举
4.1.1 定义枚举
import Cocoa
enum lifeType {
case eat
case sleep
case washing
}
4.1.2 创建实例
- 可以明确类型,也可以使用类型推断
- 当创建完enum实例后,要更改值可以简化
import Cocoa
enum lifeType {
case eat
case sleep
case washing
}
var mylift: lifeType = lifeType.eat
var mylift1 = lifeType.eat
mylift = .sleep
4.1.3 switch——enum
- switch默认需要全覆盖所有的可能性,因此需要加入default来保证,但使用enum就无需使用default,只要你将所有的enum case都罗列出来即可
import Cocoa
enum lifeType {
case eat
case sleep
case washing
}
var mylift: lifeType = lifeType.eat
switch mylift {
case .eat:
print("1")
case .sleep:
print("2")
case .washing:
print("3")
}
4.1.4 原始值枚举
- swift的枚举默认是没有底层的值的
import Cocoa
enum lifeType: Int {
case eat
case sleep
case washing
}
print(lifeType.sleep.rawValue)
// 1
- 指定原始值
import Cocoa
enum lifeType: Int {
case eat = 1
case sleep
case washing
}
print(lifeType.sleep.rawValue)
// 2
- 将原始值转化为枚举类型
import Cocoa
enum lifeType: Int {
case eat = 1
case sleep
case washing
}
var liftCode = 3
var code2Type = lifeType(rawValue: liftCode)
if code2Type == lifeType.washing {
print("Yes")
}
4.1.5 方法
- 在enum中定义方法
import Cocoa
enum lifeType: Int {
case eat = 1
case sleep
case washing
func getTime() -> Int {
switch self {
case .eat:
return 12
case .sleep:
return 10
case .washing:
return 8
}
}
}
var eatSchame = lifeType.eat
var eatTime = eatSchame.getTime()
print(eatTime)
- 方法中不能修改self的值,如果需要修改需要在方法前加入
mutating
修饰
4.1.6 关联值
- 可以传入值作为枚举case的属性,并可用于方法中用于计算等处理
- 有点类似于构造函数的意思,并不需要每一个case都有关联值
import Cocoa
enum lifeType {
case eat(Time: String, Food: String)
case sleep
case washing
func printEat() {
switch self {
case var .eat(Time: time, Food: food):
print(time)
default:
print("fds")
}
}
}
var eat = lifeType.eat(Time: "10:00", Food: "eggs")
eat.printEat()
4.2 结构体
- 结构体要修改其属性就要在方法前加入mutating
- 是值类型
import Foundation
struct Town {
// attribute
var population = 5_422
var numberOfStoplights = 4
// static function list
func printDescription() {
print("This is myTown, then people has \(population) and lights has \(numberOfStoplights)")
}
// mutating function
mutating func changepopulation(by amount: Int) {
population += amount
}
}
4.3 类
4.3.1 创建类
- 是引用类型
- 类和结构体很大的一个区别在于结构体的传递只会是副本,改变不会对其有影响,类是引用类型,传递的是源对象的引用,会随之改变
import Foundation
struct Town {
// attribute
var population = 5_422
var numberOfStoplights = 4
// static function list
func printDescription() {
print("This is myTown, then people has \(population) and lights has \(numberOfStoplights)")
}
// mutating function
mutating func changepopulation(by amount: Int) {
population += amount
}
}
4.3.2 继承
- 区别于结构体的部分之一是继承,结构体没有
import Foundation
class Zombie: Monster {
var walksWithLimp = true
override func terrorizeTown() {
town?.changepopulation(by: -10)
super.terrorizeTown()
}
}
4.3.3 类型方法
- 以上我们使用的都是实例方法,也就是必须要创建其实例才能调用的方法,类型方法就是无需创建他就可以使用的方法,也就是静态方法,类型方法可以直接使用类型调用
- 使用class修饰func表示类型方法
- 使用final class 修饰或者static修饰表示无法被override的方法
import Foundation
class Zombie: Monster {
var walksWithLimp = true
override func terrorizeTown() {
town?.changepopulation(by: -10)
super.terrorizeTown()
}
final class func makeNoise() -> String {
return "Brains..."
}
}
4.4 属性
4.4.1 嵌套类型
- 可以在类型中间在嵌套一个类型
struct Person {
var name: String = "1"
var age: Int = 1
var sex: Sex = Sex.boy
enum Sex {
case boy
case girl
}
}
4.4.2 惰性存储属性
- 使用lazy修饰的属性不会在初始化就加载,而是会在第一次调用后加载,并且只会加载一次
struct Person {
var name: String = "1"
var age: Int = 1
var sex: Sex = {switch age {
case 0...10:
return Sex.boy
case 11...40:
return Sex.girl
default:
return Sex.boy
}}()
enum Sex {
case boy
case girl
}
}
4.4.3 计算属性
- 计算属性类似于java的get方法,读取属性时可以调用自定义的get方法返回
struct Person {
var name: String = "1"
var age: Int = 11
var sex: Sex {
get {
switch age {
case 1...10:
return Sex.boy
case 11...20:
return Sex.girl
default:
return Sex.boy
}
}
}
enum Sex {
case boy
case girl
}
}
4.4.4 写入属性
struct Person {
var name: String = "1"
var age: Int = 11
var sex: Int {
get {
switch age {
case 1...10:
return 1
case 11...20:
return 2
default:
return 3
}
}
set(value) {
self.age = value
}
}
enum Sex {
case boy
case girl
}
}
var p = Person()
p.sex = 11
print(p.sex)
4.4.5 属性观察者
- 提供了二个方法可以对属性的变化进行监测
- didSet: 变化的时候会调用,可以访问未改变的值
- willSet: 变化的时候会调用,可以访问改变后的值
var tmp: String = "111" {
willSet(newValue) {
print("\(oldTmp)")
}
didSet(oldValue) {
print("\(oldValue) to \(tmp)")
}
}
tmp = "112"
print(tmp)
// 112
// 111 to 112
4.4.6 类型属性
- 类型属性就是无需实例化就可以访问的属性
- 类型属性必须有默认值
struct test {
static var name: String = "gfsdg"
var age: String = "11"
}
print(test.name)
- 计算类型属性, 使用class修饰变量,和类型方法很像,只是一个用func一个用var,(注意此属性只能在class中使用)
- 计算类型属性可以被子类覆盖
class var name: String {
return "xxx"
}
4.4.7 访问控制
- 通过对类型进行private等修饰来达到模块和作用域等的访问控制
- private 可以被同一作用域内的属性和方法访问
- 默认的可见度是internal
- 还可以分别控制属性的读取和写入方法,默认情况下读取和写入的可见度是一样的
class Person {
internal private(set) var age: Int = 1
private(set) var name: String = "ccc"
}
4.5 初始化
4.5.1 默认初始化方法
- 初始化可以传入指定的值以赋给属性,而无需手动一个个赋值
- 结构体有一个默认的初始化方法,无需定义, 且外部变量就是其属性名称
- 定义一个结构体必须每个非空属性都默认初始化或者有初始化函数可以为每个属性进行初始化,之所以能定义没有默认值的结构体是应为其默认给了一个每个属性都包含的初始化函数
import Foundation
struct Person {
var name: String
var age: String
var sex: String
}
var person = Person(name: "cc", age: "11", sex: "1")
print("\(person.name) \(person.age) \(person.sex)")
4.5.2 自定义初始化方法
- 一旦使用自定义的初始化方式,就不会有默认的初始化方法了
import Foundation
struct Person {
var name: String
var age: String
var sex: String
init(name: String, age: String) {
self.init(name: name, age: age, sex: "N/A")
}
init(name: String, age: String, sex: String) {
self.name = name
self.age = age
self.sex = sex
}
}
var person = Person(name: "cc", age: "11")
print("\(person.name) \(person.age) \(person.sex)")
4.5.3 类初始化
- 子类会继承父类的初始化方法,也就是说继承了之后子类就没有默认的初始化方法了,这将导致子类如果有多余的属性,那么其会因为没有初始化属性而报错,需要添加自己的初始化方法
- 类没有一个可以为属性赋值的默认初始化方法,只有一个没有任何参数的初始化方法
import Foundation
class humen {
var body: String
var bones: String
init(body: String, bones: String) {
self.body = body
self.bones = bones
}
}
class Person: humen {
var name: String
init(body: String, bones: String, name: String) {
self.name = name
super.init(body: body, bones: bones)
}
}
var person = Person(body: "1", bones: "12", name: "fds")
print(person.name)
- 使用关键字required 来修饰init表示,其子类必须要实现此init
4.5.4 反初始化
- 反初始化就是将类的实例移除内存的过程
- 只有引用类型可以反初始化,值类型不行
- 一个类只有一个反初始化方法
- 没有参数
- 当类的实例设为nil后就会触发deinit
import Foundation
class Person {
var body: String
var bones: String
init(body: String, bones: String) {
self.body = body
self.bones = bones
}
deinit {
print("out")
}
}
var person: Person? = Person(body: "1", bones: "12")
person = nil
// out
4.6 值类型和引用类型
4.6.1 值类型和引用类型
- Swift 的基本类型(Array, Dictionary, Int, String)等类型都是用结构体实现的,它们在传递的过程中都是以赋值的方式
- 对于引用类型来说,它们的实例都指向内存中的同一个实例
4.6.2 值类型常量和引用类型常量
- 不能修改声明为常量的值类型实例的属性
- 可以修改声明为常量的引用类型的实例的属性
- 因为后者修改的是指向的引用的属性而不是常量,常量指向的实例位置还是不变的
4.6.3 浅复制和深复制
- 浅复制:复制不会创建实例的副本,而是复制实例的引用
- 深复制:复制会创建实例的副本
4.6.4 相等与等一
- 相等:指的是二个实例可见特征一样
- 等一:指的是二个引用对象指向同一个实例
第五章. 高级编程
5.1 协议
- 类似于接口,继承的协议,需要子去实现
- 一个类型可以符合多个协议
- 类的协议有一个要求就是,如果此类有父类的话,那么需要先继承父类,再写协议
import Foundation
import Cocoa
protocol TableProtocol {
var numberOfRows: Int { get }
var numberOfColums: Int { get }
func label(forColumn colunm: Int) -> String
func itemFor(row: Int, column: Int) -> String
}
struct Person {
var name: String
var age: String
var sex: String
init(_ name: String, _ age: String, _ sex: String) {
self.name = name
self.age = age
self.sex = sex
}
}
struct Department: TableProtocol {
let name: String
var people = [Person]()
init(name: String, people: [Person]) {
self.name = name
self.people = people
}
var numberOfRows: Int {
get {
return self.people.count
}
}
var numberOfColums: Int {
get {
return 2
}
}
func label(forColumn colunm: Int) -> String {
switch colunm {
case 0:
return "Name"
case 1:
return "Age"
case 2:
return "Sex"
default:
return "Error Message"
}
}
func itemFor(row: Int, column: Int) -> String {
let person = people[row]
switch column {
case 0:
return person.name
case 1:
return person.age
case 2:
return person.sex
default:
return "fuck"
}
}
}
func printTable(_ data: TableProtocol) {
var title = "|"
for i in 0...data.numberOfColums {
title += " \(data.label(forColumn: i)) |"
}
print(title)
for row in 0...(data.numberOfRows - 1) {
var ans = "|"
for column in 0...data.numberOfColums {
ans += " \(data.itemFor(row: row, column: column)) |"
}
print(ans)
}
}
var data: Department = Department(name: "11", people: [Person("1", "2", "3"),Person("2", "3", "33")])
printTable(data)
5.1.1 协议组合
- 编写了一个方法,此方法接收一个类型,当你创建了类型,并且定制了一个协议,这就导致此方法接受此类型或者此协议,但是你想要它们二者都符合才能被接收
func printTable(_ data: TableProtocol & CustomStringConvertible) {
var title = "|"
for i in 0...data.numberOfColums {
title += " \(data.label(forColumn: i)) |"
}
print(title)
for row in 0...(data.numberOfRows - 1) {
var ans = "|"
for column in 0...data.numberOfColums {
ans += " \(data.itemFor(row: row, column: column)) |"
}
print(ans)
}
}
5.2 错误
5.2.1 定义错误
enum enumError: Error {
case E1(Int)
case E2
}
5.2.2 捕捉错误
func test(age: Int) throws -> Int {
if age < 10 {
return age
} else {
throw enumError.E1(1)
}
}
do {
var age = try test(age: 11)
} catch enumError.E1(let age) {
print("\(age)")
}func test(age: Int) throws -> Int {
if age < 10 {
return age
} else {
throw enumError.E1(1)
}
}
do {
var age = try test(age: 11)
} catch enumError.E1(let age) {
print("\(age)")
}
5.2.3 处理错误
- 使用try 标记将会发生错误的语句, 需要使用do catch语句包裹或在throws的函数内
- try!无需使用do catch捕捉,当错误发生时会被触发
- try?无需使用do catch捕捉,当错误发生时不会被触发
5.3 扩展
- 使用typealias 可以设置类型的别名
- 使用extension来扩展已有类型,使其有别的功能
- extension也可以使用协议
- extension也可定义初始化函数
- extension还可嵌套类型
import Cocoa
extension Int {
func isBig() -> Bool {
if self > 100 {
return true
} else {
return false
}
}
}
var age: Int = 20
print(age.isBig())
// false
5.4 泛型
import Cocoa
struct Stack<T> {
var items = [T]()
mutating func push(value: T) {
items.append(value)
}
mutating func pop() -> T? {
if !items.isEmpty {
return items.removeLast()
} else {
return nil
}
}
}
var stack = Stack<Int>()
stack.push(value: 1)
stack.push(value: 2)
stack.pop()
print(stack)
// Stack<Int>(items: [1])
- 使用类型约束以便检查相关性
import Cocoa
struct Stack<T: Equatable> {
var items = [T]()
mutating func push(value: T) {
items.append(value)
}
mutating func pop() -> T? {
if !items.isEmpty {
return items.removeLast()
} else {
return nil
}
}
}
var stack = Stack<String>()
stack.push(value: "1")
stack.push(value: "2")
stack.pop()
print(stack)
// Stack<String>(items: ["1"])
- 协议不可以使用泛型,但是可以使用关联类型进行约束
第六章. UI控件
6.1 视图
- 创建视图
// 创建视图,定制视图的位置以及视图的宽度和长度
let myView = UIView(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
// 设置视图的背景色
myView.backgroundColor = UIColor.black
// 将视图添加到父容器视图中
self.view.addSubview(myView)
- 使用视图的方法
- UIView.animate(withDuration: TimeInterval, animations: () -> Void) 可以设置调用指定的方法执行动画的时间,类似于渐变的意思
6.2 Label
// 创建label的位置和大小
let label1 = UILabel(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
// 视图的背景色
label1.backgroundColor = UIColor.yellow
// label的字体颜色
label1.textColor = UIColor.red
// label的文字内容
label1.text = "11111"
// label的文字Align
label1.textAlignment = .center
// 添加label到view中
self.view.addSubview(label1)
6.3 Button
// 创建自定义按钮
let button = UIButton(type: .custom)
// 设置按钮位置
button.frame = CGRect(x: 10, y: 10, width: 100, height: 200)
// 设置按钮的文字内容,在普通状况下
button.setTitle("anniu", for: .normal)
// 设置按钮文字的颜色,在普通状态下
button.setTitleColor(UIColor.blue, for: .normal)
// 设置文字内容,在按住的状态下
button.setTitle("High", for: .highlighted)
// 为按钮添加事件,当在touchUpInside的状况下,调用btnClick函数
button.addTarget(self, action: #selector(btnClick), for: .touchUpInside)
view.addSubview(button)
6.4 Image
let v = UIImageView()
// 设置位置
v.frame = CGRect(x: 135, y: 100, width: 100, height: 400)
// 设置背景色
v.backgroundColor = UIColor.blue
// 创建图片
let img = UIImage.init(named: "20180612_IMG_8518")
// 使此图片设为ImageView中的图片
v.image = img
// 设置layer边缘的弧度
v.layer.cornerRadius = 40
// 设置layerz遮罩生效
v.layer.masksToBounds = true
// 保持纵横比缩放图片,使图片充满view
// v.contentMode = .scaleAspectFill
// 不保持纵横比缩放图片,使图片全部看见
// v.contentMode = .scaleToFill
// 保持纵横比缩放图片,使图片全部显示
v.contentMode = .scaleAspectFit
view.addSubview(v)
6.5 TextField
- 需要设置一个UITextFieldDelegate代理让text对触发事件作出反应
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let text = UITextField(frame: CGRect(x:100, y: 100, width: 100, height: 20))
text.delegate = self
text.text = "111"
text.borderStyle = .roundedRect
let text1 = UITextField(frame: CGRect(x:100, y: 200, width: 100, height: 20))
text1.text = "111"
text1.borderStyle = .roundedRect
text.clearsOnBeginEditing = true
view.addSubview(text)
view.addSubview(text1)
}
}
extension ViewController: UITextFieldDelegate {
// 弹出键盘
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
return true
}
// 收缩键盘
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
// 输入框结束输入后调用
func textFieldDidEndEditing(_ textField: UITextField) {
print("End")
}
// 当内容变化的时候调用
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return true
}
// 当被clearsOnBeginEditing清除的时候调用
func textFieldShouldClear(_ textField: UITextField) -> Bool {
print("pp")
return true
}
}
6.6 UIViewController切换
- 视图A切换到视图B
- animated: 是否执行动画
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let changeBtn = UIButton(type: .roundedRect)
changeBtn.frame = CGRect(x: 100, y: 100, width: 100, height: 20)
changeBtn.setTitle("switch", for: .normal)
changeBtn.layer.masksToBounds = true
changeBtn.layer.cornerRadius = 5.0
changeBtn.backgroundColor = .yellow
changeBtn.setTitleColor(.black, for: .normal)
changeBtn.addTarget(self, action: #selector(btnClick), for: .touchUpInside)
self.view.addSubview(changeBtn)
}
@objc
func btnClick() {
let b = BViewController()
self.present(b, animated: true) {
print("A -> B")
}
}
}
- 从B返回A
class BViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .orange
let label = UILabel(frame: CGRect(x:100, y: 100, width: 100, height: 100))
label.text = "B!"
view.addSubview(label)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.dismiss(animated: true) {
print("B -> A")
}
}
}
6.7 生命周期
class ViewController: UIViewController {
// 初始化界面
// override func loadView() {
// print("初始化视图")
// }
// 界面加载的时候
override func viewDidLoad() {
super.viewDidLoad()
let changeBtn = UIButton(type: .roundedRect)
changeBtn.frame = CGRect(x: 100, y: 100, width: 100, height: 20)
changeBtn.setTitle("switch", for: .normal)
changeBtn.layer.masksToBounds = true
changeBtn.layer.cornerRadius = 5.0
changeBtn.backgroundColor = .yellow
changeBtn.setTitleColor(.black, for: .normal)
changeBtn.addTarget(self, action: #selector(btnClick), for: .touchUpInside)
self.view.addSubview(changeBtn)
print("加载视图")
}
// 界面将要显示的时候
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
view.backgroundColor = .red
print("将要显示")
}
// 界面已经显示的时候
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
view.backgroundColor = .white
print("已经显示")
}
// 界面将要消失
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
print("界面将要消失")
}
// 界面已经消失
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(true)
print("界面已经消失")
}
@objc
func btnClick() {
let b = BViewController()
self.present(b, animated: true) {
print("A -> B")
}
}
}
6.8 分栏控制器
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
// 当程序启动的时候会调用此方法,把要启动的视图控制器放在此函数中
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
// 创建分栏控制器
let tab = UITabBarController()
// 创建一个视图控制器
let v1 = ViewController()
// 添加视图控制器中的tabbar名字
v1.tabBarItem.title = "1"
let v2 = twoViewController()
v2.tabBarItem.title = "2"
let v3 = threeeViewController()
v3.tabBarItem.title = "3"
// 添加视图控制器到分栏控制器中
tab.viewControllers = [v1, v2, v3]
// 设置windows的根控制器是谁
self.window?.rootViewController = tab
// 让windows可见
self.window?.makeKeyAndVisible()
return true
}
}
6.9 导航控制器
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
// 当程序启动的时候会调用此方法,把要启动的视图控制器放在此函数中
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let v = ViewController()
// 创建一个导航控制器
let uiViewController = UINavigationController(rootViewController: v)
// 让导航控制器作为根控制器
self.window?.rootViewController = uiViewController
// 让windows可见
self.window?.makeKeyAndVisible()
//window?.backgroundColor = .black
return true
}
}
- 导航控制器的切换
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .red
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let bView = twoViewController()
self.navigationController?.pushViewController(bView, animated: true)
}
}
6.10 分栏导航组合使用
- 分栏作为主控制器,每一栏由一个导航控制器管控,导航控制器管控里面的视图控制器
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
// 当程序启动的时候会调用此方法,把要启动的视图控制器放在此函数中
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let v1 = ViewController()
let nav1 = UINavigationController(rootViewController: v1)
v1.navigationItem.title = "1"
nav1.tabBarItem.title = "1"
let v2 = twoViewController()
let nav2 = UINavigationController(rootViewController: v2)
v2.navigationItem.title = "2"
nav2.tabBarItem.title = "2"
let v3 = threeeViewController()
let nav3 = UINavigationController(rootViewController: v3)
v3.navigationItem.title = "3"
nav3.tabBarItem.title = "3"
let tab = UITabBarController()
tab.viewControllers = [nav1, nav2, nav3]
self.window?.rootViewController = tab
self.window?.makeKeyAndVisible()
return true
}
}
第七章. Swift传值
7.1 正向传值
- 实现原理: 本页面初始化跳转页面,并且通过赋值来传值
7.2 反向传值
7.3 代理传值
- 通过创建代理类型,让本页面实现它,在跳转页面定义此类型的参数
7.4 闭包传值
- 与代理传值类似,不过采用的是闭包,简单的说就是通过传递函数来使跳转页面调用本视图的方法
7.5 通知传值
- 通过通知传值
第八章. Swift手势与CA框架动画
8.1 单击手势
- 为控件添加手势识别器
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = .white
for i in 0...10 {
let label = UILabel(frame: CGRect(x:10, y: i * 30, width: 100, height: 30))
label.tag = i
label.text = "this is \(i) Click"
label.textColor = .red
label.backgroundColor = .green
// 创建一个点击手势
let tap = UITapGestureRecognizer()
tap.view?.backgroundColor = .blue
// 为手势添加方法
tap.addTarget(self, action: #selector(Click(name:)))
// 为控件开启用户交互
label.isUserInteractionEnabled = true
// 为控件添加手势识别器
label.addGestureRecognizer(tap)
view.addSubview(label)
}
}
@objc
func Click(name: UITapGestureRecognizer) {
let labelTmp = view.viewWithTag(name.view!.tag) as! UILabel
print(labelTmp.text!)
}
}
8.2 滑动手势
import UIKit
class ViewController: UIViewController {
var viewStatic: UIView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = .white
let viewVar = UIView(frame: CGRect(x:100, y: 100, width: 100, height: 100))
viewVar.backgroundColor = .green
let swipe = UISwipeGestureRecognizer()
swipe.addTarget(self, action: #selector(Swipe(name:)))
// 设置滑动的方向
swipe.direction = UISwipeGestureRecognizer.Direction.left
viewVar.addGestureRecognizer(swipe)
view.addSubview(viewVar)
viewStatic = viewVar
}
@objc
func Swipe(name: UISwipeGestureRecognizer) {
var offSet: CGFloat = 0
offSet += 30
viewStatic?.frame.origin.x = (viewStatic?.frame.origin.x)! + offSet
}
}
8.3 缩放手势
import UIKit
class ViewController: UIViewController {
var viewStatic: UIView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = .white
let viewVar = UIView(frame: CGRect(x:100, y: 100, width: 100, height: 100))
viewVar.backgroundColor = .green
let img = UIImageView(image: UIImage(named: "月见 女孩子 星空 流星 餐桌 聚会 4k动漫壁纸_彼岸图网"))
img.frame = CGRect(x:10, y:10, width: 100, height: 100)
viewVar.addSubview(img)
view.addSubview(viewVar)
let pinch = UIPinchGestureRecognizer()
pinch.addTarget(self, action: #selector(Swipe(name:)))
img.isUserInteractionEnabled = true
view.addGestureRecognizer(pinch)
viewStatic = viewVar
}
@objc
func Swipe(name: UIPinchGestureRecognizer) {
let scaleVar = name.scale
let scaleOffset: CGFloat = 1.0
if scaleVar < scaleOffset {
viewStatic?.transform = CGAffineTransform(scaleX: scaleVar, y: scaleVar)
} else {
viewStatic?.transform = CGAffineTransform(scaleX: scaleOffset + scaleVar - 1, y: scaleOffset + scaleVar - 1)
}
}
}
8.4 旋转手势
import UIKit
class ViewController: UIViewController {
var viewStatic: UIView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = .white
let viewVar = UIView(frame: CGRect(x:100, y: 100, width: 100, height: 100))
viewVar.backgroundColor = .green
let img = UIImageView(image: UIImage(named: "月见 女孩子 星空 流星 餐桌 聚会 4k动漫壁纸_彼岸图网"))
img.frame = CGRect(x:10, y:10, width: 100, height: 100)
viewVar.addSubview(img)
view.addSubview(viewVar)
let rotation = UIRotationGestureRecognizer()
rotation.addTarget(self, action: #selector(Swipe(name:)))
img.isUserInteractionEnabled = true
view.addGestureRecognizer(rotation)
viewStatic = viewVar
}
@objc
func Swipe(name: UIRotationGestureRecognizer) {
viewStatic?.transform = CGAffineTransform.init(rotationAngle: name.rotation)
}
}
8.5 裁剪和阴影化
- UIImage上的图片等相当于是在layer层上绘制的,通过对layer的处理达到裁剪的目的
- 阴影的透明度不要忘记设置
import UIKit
class ViewController: UIViewController {
var viewStatic: UIView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = .white
let viewVar = UIView()
viewVar.frame = CGRect(x:30, y: 100, width: 200, height: 200)
let img = UIImageView(image: UIImage(named: "月见 女孩子 星空 流星 餐桌 聚会 4k动漫壁纸_彼岸图网"))
img.frame = viewVar.frame
//viewVar.backgroundColor = .red
// 设置UIImage的layer的边框弧度
img.layer.cornerRadius = img.frame.width / 2.0
// 设置UIImage的layer边框宽度
img.layer.borderWidth = 1
// 设置UIImage的layer的边框颜色
img.layer.borderColor = UIColor.blue.cgColor
// 设置UIImage的layer边框外的部分全部遮盖
img.layer.masksToBounds = true
// 设置viewVar的阴影,而不是设置img,因为即使设置了也会被裁减掉
viewVar.layer.shadowColor = UIColor.yellow.cgColor
// 设置阴影的偏移量
viewVar.layer.shadowOffset = CGSize(width: 0, height: 2.0)
// 设置弧度
viewVar.layer.shadowRadius = 10
// 设置透明度!!!必须设置默认是0
viewVar.layer.shadowOpacity = 1.0
viewVar.addSubview(img)
view.addSubview(viewVar)
}
}
第九章. 滚动视图与表格视图
9.1 滚动视图
class ViewController: UIViewController, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
// 创建一个滚动视图
let scroll = UIScrollView()
// 设置滚动视图的size
scroll.frame = self.view.frame
// 为滚动视图里添加4个视图
for i in 0...4 {
let v = UIView()
v.frame = CGRect(x: CGFloat(i) * view.frame.size.width, y: 0,
width: view.frame.size.width, height: view.frame.size.height)
v.backgroundColor = UIColor(red: CGFloat(Double(arc4random() % 256) / 255.0),
green: CGFloat(Double(arc4random() % 256) / 255.0),
blue: CGFloat(Double(arc4random() % 256) / 255.0),
alpha: 0.6)
scroll.addSubview(v)
}
// 设置滚动视图的滚动范围
scroll.contentSize = CGSize(width: view.frame.size.width * 4, height: view.frame.size.height)
// 设置滚动视图是否分页
scroll.isPagingEnabled = true
// 为滚动视图设置代理,以便于相关事件的操作
scroll.delegate = self
view.addSubview(scroll)
}
// 当滚动的时候触发
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("Yes")
}
}
9.2 ScrollView图片浏览
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
// 创建一个滚动视图
let scroll = UIScrollView()
// 设置滚动视图的size
scroll.frame = self.view.frame
let img = UIImageView(image: UIImage(named: "20180613_IMG_8715"))
scroll.addSubview(img)
// 设置滚动的内容为图片的大小,以观看整张图片
scroll.contentSize = img.frame.size
// 视图初始位置的设定
scroll.contentOffset = CGPoint(x: 100, y: 100)
view.addSubview(scroll)
}
}
9.3 UITableView
class ViewController: UIViewController {
static let cellID: String = "CELLID "
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
let table = UITableView(frame: view.bounds, style: .plain)
table.dataSource = self
table.delegate = self
// 注册。。。配合dequeueReusableCell(withIdentifier: ViewController.cellID, for: indexPath)使用
table.register(UITableViewCell.self, forCellReuseIdentifier: ViewController.cellID)
view.addSubview(table)
}
}
extension ViewController: UITableViewDataSource {
// 返回每组cell有多少个
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
// 返回每个cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// cell复用
let view = tableView.dequeueReusableCell(withIdentifier: ViewController.cellID, for: indexPath)
view.textLabel?.text = "fsdf" + String(indexPath.row)
view.imageView?.image = UIImage(named: "20180613_IMG_8715")
// print(view)
return view
}
// 返回有多少组cell
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
}
extension ViewController: UITableViewDelegate {
// 代理,选中之后的触发
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath)
}
}
9.4 UIcollectionView
- 流水布局
- 瀑布布局
import UIKit
class ViewController: UIViewController {
static let cellID: String = "CELLID "
override func viewDidLoad() {
super.viewDidLoad()
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 5
layout.itemSize = CGSize(width: 100, height: 200)
layout.minimumInteritemSpacing = 5
let conview = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
conview.backgroundColor = .white
conview.dataSource = self
view.addSubview(conview)
conview.register(UICollectionViewCell.self, forCellWithReuseIdentifier: ViewController.cellID)
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ViewController.cellID, for: indexPath)
cell.backgroundColor = .red
return cell
}
}
第十章. 网络请求与数据解析
10.1 NSURLSession网络请求
- 另外需要配置Info.plist中添加
App Transport Security Settings -> Allow Arbitrary Loads(Yes)
import UIKit
class ViewController: UIViewController {
static let cellID: String = "CELLID "
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "http:www.baidu.com")
let urlRequest = URLRequest(url: url!)
let session = URLSession.shared
let dataTask = session.dataTask(with: urlRequest) { (data:Data?, response:URLResponse?, error:Error?) in
print(String(data:data!, encoding: String.Encoding.utf8))
}
dataTask.resume()
}
}