swift 的變量都是集成結(jié)構(gòu)體,并且結(jié)構(gòu)體里邊和實現(xiàn)了很多的方法
swift 不允許基本屬性為空(必須有一個不為空的初始值),所以引入了可選類型
?:可選類型
就是一個盒子,里邊裝這數(shù)據(jù)
!:強制解包
脫掉盒子,拿到里邊的數(shù)據(jù)
if 或者guard 可選項綁定解包
let a : Int? = 10
if let b = a {
// 如果a 解包 == b
print(b)
}else {
//解包失敗
}
// guard 默認(rèn)是flase(和if 相反)
guard let b = a else{
// 如果a 解包 == b
print(b)
}
??:空合運算符
// 底層是一個自動閉包
//如果b不為空,把b賦值給a,如果b為空,把c賦值給a
let a = b ?? c
//> 注意:b 必須是可選類型
// b和c的存儲類型必須相同
// a的類型取決于c 的類型,如果c 為可選類型,那么a為可選,如果c為值,a也為值
let b : Int? = 10
let c = 1
let a = b ?? c // a = 10 強制b解包,賦值給a
let b : Int? = nil
let c = 1
let a = b ?? c // a = 1
//空合運算符解包(解包成功就賦值,否則賦值為o)
let a : Int? = 10
let b = a ?? 0
枚舉:
// 普通
enum Direction {
case north //成員值
case south
case east
case west
}
// a(enun) 一個字節(jié)保存(0,1,2,3)
let a = .north
enum Score {
case points(Int) // 關(guān)聯(lián)值 (成員值和其他類型的關(guān)聯(lián)存儲在一起)
case grade(String)
}
// b(enun) 16個字節(jié)保存(int = 8 string = 8)
// 關(guān)聯(lián)屬性保存在enum 內(nèi)存中
let b = Score.points(98)
enum Poker : String {//原始值類型
case a = "A" // 原始值(相同類型的默認(rèn)值賦值給關(guān)聯(lián)值(默認(rèn)關(guān)聯(lián)成員值))
case b = "B"
}
// c(enun) 1個字節(jié)保存(1,2)
// 原始值其實就是一個計算屬性,內(nèi)部是以set來實現(xiàn)的,所以不會占enum 的內(nèi)存
let c = Poker.a
let d = Poker.a.rawValue//c.rawValue
結(jié)構(gòu)體
struct Point {
var x : Int
var y : Int
}
// 結(jié)構(gòu)體默認(rèn)有一個init 方法
// a (struct) 占 16 字節(jié)
var a = Point(x : 10, y : 20)
//下邊的方法不行(變量必須包含一個初始值)
var a = Point(x : 10)
var a = Point(y : 20)
var a = Point()
struct Point {
var x : Int = 10
var y : Int = 20
}
// 結(jié)構(gòu)體默認(rèn)有4個init 方法
//下邊的方法都可以
var a = Point(x : 10, y : 20)
var a = Point(x : 10)
var a = Point(y : 20)
var a = Point()
// 下邊2中寫法相同(系統(tǒng)默認(rèn)添加init初始化器)
struct Point {
var x : Int = 10
var y : Int = 20
}
struct Point {
var x : Int
var y : Int
init(){
x = 10
y = 20
}
}
類
class Point {
var x : Int = 10
var y : Int = 20
}
// 如果類有初始化值就,默認(rèn)創(chuàng)建一個init方法
// 如果沒有初始值,默認(rèn)一個init 方法都沒有
// a (class) 占 32 字節(jié),保存在堆上 前8個字節(jié)保存指向類型的信息,后8個字節(jié)是引用計數(shù),再后邊是x 和 y 各占8字節(jié)
var a = Point()
//下邊的方法不行(類沒有)
var a = Point(x : 10)
var a = Point(y : 20)
var a = Point(x : 10, y : 20)
類和結(jié)構(gòu)體的區(qū)別

