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)")
        
    }

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