swift 基礎(chǔ)(一)

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ū)別

  1. 結(jié)構(gòu)體(枚舉) 是值類型 而 類是引用類型(指針類型)
  2. 值類型保存在棧里邊,而引用類型保存在堆里邊
  3. 值類型賦值,采用的是深拷貝(在swift 標(biāo)準(zhǔn)庫中,sring,arr,dic 等如果指沒有修改,采用的就是淺拷貝)
  4. 類可以繼承,而結(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])
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容