swift介绍
swift是2014年推出的开发语言,中文名称为雨燕。
版本
从1.X升级到5.X。
其中1,2, 3之间的版本不兼容。
编译过程
- 导出抽象语法树
swiftc -dump-ast main.swift -o main.ast
- 生成sil代码
swiftc -emit-sil main.swift -o main.sil
- 生成llvm ir代码
swiftc -emit-ir main.swift -o main.ir
- 生成汇编可执行文件
swiftc -emit-assembly main.swift -o main
hello world
使用print进行字符串输出,其中Foundation可以不需要导入。
//import Foundation
print("Hello, World!")
变量和常量
变量使用var关键字,常量使用let关键字。 其中变量可以被多次修改,常量无法被修改。
var a = 10
a = 20
a = 30
let c = 40
//c = 50
print(a)
print(c)
var a = 10
a += 10
// 常量不要求在编译期确定值,只要求在使用之前赋值一次
let b = a
print(a)
格式化输出
print("a is \(a) c is \(c)")
playground
其中UIKit是UI控件,PlaygroundSupport则是让可以在Playground中查看到UI。
import UIKit
import PlaygroundSupport
let view = UIView()
view.frame = CGRect(x:0, y:0, width:100, height:100)
view.backgroundColor = UIColor.red
PlaygroundPage.current.liveView = view
一个playground可以新建多个page。
数据类型
- 值类型
- 枚举
- 结构体 Bool Int String Set Array Dictionay
- 引用类型
- class
整数类型Int, Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64。在32位平台Int是Int32,在64位平台Int是Int64。
// 根据数据类型,可以求最大值最小值。
print(Int.max)
print(Int.min)
// 十进制
var a = 10
// 二进制0b
var b = 0b100
// 八进制0o
var c = 0o10
// 十六进制0x
let d = 0x22
浮点数
// 默认都是double类型
var a = 10.0
// 等价于13.2 * 10的2次方 1320
var b = 13.2e2
// 等价于20.1 * 10的-2次方 0.201
var c = 20.1e-2
// 等价于0xF3 * 2的3次方 1944
var d = 0xF3p3
// 等价于0xF3 * 2的-3次方
var e = 0xF3p-3 30.375
bool类型只能是true或者false。let v = true
字符和字符串都是双引号,默认是字符串。如果要声明为字符类型,则必须强制添加类型声明。
let a = "h"
let b:Character = "h"
print(type(of: a))
print(type(of: b))
字符串
Swift中的字符串是字符组成,有些字符是由2个Unicode组成。也认为是一个字符。
import UIKit
var s1 = "\u{00E9}"
var s2 = "e\u{0301}"
// 字符数量一样多
print("\(s1) \(s1.count)")//é 1
print("\(s2) \(s2.count)")//é 1
print("\(s1.utf16.count)") //转成Unicode计数。只有1个
print("\(s2.utf16.count)") // 转成Unicode计数,有2个
print((s1 as NSString).isEqual(to: s2))//false
数组
var a = [10, 20.0, 30]
print(a)
字典
定义字典
// 自动推断类型, 只能是相同的类型,下面代码编译失败
//var dict1 = ["name":"小王", "age": 18]
var dict2 = ["name":"李白", "job":"打野"]
//print(type(of: dict1))
print(type(of: dict2))//Dictionary<String, String>
// 如果字典的类型不一致,可以手动指定类型
var dict3:[String: Any] = ["name":"小王", "age": 18]
print(type(of: dict3))//Dictionary<String, Any>
// 使用泛型指定数据类型
var dict4:Dictionary<String, String> = ["name":"鲁班七号", "JOB":"ADC"]
print(type(of: dict4))//Dictionary<String, String>
空字典
// 语法错误,无法确定类型
//var dict = [:]
//print(dict)
// 确定了数据类型,因此可以编译通过
var dict1:[Int: String] = [:]
// 使用泛型指定数据类型
var dict2:Dictionary<String, String> = [:]
// 类型+括号
var dict3 = [Int: Int]()
print(type(of: dict3)) // Dictionary<Int, Int>
字典方法
var dict1 = ["name":"小明", "addr":"china"]
// 有几个key
print(dict1.count) //2
// 是否是空的
print(dict1.isEmpty) //false
// 取值返回的option类型,返回对应的值或者nil
print(dict1["age"]) // nil
print(dict1["name"]) //Optional("小明")
// 对于确定有值,又不想被Optional包装,则可以使用!标识强制解包。如果没有值,强制解包会报错
print(dict1["name"]!) //小明
var dict2 = ["addr":"china", "name":"小明"]
// 判断2个字典是否相等
print(dict1 == dict2) // true
字典的遍历
var dict = ["name":"小明", "addr":"China"]
for v in dict{
print(v)
}
/*
(key: "addr", value: "China")
(key: "name", value: "小明")
*/
for v in dict{
print("key is \(v.key) value is \(v.value)")
}
/*
key is addr value is China
key is name value is 小明
*/
for (k, v) in dict {
print("key is \(k) value is \(v)")
}
/*
key is addr value is China
key is name value is 小明
*/
字典的修改
var user = ["name":"age"]
print(user)//["name": "age"]
// 如果对应的key不存在,则新增一个键值对
user["addr"] = "china"
print(user)//["addr": "china", "name": "age"]
// 如果对应的key存在,则修改一个键值对
user["addr"] = "Beijing"
print(user)//["addr": "Beijing", "name": "age"]
// 设置对应的key的值为nil,则删除对应的键值对
user["addr"] = nil
print(user)//["addr": "Beijing", "name": "age"]
// key不存在,则新增
user.updateValue("China", forKey: "addr")
print(user)//["name": "age", "addr": "China"]
// key存在,则修改
user.updateValue("Beijign", forKey: "addr")
print(user)
// 删除,不能设置nil,得使用remove
//user.updateValue(nil, forKey: "addr")
user.removeValue(forKey: "addr")
print(user)// ["name": "age"]
// 清空数据
user.removeAll()
print(user) // [:]
类型转换
var a:Int8 = 10
var b: Int32 = 20
// 语法错误,数据类型不一致,不能直接运算
//var c = a + b
// 必须数据类型一致,才可以进行运算
var c = a + Int8(b)
print(c)
元组
可以保存多个不同类型的数据。
var a = ("xiaoming", 18, "china")
print(a.0)
print(a.1)
print(a.2)
// 可读性更强
var b = (code:200, msg:"你好")
print(b.code)
流程控制语句
let a = 20
//if (a > 20){
// swift的括号可以省略
if a > 20{
print("a > 20")
}else{
print("a <= 20")
}
var b = 0
var sum = 0
while b < 101 {
sum += b
b += 1
}
print(sum)
var c = 0
var sum1 = 0
repeat {
sum1 += c
c+=1
}while c < 101
print(sum1)
let names = ["libai", "ake", "houzi"]
for i in 0...2{
print(i)
print(names[i])
}
// 默认for的变量是不可以修改的, 如果需要修改添加var修饰
for var i in 1...2 {
i *= 2
print(i)
}
// 如果不关心每次循环的值,可以使用下划线,
// for i in 0...9 ,如果声明了i但是不实用,则会警告
for _ in 0...9 {
print("hello world")
}
// 半开区间 1<=i<5
for i in 1..<5 {
print(i)
}
// for与数组
// ArraySlice<String> 返回的是数组切片
// names[2...] 如果不写后面的,表示一致到数组的最后一个元素
// names[...2] 表示从头开始
// names[..<2] 从头开始,不包含2
print(type(of: names[0...2]))
for name in names[0...2]{
print(name)
}
// 带间隔的区间
for v in stride(from: 0, through: 10, by: 2) {
print(v, terminator: " ")
}
// 0 2 4 6 8 10
// switch
// case和default后面不能有大括号
// switch必须处理所有情况。如果有default则自动包含了所有情况。
// case和default至少有一条语句,如果不需要执行代码,可以直接break
var numer = 1
switch numer {
case 1:
print("1")
// break //默认是break
fallthrough // 会直接执行下一条case
case 2:
print(2)
// break
default:
print("not match")
break
}
// 区间匹配
let count = 10
switch count {
case 0:
print("a is 0")
case 1...100:
print("1 <= count <= 100")
default:
break
}
// 元组匹配
var t1 = (100, 200)
switch t1 {
case (10, 20):
print("(10, 20)")
case (_, 100):
print("第二个值是100")
case (100, _):
print("第一个值是100")
case (-100...100, 100...1000):
print("好大一个数")
default:
print("not match")
}
// 值匹配
var point = (10, 200)
switch point {
case (let x, 0): // 第二个必须是0才能匹配
print("x is \(x)")
case (0 ,let y):
print("y is \(y)")
case let (x, y):
print(" x is \(x) y is \(y)")
}
// where
for v in 0...100 where v % 30 == 0 {
print(v, terminator: " ")
// 0 30 60 90
}
// 标签语句
outer: for i in 1...4 {
for k in 1...4 {
if k == 3 {
continue outer
}
if i == 3 {
break outer
}
}
}
函数
无参无返回值函数
func hello(){
print("hello world")
}
hello()
如果函数没有返回值,也可以写成返回Void,空元组。
// 返回值是空可以返回Void
func test1() -> Void {
}
// 返回值是空可以返回空元组
func test2() -> () {
}
// 返回值是空可以不写返回值
func test3() {
}
有参数无返回值函数
func hello(name: String){
print("你好 \(name)")
}
hello(name: "大哥")
可以传递多个参数
func add(num1:Int, num2: Int, num3: Int){
var total = num1 + num2 + num3;
print("total is \(total)")
}
add(num1: 10, num2: 20, num3: 30)
可以传递数组作为参数
func add1(a:[Int]){
print(a)
}
func add2(a:Array<Int>){
print(a)
}
add1(a: [1,2,3])
add1(a: [4,5,6])
可以传递字典作为参数
func hello1(data:[Int: Int]){
print(data)
}
func hello2(data:Dictionary<Int, Int>){
print(data)
}
var dict = [1:100, 2:89, 3: 78]
hello1(data: dict)
hello2(data: dict)
指针参数
基本数据类型,默认是值传递。无法修改原来的值。使用指针则传递的是引用。
func myadd(a: inout Int){
a += 1
}
var a = 10;
myadd(a: &a)
print(a)
+
和+=
具体的作用全部是由开发者去实现。
class Student{
var age : Int = 10;
static func +(stu:Student, stu2:Student){
stu.age += stu2.age
}
static func +=(stu:Student, stu2:Student){
stu.age = stu2.age
}
}
var s = Student()
var s2 = Student()
s + s2
print(s.age) //20
s += s2
print(s.age) // 10
有参数有返回值
func hello(name: String) -> String{
return "你好 \(name)"
}
var s = hello(name: "小明")
print(s)
如果函数体只有一句代码,可以省略return
func hello(name: String) -> String{
// 语法错误,不能有多行代码
// var s = "你好 \(name)"
// s
"你好 \(name)"
}
var s = hello(name: "小明")
print(s)
// 返回元组
func matchMaxMin(a: Int, b: Int) -> (max: Int, min: Int) {
if a > b {
return (a , b)
}else {
return (b , a)
}
}
print(matchMaxMin(a: 10,b: 20))
print(matchMaxMin(a: 100,b: 20).max)
函数的文档注释
/// 求2个整数的和
///
/// 求2个数的和,并返回和
///
/// - Parameter a: 第一个整数
/// - Parameter b: 第二个整数
/// - Returns: 返回值是整数
///
/// Note: 两个参数的类型都是整数,返回值也是整数
///
func sum(a: Int , b: Int) -> Int {
a + b
}
参数标签
// 参数标签
func sum(first a: Int , second b: Int) -> Int {
a + b
}
// 函数调用的时候可以使用参数标签的字段
print(sum(first: 10, second: 20))
// 省略参数标签使用下划线
func sum1(_ a: Int , _ b:Int ) -> Int {
a + b
}
// 参数可以不写,直接写内容
print(sum1(10, 20))
函数参数可以提供默认值
// 默认值
func greet(name: String, text: String = "你好") {
print("\(text) \(name)")
}
greet(name: "李白")
greet(name: "猴子", text: "welcome")
可变参数: 一个函数只能有一个可变参数,另外,可变参数后面的第一个参数不能使用省略标签func sum(a:Int ... , _ b: Int = 10)
, sum(10, 20)
这样容易引起歧义,其中20是a还是b不好界定,所以不可以这样写。
// 可变参数
func all_print(a: Int...) {
for v in a {
print(v, terminator: " ")
}
// 100 200 300
}
all_print(a: 100, 200 ,300)
函数重载
- 必须满足函数名称相同
- 满足其一
- 参数个数不同
- 参数类型不同
- 参数标签不同
func sum(a: Int, b: Int){
print(a + b)
}
// 参数个数不同
func sum(a: Int, b: Int, c: Int){
print(a + b + c)
}
//参数的类型不同
func sum(a: Int, b: Double) {
print(Double(a) + b)
}
//标签不同
func sum(first a: Int ,second b : Int) {
print(a + b)
}
// 形参不同
func sum(a1: Int , b : Int) {
print(a1 + b)
}
类和对象
类使用class关键字。
class Person{
var name:String
var age:Int
init(name:String, age:Int){
self.name = name;
self.age = age;
}
}
var p = Person(name: "程咬金", age: 20);
print(p.name)
print(p.age)
多线程
Swift的多线程和OC基本一致。另外,Swift开始支持async,await。