- 結(jié)構(gòu)體(枚舉) 是值類型 而 類是引用類型(指針類型)
- 值類型保存在棧里邊,而引用類型保存在堆里邊
- 值類型賦值,采用的是深拷貝(在swift 標(biāo)準(zhǔn)庫中,sring,arr,dic 等如果指沒有修改,采用的就是淺拷貝)
- 類可以繼承,而結(jié)構(gòu)體不可以
閉包表達(dá)式
func sum (_ vi: Int, _v2: Int) -> Int{
return v1 + v2
}
//等價下邊這個,return 一行可以省略
func sum (_ vi: Int, _v2: Int) -> Int{ v1 + v2}
// 使用閉包表達(dá)式
let fn = {
(_ vi: Int, _v2: Int) in { v1 + v2}
}
fn(10, 20)
//閉包精簡過程
func exec(v1: Int, v2:Int, fn: (Int, Int) -> Int){
print(fn(vi, v2))
}
//調(diào)用
exec(v1:10, v2:20, fn: {
(vi: Int, v2: Int) -> Int in return v1 + v2
})
exec(v1:10, v2:20, fn: {
vi, v2 in return v1 + v2
})
exec(v1:10, v2:20, fn: {
vi, v2 in v1 + v2
})
exec(v1:10, v2:20, fn: {
$0 + $1
})
//尾隨閉包(當(dāng)最后一個參數(shù)是閉包表達(dá)式,可以放到函數(shù)調(diào)用的外邊)
exec(v1:10, v2:20) {
$0 + $1
}
閉包
當(dāng)閉包表達(dá)式引用了捕獲了外部變量,就把這個表達(dá)式+變量的組合叫做閉包
typealias Fn = (Int) -> Int
func getFn () -> Fn{
var a = 0
func plu(_ i: Int) -> Int{
a += i
return a
}
return plu
}//plu + a 形成閉包
//a為局部變量,保存在棧里邊,fn(1) 執(zhí)行完成,就釋放了;那么為什么fn(2) = 3
// 閉包為了延長局部變量的生命周期,把a重??臻g拷貝到堆空間
// fn 占16字節(jié),前8個字節(jié)是plu的地址值,后8個是a堆空間的地址值(如果沒有捕獲,后邊都是0)
//當(dāng)調(diào)用plu 的時候,會把a的地址值傳進(jìn)去
var fn = getFn()
print(fn(1)) // 1
print(fn(2)) // 3
var fn1 = getFn()
print(fn1(1)) // 1
print(fn1(2)) // 3
//自動閉包 @autoclosure
func geta (_ v1: Int, _ v2: @autoclosure () -> Int) ->Int{
return v1 > 0 ? v1 : v2()
}
//自動把 20 變成了閉包 :geta(10, {20})
geta(10, 20)
屬性
分類:
1.實例屬性:使用對象調(diào)用
存儲實例屬性:相當(dāng)成員變量,類和結(jié)構(gòu)體可以定義而枚舉不可以
計算實例屬性:就是方法,不占用內(nèi)存,枚舉也可以定義
2.類型屬性:使用類調(diào)用的(在class 也可以使用class 修飾,線程安全)
存儲類型屬性:整個程序運行過程中只有一份內(nèi)存(static 修飾)
計算類型屬性:static 修飾
//一般情況下,使用計算屬性就是因為計算屬性和存儲屬性存在魔種有關(guān)系
class c {
//存儲屬性
var a :Double
//計算屬性:不能使用let,因為要改變。
//可以只有g(shù)et 方法(但是這樣也不能使用let),不能只有set方法
var b : Double {
set {
a = newValue / 2
}
get {
a * 2
}
}
}
延遲屬性lazy
在第一次使用的時候初始化
class text {
// lazy 不能使用let(let 必須在初始化之前有初始值)
// 多線程調(diào)用lazy 屬性,有可能初始化多次
lazy var a: Int
}
var a = text()//沒有初始化a, a.a 的時候調(diào)用
屬性觀察器
非lazy 可以添加
在初始化的時候不會觸發(fā)屬性觀察器
class text {
var a: Int{
willSet{
print(newValue)
}
didSet{
print(oldValue, newValue)
}
}
}
存儲類型屬性
class Car {
static var count = 1
}
// 和全局變量一樣
// 默認(rèn)為lazy,并且可以為let
// 第一次賦值( count = 1)的時候,底層調(diào)用了dispath_one 初始化
Car.count = 10
方法
實例方法:對象調(diào)用的方法
類型方法: 類型調(diào)用的方法(結(jié)構(gòu)體和class)
class Car {
static var cout = 0
init() {//實例方法
}
//類型方法
static func getCount() ->Int{ cout }
}
var car = Car()
Car.getCount()
struct Car {
var a = 0
//結(jié)構(gòu)體(或枚舉)不能在方法里邊修改變量,class 可以
//add mutating 就可以了
mutating func text(){
a = 10
}
//@discardableResult 可以消除調(diào)用的時候無返回值的警告
@discardableResult mutating func text1() -> Int{
a += 1
return a
}
}
var car = Car()
car.text1()
subscript 下標(biāo)
struct Car {
var a = 0.0
var b = 0.0
// 返回值(Double) 確定了 newValue 和 get 返回值的類型
subscript(index: Int) -> Double{
set {
if index == 0 {
a = newValue
}else if index == 1{
b = newValue
}
}
get{
if index == 0 {
return a
}else if index == 1{
return b
}
return 0
}
}
}
var car = Car()
car[0] = 11.1
car[1] = 22.2
print(car[0])
print(car[1])