Swift基本數據類型以及控制循環

基本數據類型

  • 常見的數據類型:

    • 值類型(value type)
    1. 枚舉
      enum / Optional
    2. 結構體
      Bool/Int/Float/Double/Character/String/Array/Dictionary/Set
    • 引用類型(reference type):
      類(class)
    • 整數類型
      在32位的平臺中Int等價於Int32、64位平臺Int等價於Int64
      Int8/Int16/Int32/Int64/UInt8/UInt16/UInt32/UInt64
    • 浮點類型:
      Float(32位,精度只有6位)
      Double(64位,精度至少15位)
 func valueFunc() {
        
        var floatDemo: Float? = 10
        var doubleDemo: Double? = 29
        
        enum TestEnum{
            case one,two,three
        }
        struct SomeStruct{
            var age = 10
            var height = 167
        }
    }
  • 字面量,直接賦值,編譯器可以推斷其類型的內容
        let bool = true
        let intDecimal = 17 //十進制
        let intBinary = 0b1001010 //二進制
        let intHexdecimal = 0x12 //十六進制
        let intOctal = 0o21 //八進制
        
        let doubleDecimal = 125.0 //十進制 等價於1.25e2
  • 類型轉換
func typeToChange() {
        //整數轉換
        let int1: UInt16 = 2_000
        let int2: UInt8 = 1
        let int3 = int1 + UInt16(int2)
        
        //字面量可以直接相加,字面量本身沒有明確的類型
        let int4 = 123 + 12.344
    }
  • 元組
func tupleDemo() {
        //如何創建一個404錯誤的元組?如何取值?
        let http404Error = (404,"404 error, not found")
        print("The status is \(http404Error.0)")
        
        //如何對元組取值
        var firstValue = http404Error.0
        var secondValue = http404Error.1
        
        //取到元組內容
        let (status, message) = http404Error
        print("status code is \(status), message:\(message)")
        
        //忽略某個元組參數
        let (careStatus, _) = http404Error
        print("i only care status:\(careStatus)")
        
    }
  • 條件判定(if 後面只能是Bool類型,可以省略小括號,大括號不能省略)
