参考
基础部分
1. 常量和变量
– 常量声明let i = 0
– 变量声明var i = 0
2. 显式指定变量或常量类型
var msg:String
var msg:String = "msg"
3. 注释
– 单行 //...
– 多行/*......*/
4. print输出
– print("\(表达式)")
5. 数据类型
– 浮点数Double 64位
– 浮点数Float 32位
– 整数类型Int,Int8,Int16,UInt8,UInt16
– 布尔类型Bool
6. 元组Tuples
– 声明
let t = (1,"a")
– 访问
t.1
t.2
7. 可选类型Optionals
– 含义:表示有值或没有值nil
//创建
var str1 : String?//str1为nil
var str2 : String? = "msg"//str2为msg
str2 = nil //str2为nil
//强制取值
print(/(str2!))
//可选绑定
if let number = Int(possibleNumer){
//number是真实值,不为nil
}else{
//number为nil
}
8. 错误处理
do{
try ..
}catch Error{
...
}catch Error2{
...
}
运算符
1. 三元运算符 condition?exp1:exp2
2. Nil Coalesecing Operator
– a??b
等价于a != nil ? a! : b
3. 区间运算符
- 闭区间
a...b
for index in 1...5{
//todo
}
- 半开区间
a..<b
for index in 0..<arr.count{
//todo
}
- 单侧区间
//索引2到结尾
for name in names[2...]{
//todo
}
//索引0到2
for name in names[...2]{
//todo
}
字符串和字符
- 多行用三个双引号
"""..."""
- 字符串连接使用
+
- 创建字符
let c : Character = "!"
- 字符添加到字符串
s.append(c)
- 字符串插值
\(表达式)
- 字符串长度
s.count
- 字符串索引
s.startIndex
s.index(before:s.endIndex)
s.index(after:s.startInex)
s.index(s.startIndex,offsetBy:7)
s.indices
- 在指定位置插入字符或字符串
s.insert(_:,at:)
s.insert(contentsOf:at:)
- 子字符串
s[..<index]
- 比较字符串
==
!=
- 前后缀相等
hasPrefix()
hasSuffix()
集合
可变性(引用和内容):可变var ,不可变let
1. 数组Arrays
- 创建
//空的
var arr = [Int]()
//带指定值
var arr = [1,3,5]
//
- 数组拼接
+
- 数组属性
arr.isEmpty
arr.count
- 数组操作
//访问
arr[0]
//追加
arr.append()
//插入
arr.insert(123,at:0)
//删除
arr.remove(at:0)
- 遍历
//只元素
for item in arr{
//todo
}
//元素和索引
for (index,value) in arr.enumerate(){
//todo
}
2. 集合Sets
- 创建
//空的
var s = Set<Character>()
//带值
var s : Set = ["a","b","c"]
其他与Array类似
3. 字典
- 创建
//空的
var dict = [Int:String]()
//带值
var dict = [1:"one",2:"two"]
- 操作
//取值,返回optional
dict[1]
//添加或更新
dict[1] = "one"
if let oldValue = dict.updateValue("value",forKey:1){
//key存在则更新并返回旧值,不存在则返回nil
}
//删除键值对
dict[1] = nil
dict.removeValue(forKey:1)
- 遍历
for (k,v) in dict{}
for k in dict.keys{}
for v in dict.values{}
控制流
1. for循环中不需要取每一项的值
for _ in 1...5{
//todo
}
2. repeat-while
即do while
3. switch fallthrough
switch
中的case中隐式的加入了break,不需要break可以显式的加上fallthrough
,case可以有多个值
switch value{
case value1:
...
case value2,value3:
...
default:
...
}
4.guard
//可以作为检验参数时使用
func f(person:[String,String]){
guard let name = person["name"] else {
return
}
}
函数
1. 定义函数与调用
- 一般
func f(para1:String)->String{
return ""
}
- 带有默认值
func f(para1:String="hello")->String{
return ""
}
- 无返回值
func f(para1:String){
}
- 多返回值,返回元组
func f(para1:String) -> (a:Int,b:Int){
return (a,b)
}
- 返回Optional
func f() -> String?{
//可以返回nil
}
- 可以省略return
func f() -> String{
"hello"
}
- 可变参数
func f(para1:Int...) -> Int{
}
- 输入输出参数(即按
地址
传递)
func f(para1:inout Int){
}
2. 函数当做一种类型
//当定义的函数为
func f(a:Int,b:Int)->Int{}
//函数f的类型为(Int,Int)->Int
//可以使用这种类型赋予变量
var v:(Int,Int)->Int = f
//或自动推断
var v = f
//函数类型可以作为参数
func f(AnotherF:(Int,Int)->Int){}
//函数类型可以作为返回值
func f() -> (Int)->Int{}
//可以在函数中定义函数
func f(){
func f1(){}
func f2(){}
}
闭包
简化函数类型作为参数传递
1. 闭包表达式
//sorted为例
//使用函数传递
func f(s1:String,s2:String)->Bool{s1>s2}
names.sorted(by:f)
//使用闭包表达式
names.sorted(by:{(s1:String,s2:String)->Bool in return s1>s2})
//进一步省略
names.sorted(by:{s1,s2 in s1>s2})
//参数名称缩写
names.sorted(by:{$0>$1})
//运算符方法
names.sorted(by:>)
//尾随闭包
names.sorted(){$0>$1}
//当只有一个参数时,括号也可以省略
names.sorted{$0>$1}
2. 其他
逃逸闭包
自动闭包
枚举
1.定义
enum CompassPoint {
case north
case south
case east
case west
}
2.使用
val s = CompassPoint.north
3.可遍历
enum CompassPoint : CaseIterable{
case north
case south
case east
case west
}
//获取所有case:
CompassPoint.allCases
4. 带值
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
类与结构体
1. 不同点:
- 类实例没有默认的
逐一构造器
,结构体实例会有一个自动生成的逐一构造器
- 类是引用类型,结构体是值类型
2. 创建
struct SPeople{
var age:Int
var name:String
}
class CPeople{}
3. 创建实例
var sp = SPeople()
var cp = CPeople()
4. 属性访问和修改.
p.name = ""
5. lazy关键字
//被lazy修饰的属性,在第一次被访问到的时候才被创建
class C{
lazy var ...
}
6. 计算属性
获取该属性时,需要通过其他属性进行计算得到,设置改属性值时,其他属性的值可以发生变化
//例子:圆
struct Circle{
var r:Double = 0.0
var area:Double{
get{
return Double.pi*r*r
}
set(newArea){
r = sqrt(newArea/Double.pi)
}
}
}
//上面get可以省略return
//set可以使用默认的newValue参数,简化为
set{
r = sqrt(newValue/Double.pi)
}
//上面的计算属性area可以设置为只读,取消set
var area:Double{ Double.pi*r*r }
7. 属性观察器willSet
didSet
//默认参数newValue,oldValue
class C{
var v:Int=0{
willSet{
print("willSet:\(newValue)")
}
didSet{
print("didSet:\(oldValue)")
}
}
}
8. 类属性
(类似java中的static)
struct/class S{
static var v = ""
}
//static 换成 class可以允许子类重写
class C{
class var v = ""
}
9. 方法
- self关键字代表本实例
- 在struct的方法中修改属性需要加
mutating
struct S{
var v = 0.0
mutating func f(){
v += 1
}
}
10. 类方法(static)
class C{
static func f(){}
class func f(){}//允许子类重写
}
11. 下标语法
相当于用下标的方式调用函数
struct S{
subscript(index:Int)->Int{
get{}
set{}
}
}
//如果是只读
subscript(index:Int)->Int{
return...
}
//调用
var s = S()
s[0]//get
s[0]=1//set
下标可以有多个参数,多种类型
subscript(a:Int,b:String)->Int{
get{}
set{}
}
- 类下标
static subscript
继承
基本与Java类似
- 声明继承class ChildClass
:
SuperClass - 重写属性,方法等,在前面加上
override
- 子类访问父类
super.
- 防止继承或重写父类中加
final
构造过程
与Java类似
1. 构造方法为init
class A{
var i : Int = 0
init(i:Int){
self.i = i
}
}
2. 重写父类构造器
override init(){
super.init()
...
}
3. convenience init
用于初始化时没有指定属性值,默认初始化属性
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
//调用
let f = Food()
//f.name为[Unnamed]
4. 可失败构造器
传入不符合条件的构造参数时,初始化失败
init?
5. 必要构造器
该类的子类都必须实现该构造器
class C{
required init(){
//...
}
}
class D : C{
required init(){
//...
}
}
析构过程
在实例被释放前需要执行的代码,每个类只能有一个析构器,析构器不能主动调用
deinit{
//...
}
可选链式调用
1. 定义
- 可选链式调用是一种可以在当前值可能为 nil 的可选值上请求和调用属性、方法及下标的方法。如果可选值有值,那么调用就会成功;如果可选值是 nil,那么调用将返回 nil。多个调用可以连接在一起形成一个调用链,如果其中任何一个节点为 nil,整个调用链都会失败,即返回 nil
2. 使用可选链式调用代替强制展开
//如果使用!强制展开可选值可能会引发错误
//代替方案为 :使用?
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
错误处理
1. 方法抛出错误,称为throwing方法
func f() throws -> String{
//...
throw Error..
}
2. 不处理错误
func f1() throws -> String{
//...
throw Error..
}
func f2() throws -> String{
//...
try f1()
}
3. 处理一部分错误
func f2() throws -> String{
//...
do{
try f1()
}catch is XXXError{
//...
}
}
4. 处理所有错误
func f2() -> String{
//...
do{
try f1()
}catch XXXError{
//...
}catch XXXXError{
//...
}catch{
//...
}
}
5. 错误转换为可选值
//出错时x为nil
let x = try? f1()
6. 禁用错误传递
//强制执行,不抛出
try!f1()
7. 指定清理操作
//退出代码块`{}`后执行的操作(延迟执行)
func open(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readline() {
// 处理文件。
}
// close(file) 会在这里被调用,即作用域的最后。
}
类型转换
1. 判断实例属于哪个特定的子类型is
item is Movie
2. 将实例向下转换为特定的子类型as?
as!
item as? Movie //返回一个可选的Movie,转换失败则为nil
item as! Movie //强制转换为Movie类型
3. Any
和 AnyObject
//Any 可以表示任何类型,包括函数类型
//AnyObject 可以表示任何类类型的实例
嵌套类型
内部类
扩展
为已经存在的类,结构体,枚举,协议添加新功能
新功能包括:
添加计算型实例属性和计算型类属性
定义实例方法和类方法
提供新的构造器
定义下标
定义和使用新的嵌套类型
使已经存在的类型遵循(conform)一个协议
//添加方法
extension Double{
var km:Double{
self*1000.0
}
}
//使用
var a = 1.2.km
//a的值为1200
协议
类似Java interface
1. 创建
protocol P{
}
2. 使用
//父类名在协议前
class C : SuperClass,FirstProtocal,AnotherProtocal{}
3. 属性要求
协议中指定属性名,类型,可读写
protocol P{
var a : Int{get set}
var b : Int{get}
//类属性
static c : Int{get set}
}
4. 方法要求
protocol P{
func f() -> String
static func f() -> Int
}
5. 构造器要求
protocol P{
init(para:Int)
}
//required不可少
class C : P{
required init(para:Int){
}
}
//如果同时继承
class C : Super,P{
required override init(para:Int){
}
}
6. 协议的继承
protocol P : AnatherP{}
//如果继承AnyObject,那么该协议只能被类实现,不能被结构体实现
protocol P : AnyObject{}
7. 组合协议
//同时实现两个协议的类做为参数
func f(para:P1&P2){
}
8. 可选的协议要求@objc
9. 提供默认实现
通过extension
extension P{
}
10. some
- 反向泛型,隐藏具体的返回类型
//不使用some
struct ContentView : View{
var body : Text{
Text("hello")
}
}
//使用some
struct ContentView : View{
var body: some View{
Text("hello")
}
}
//这里的用some可以指定返回实现了View的类即可,避免在方法声明时就写上具体类型,方便更新维护
泛型
- 基本
func f<T>(a:T,b:T) -> T{}
//泛型约束
T约束为子类或实现协议
func f<T : SuperClass,P>
- 在protocol中使用泛型
associatedtype
protocol P{
associatedtype T
}
访问控制
public
internal
默认的,模块内
file_private
private
常用类、协议、结构体
1. Hashable
//标明一个类型是可哈希化的,这样这个类型可以在Set,Dictionary中使用,因为需要这个类型的hashValue。hash后可以使用==操作符。
struct Person:Hashable{
var name:String
var id:Int
func hash(into hasher: inout Hasher) {
//需要用哪些属性进行hash计算,就combine进去,如果没有属性被combine进去,那么每个实例的hash值都是相同的
hasher.combine(name)
hasher.combine(id)
print("hash")
}
}
2. Codable
//类似于java的序列化,可以将实例编码为外部数据,也可以用外部数据解码生成实例
//例JSONEncoder ,JSONDecoder
let s = S(name: "a", id: 1)
let str = String(data: try! JSONEncoder().encode(s), encoding:.utf8)!
//str 为 {"name":"a","id":1}
let jsonStr = """
{"name":"a","id":1}
"""
let s2 = try JSONDecoder().decode(S.self, from:jsonStr.data(using: .utf8)!)
//s2为S(name: "a", id: 1)