func loginJudge() {
        let age = 5
        if age >= 22 {
            print("ready to marry")
        }else if age > 18{
            print("just in adult")
        }else{
            print("just a child")
        }
  • while的使用
 /*
     循環
     while使用
     repeat...while 相當於OC中的do...while循環
     */
    func whileUse() {
        var num = 5
        while num > 0 {
            print("循環我...")
            num -= 1
        }
        
        var repeatTimes = 5
        repeat{
            print("look here ...")
            repeatTimes -= 1
        }while repeatTimes > 0
    }
  • for循環使用
func forLoopUse() {
        let names = ["Zhang", "Lee", "Chen", "Gong"]
        //...是閉區間方法,返回閉區間
        for i in 0...3 {
            print(names[i])
        }
        //使用range遍歷
        let range = 1...3
        for j in range {
            print(names[j])
        }
        
        var a = 1
        let b = 3
        for j in a...b {
            print(names[j])
        }
        
        for _ in 0 ..< names.count {
            print("for item")
        }
    }
  • 區間運算符
    /*
     區間運算符
     通過創建區間運算符判定指定數的範圍類型
     */
    func rangeCreatAndUse() {
        let range = ...10
        print(range.contains(20))
        print(range.contains(11))
    }

    /*
     使用區間運算符遍歷數組,區間運算符:[1...b]/[1...]/[...1]/[..<2]
     */
    func rangUseInArray() {
        
        let names = ["Zhang", "Lee", "Chen", "Gong"]
        for name in names[0...3] {
            print(name)
        }
        
        for name in names[...3] {
            print(name)
        }
        
        for name in names[..<4] {
            print(name)
        }
    }
  • 區間類型
    1. ClosedRange<T> 閉區間
    2. Range<T> 半開區間(前閉後開)
    3. PartialRangeThrough<T> 部分區間
//練習:使用區間判斷字符是否在字母範圍,請利用區間特性
func rangeType() {
        let _: ClosedRange<Int> = 1...3 //閉區間
        let _: Range<Int> = 1..<3 //半開區間(前閉後開)
        let _: PartialRangeThrough<Int> = ...5 //部分區間
        
        let character: ClosedRange<Character> = "a"..."z"
        print(character.contains("B"))
        
        let charRang: ClosedRange<Character> = "\0"..."~"
        print(charRang.contains("B"))
    }

//從4開始累加2,不超過11,篩選出對應的數據值,可以使用stride方法來進行跳躍
 func rangeContainThrough() {
        let allRang:ClosedRange<Int> = 1...100
        
//        var indexValue = 0
//        switch allRang.startIndex {
//        case .inRange(let preIndex):
//            indexValue = preIndex
//        default:break
//        }
//
//        print("position [0] = \(indexValue)")
    
        for targetValue in stride(from: 4, through: 100, by: 2) {
            print(targetValue)
        }
    }
  • Switch 語句
    1. case/default後面不能夠添加大括號
    2. Swift中的case不用添加break,默認會執行到下一個case到來

注意點:
1. case、default 後面至少需要跟一條語句
2. 如果不想做任何事,可以在最後添加break語句結束

func switchUse() {
        let num = 1
        switch num {
        case 1:
            print(num)
        case 2:
            print(num)
        default:
            print(num)
        }
    }

    /*
     連續執行多行case,如何操作?
     可以使用fallthrough操作
     */
    func mutiCaseExec() {
        let num = 1
        switch num {
        case 1:print(num); fallthrough
        case 2:print(num); fallthrough
        case 3:print(num); fallthrough
        case 4:print(num)
        case 5:print(num)
        default:break
        }
    }

    /*
     switch 自定義枚舉的時候,如果保證所有的枚舉都列舉完成,
     那麼可以不必使用default來處理默認情況
     */
    func associateEnumValue() {
        enum Answer{case right, wrong}
        let finishAnswer = Answer.right
        switch finishAnswer {
        case .right:print("answer result is \(finishAnswer)")
        case .wrong:print("answer result is \(finishAnswer)")
        }
    }

    /*
     switch case如何使用複合類型來判定
     */
    func moreTypeCase() {
        let string = "Jack"
        switch string {
        case "hello", "Lee", "Wang": print("rich man~")
        case "Jack": print("poor man~~")
        default: print("Not Found")
        }
    }

    /*
     Switch
     1. 使用區間Range進行值匹配
     2. 使用元組進行case匹配
     */
    func switchRangeCase() {
        let score = 45
        switch score {
        case 0..<60: print("Not Ok")
        case 60..<80: print("Just So So")
        case 80..<90: print("Good")
        case 90..<100: print("Woundful")
        default:print("So bad")
        }
        
        let infoMan = (84, "Good")
        switch infoMan {
        case let (cScore, cLevel): print("score\(cScore), level:\(cLevel)")
        case let (_, cLevel): print("level:\(cLevel)")
        default:break
        }
        
    }
  • 值綁定

使用let = option case 進行值綁定

    /*
     值綁定
     使用let = option case 進行值綁定
     */
    func valueBind() {
        let point = (2, 0)
        switch point {
        case (let x, var y): print("x: \(x), y:\(y)")
        case (_, var y): print("x: -, y:\(y)")
        case (let x, _): print("x: \(x)")
        default:break
        }
    }
  • 條件過濾where
    /*
     where 條件過濾
     */
    func whereFiliterUse() {
        var point = (1, 2)
        switch point {
        case (let x, let y) where x == y: print("y=x line in dicarl line")
        case (_, let y) where y==0: print("y line in dicarl line")
        case (let x, let y) where (x>0 && y>0): print("location is in first part view")
        default:break
        }
    }
  • 標籤語句 outer
    /*
     標籤語句(通過outer標籤語句能夠簡化跳轉邏輯)
     outer:
     */
    func outerUse() {
        outer: for k in 1...4 {
                for j in 8...16 {
                    if j == 10 {
                        continue outer
                    }
                    if k == 3 {
                        break outer
                    }
                    print("k == \(k), j=\(j)")
                }
        }
    }

函數的定義

  • 函數的隱式返回

對於只有一行的語句,可以省略返回return關鍵字,這種省去返回return關鍵字的操作叫做隱式返回.

    class FuncUse {
        //帶返回值
        static func pi() -> Double {
            return 3.14;
        }
        
        //加法
        static func sum(v1: Int, v2: Int) -> Int {
            return v1 + v2
        }
        
        //加法簡化
        static func sumSlim(v1: Int, v2: Int) -> Int {v1+v2}
        
    }
    /*
     返回元組,實現多值返回
     */
    func tupleReturnUseTypeAlias() -> (userName: String, age: String, className: String) {
        (userName: "String", age: "String", className: "String")
    }
   
  • 函數默認參數值
    這裏的方法參數設置與C++有點區別,
    C++中參數值有限制,必須從右向左設置
    對於沒有設置默認值的方法參數是不能夠省略的
    而Swift中由於存在參數標籤,所以不用按順序進行設置

例如下面的方法調用:
Swift:self.funcDefaultParamter(age: 28)
c++: self.funcDefaultParamter("lcc",28,"workMan")

func funcDefaultParamter(name: String = "lcc", age: Int, job: String = "none") {
        print("name:\(name), age:\(age), job:\(job)")
    }
  • 可變參數(...)
    1. 可變參數在取值的時候使用遍歷取值
    2. 一個方法最多隻有一個可變參數
    3. 緊跟可變參數後面的參數不能夠省略標籤
    func moreParameterIngoreTag(_ numbers: Int..., eachItem: (Int)->()) -> Int {
        var sum = 0
        for item in numbers {
            eachItem(item)
            sum += item
        }
        return sum
    }
    
    func moreParamterUse(_ numbers: Int...) -> Int {
        var sum = 0
        for number in numbers {
            sum += number
        }
        return sum
    }
  • 函數重載
    1. 返回值類型與函數重載沒有關係
    2. 默認參數值與函數重載一起使用的時候如果產生歧義,編譯器不會報錯,優先調用匹配完全一致的方法
    func someFunc() {
        print("source func")
    }
    
    func someFunc(v1: Int, v2: Int) {
        print("change func use to sum: \(v1 + v2)")
    }
    
    func someFunc(v1: Int, v2: Int, v3 :Int = 20) {
        print("more parameter count: \(v1 + v2 + v3)")
    }
  • 輸入輸出參數 inout

可以在函數內部調用外界的方法,比較典型的範例就是通過元組實現兩個數字的交換

    //傻子方法
    func swapNum(numberOne: inout Int, numberTwo: inout Int) {
        let sourceTuple = (numberOne, numberTwo)
        let result = (sourceTuple.1, sourceTuple.0)
        numberOne = sourceTuple.1
        numberTwo = sourceTuple.0
        print("交換之前:\(sourceTuple), 交換之後\(result),numberOne:\(numberOne),numberTwo:\(numberTwo)")
    }
    
    //優雅方法,使用元組直接能夠交互
    func swapNum(numberOne: inout Int, numberTwo: inout Int, des: String = "") {
        (numberOne, numberTwo) = (numberTwo, numberOne)
    }
  • 內聯函數 @inline

Swift編譯器中默認是開啓自動轉換內聯函數的功能的實質:將函數調用展開成函數體。
注意:
1. 函數體比較長的不會被轉換成函數體
2. 遞歸調用不會轉換成函數體
3. 包含動態派發不能夠轉換成函數體

    func buildToChange() {
        print("transform to me")
    }
    
    //關閉內聯
    @inline(never) func inlineUse() {
        print("即使開啓編譯器優化,也不會被內聯")
    }
    
    //強制內聯
    @inline(__always) func inlineOnAlways() {
        print("即使代碼段很長,也會被內聯,除了動態派發的函數以及遞歸調用的函數外")
    }
  • 函數類型

函數類型包含以下兩個重要組成:

  1. 形式參數類型
  2. 返回值類型
 func funcTest(parameter: String...) -> (String) {
        var strUnition = ""
        for str in parameter {
            strUnition.append(str)
        }
        return strUnition
    }
print(self.funcTest(parameter: "leo ", " is"," the", " best", " programmer"))
  • 使用函數類型作爲函數的參數進行傳遞
  1. @autoclosure的使用,對於沒有參數的函數作爲參數的話可以添加@autocclosure關鍵字讓函數的調用更加簡潔高效
  2. 正常函數調用,如果將函數作爲參數進行傳遞的話,可以考慮使用$符獲取參數內容
    func printSumResult(n1: Int, n2: Int, sumAdd: @autoclosure()->(Int)) {
        print(sumAdd())
    }
    
    func printSumResult(n1: Int, n2: Int, sumAdd: (Int, Int)->Int) {
        print(sumAdd(n1, n2))
    }

self.printSumResult(n1: 1, n2: 2, sumAdd: 3)
self.printSumResult(n1: 32, n2: 29) {$0+$1}
self.printSumResult(n1: 32, n2: 11) { (num1, num2) -> Int in num1 + num2}
  • 使用函數作爲返回值進行傳遞操作
    返回值是函數類型的函數,也叫做高階函數
    func returnFunUse() -> (Int, Int) -> Int {
        return {$0+$1}
    }
  • 類型別名 typealias
typealias LCInt = Int
typealias LCFloat = Float
func typealiasUse(age: LCInt, score: LCFloat) {
    print("age:\(age), score:\(score)")
}
  • 嵌套函數
    在函數中嵌套一個函數。
    func funcInFunc() -> ((String, Int) -> () , (Int, Int) -> (Int)) {
        func result(usrName: String, age: Int){
            print("I get your name:\(usrName), and your age:\(age)")
        }
        func countTwoSum(num1: Int, num2: Int) -> Int{num1 + num2}
        return (result, countTwoSum)
    }

    
     var (funcOne, funcTwo) = self.funcInFunc()
     funcOne("lcc", 25)
     print("count result:\(funcTwo(24, 64))")
     
     self.funcInFuncSignal()(1,3)

  • 枚舉的基本用法

    1. 值類型枚舉
    2. 關聯值類型

將值類型成員與其他類型的值關聯在一起,可以起到關聯變量值存儲的作用,在使用的枚舉,抽象表達某些功能的時候會變得異常方便

注意:值類型與關聯值類型的空間存儲區別
1. 如果枚舉是基本的值類型,那麼枚舉在內存空間的容量是固定的,因爲本質存儲的是原始值,默認分配1個字節的空間內容來進行存儲
2. 如果枚舉是關聯類型的存儲,那麼要根據枚舉的類型來確定其內存空間的佔用大小,通常選擇枚舉關聯值最大的爲存儲空間,還要加上原始值的存儲(1個字節),最終算出來的是其真實佔用的空間大小

佔用空間大小與實際內存分配的大小區別

佔用空間大小是通過當前數據類型佔用的空間大小累加的總和,而在實際分配過程中由於iOS系統通常會採用內存對齊的方式去分配真實的空間,通常是8個字節的整數倍。所以由於內存對齊的原因,在實際分配內存上,可能分配的空間大於實際所佔用的內存空間

    //以下實際佔用了 32+1 = 33 個字節的空間大小,實際分配了40個字節的空間大小
    enum Password {
        case number(Int, Int, Int, Int)
        case other
    }
    
    //值類型,僅分配1個字節存儲原始值內容
    enum Direction {
        case top, left, bottom, right
    }
    
    //關聯值類型
    enum LoadServerMethod {
        case LoadFirst(url: String)
        case LoadSecond(url: String)
        case LoadFinish(finish: (Any)->())
    }
    
    func testEnum() {
        let gogoUp = Direction.top
//        let requestServer = LoadServerMethod.LoadFirst(url: "http://www.baidu.com")
        let finishClosure = LoadServerMethod.LoadFinish { (data) in
            print("server data:\(data)")
        }
        
        switch gogoUp {
        
        case .top: print("top")
        case .left: print("left")
        case .bottom: print("bottom")
        case .right: print("right")
        }
        
        switch finishClosure{
        case .LoadFirst(let url): print("請求的地址:\(url)")
        case .LoadSecond(let url): print("請求的地址:\(url)")
        case .LoadFinish(let finish): finish(["data":"nil"]);
        }
    }
    
  • 枚舉的用法
    枚舉成員可以使用相同的類型的默認值進行預先關聯,默認設置的值叫做原始值,枚舉原始值類型如果是Int、String,Swift會默認分配其原始值
func enmuSourceValue() {
        
        enum DefaultIntEnum: String{
            case top, left, bottom, right
        }
        
        enum TypeSource: Int{
            case age = 18
            case birth = 19701010
            case idCard = 00000000000
        }
        //打印出原始值
        print(DefaultIntEnum.top.rawValue)
        print(DefaultIntEnum.top)
    }
  • 枚舉遞歸
  1. 遞歸枚舉類似於函數的遞歸,是枚舉內容本身調用枚舉本身
  2. 遞歸枚舉可以用來按層級存儲關聯數值,在使用的時候結合業務
  3. 一般使用遞歸函數配合來進行switch..case的判定
func indirectEnum() {
        enum AirthExpr {
        case number(Int)
        indirect case sum(AirthExpr, AirthExpr)
        indirect case difference(AirthExpr, AirthExpr)
        }
        
        func traverseEnum(airthNum: AirthExpr) -> Int {
            switch airthNum {
            case .number(let num): return num
            case let .sum(airthExpOne, airthExpTwo): return traverseEnum(airthNum: airthExpOne) + traverseEnum(airthNum: airthExpTwo)
            case let .difference(airthExpOne, airthExpTwo): return traverseEnum(airthNum: airthExpOne) - traverseEnum(airthNum: airthExpTwo)
            }
        }
        
        let five = AirthExpr.number(5)
        let four = AirthExpr.number(4)
        let sumAdd = AirthExpr.sum(five, four)
        let diffEnum = AirthExpr.difference(five, four)
        print("add result :\(traverseEnum(airthNum: sumAdd))")
        print("different result :\(traverseEnum(airthNum: diffEnum))")
    }
  • 可選類型
    聲明某個變量爲可選,直接在變量的類型後面添加?即可
    對於可選類型的變量或者常量,有兩種方式可以拿到其原始值:
    1. 強制解包
    2. 可選鏈操作

可選可以理解爲一層包裝盒子,盒子裏裝的是真實數據

  1. 如果爲nil,那麼它是一個空盒子
  2. 如果非nil,那麼盒子裝的就是被包裝的數據

!是強制解包的標識符,如果對nil的可選類型進行強制解包,將會產生運行時錯誤(Fatal error:...)

注意:
數組返回的數值不是可選類型的數值,因爲當數組越界的時候就已經發生崩潰,並不能拿到帶有歧義的數值(nil或者有數值),而字典獲取的數值爲可選數值

    func unwrappTypeUse() {
        var age: Int?
        //直接相加由於age是可選類型所以會報錯
//        age+=10
        //通過!來進行強制解包
        print(age!+=10)
    }
  • 解包之可選綁定
  1. 如果包含內容就自動解包,把可選內部包裝的值賦值給一個臨時變量 var 或者常量 let,並返回 true, 否則返回false
  2. 如果存在多個值,可選綁定可以通過逗號分開,注意不能使用&&分割
func unwrappingBindUse() {
        let num: Int? = 10
        let addTo: Int? = nil
        if let tmpNum = num,
           let _ = addTo{
            print("含有內容:\(tmpNum)")
        }   
    }
  • while 使用可選綁定
    /*
     while中使用可選綁定
     遍歷數組,將遇到的整數都加起來,如果遇到複數或者非數字,停止遍歷
     */
    func bindLetWhileLoop() {
        let strs = ["10", "20", "abc", "-20", "30"]
        var index = 0
        var sum = 0
        
        while let num = Int(strs[index]), num > 0 {
            sum += num
            index += 1
        }
        
        print("運算結果:\(sum)")
    }
  • 合併空運算符 ??
  1. 被修飾的是可選類型
  2. 合併的備選常量或者變量與被修飾的類型要保持一致
  3. 如果備選不是可選類型,返回的時候會自動進行解包操作

注意:
空合併運算符(??)是如何實現的?爲什麼在返回默認值的時候要使用閉包來實現,直接返回默認內容不可以嗎?
1. 包裝了一個函數裏面實現的public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
2. 內部實現使用了switch判定類似於以下的操作,使用運算符重載操作

運算符重載??實現可能如下:

    func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T{
        switch optional {
        case .some(let optional): return optional
        case .none: return try!defaultValue()
        }
    }

  • 多個空合併運算符??一起使用
    /*
     多個 ?? 一起使用
     */
    func mutiDefaultValueUse() {
        let a: Int? = 1
        let b: Int? = 2
        let c = a ?? b ?? 3 //c是Int,1
        
        let d: Int? = nil
        let e: Int? = 2
        let f = d ?? e ?? 3 //f是Int, 2
    }

  • ??if let配合使用
    /*
     ?? 與 if let 配合使用
     等同於 if a! = nil || n != nil
     */
    func defaultWithChooseBind() {
        let a: Int? = nil
        let b: Int? = 2
        if let c = a ?? b {
            print("result--->\(c)")
        }
    }
  • guard 語句
  1. guard語句條件爲false時,會執行大括號裏面的內容,否則正常執行
  2. guard時候提前過濾不滿足當前方法或者函數執行的條件
  3. 當使用guard語句進行可選綁定的時候,綁定的常量let、變量var也會在外層作用域使用
    func guardUseStatement(age: Int, level: Int) {
        guard age > 18, level > 50 else {
            print("未成年人禁止瀏覽")
            return
        }
        print("一起看動畫片啊~")
    }
  • 隱式解包
  1. 某些情況下,有些可選類型變量一開始設定就直接有值
  2. 在確定可選類型內容一直有值的情況下,可以通過在變量後面添加!的方法去除類型檢查
  3. 去除類型檢查之後,每次獲取的可選類型變量將會隱式進行解包取出其中包含的數值
    func unwrappingValueUse() {
        var num: Int! = 10
        var choose: Int? = 20
        print("隱式解包\(num)")
        print("強制解包\(choose!)")
    }
  • 字符串查值
 func strDesprint() {
        let age: Int? = 10
        print("age:\(age ?? 0)") //這樣打出來的內容是可選類型
        print("ageDes:\(String(describing: age))")
    }
  • 多重可選項
    多重可選項可以理解爲多重可選的包裝,在取值的時候需要格外注意,要分層取值。
    func moreUnwrappingValue() {
        let num: Int? = 10
        let userone: Int?? = 20 //被包裝了兩次,解包的時候需要解包兩次纔行
        let userTwo: Int??? = 30 //道理同上
        
        let numValue = num!
        let userOneValue = userone!!
        let userTwoValue = userTwo!!!
        print("當前內容:\(numValue), \(userOneValue), \(userTwoValue)")
        
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章