美文网首页
Swift基础:2-Swift常用关键字

Swift基础:2-Swift常用关键字

作者: 黑色幽默_0d96 | 来源:发表于2024-02-26 16:16 被阅读0次

    var、let

    var声明变量,表示变量可修改,如var a = 3,可以对a进行修改,a=4

    let声明变量,表示变量不可修改,如let a = 3,那么就不可以对a进行修改(a=4报错)

    简单来说,var表示这个变量,可以指向新的内存地址,而let,则不能指向新的内存地址

    staic、class、final

    static修饰的方法,变量,表示静态方法、变量,可以用于结构体、协议、类中,而在类中使用时,它和它的子类共享,但是不能被子类重写

    class修饰的方法,变量,表示类方法、变量,只能用在类中,子类可以重写;

    需要注意的是,class通常修饰方法,如果修饰变量的话,只能是计算型变量。

    final关键字在大多数的编程语言中都存在,表示不允许对其修饰的内容进行继承或者重新操作。Swift中,final关键字可以在class、func和var前修饰。

    defer

    1、defer语句在代码块(方法、闭包等,可以理解为大括号包装起来的代码)作用域退出之前执行,也就是代码块中其他应该执行的代码都执行完了,才执行defer中的代码

    2、一个代码块允许多个defer,多个defer执行的顺序 从后到前

    3、defer 语句块中的代码, 会在当前作用域结束前调用, 常用场景如异常退出后, 关闭数据库连接

    4、需要注意的是, 如果有多个 defer, 那么后加入的先执行

    func someQuery() -> ([Result], [Result]){
       let db = DBOpen("xxx")
       defer {
           db.close()
       }
       guard results1 = db.query("query1") else {
           return nil
       }
       guard results2 = db.query("query2") else {
           return nil
       }
       return (results1, results2)
    }</pre>
    
    //需要注意的是, 如果有多个 defer, 那么后加入的先执行
    
    func someDeferFunction() {
       defer {
           print("\(#function)-end-1-1")
           print("\(#function)-end-1-2")
      }
       defer {
           print("\(#function)-end-2-1")
           print("\(#function)-end-2-2")
      }
       if true {
           defer {
               print("if defer")
          }
           print("if end")
      }
       print("function end")
    }
    someDeferFunction()
    // 输出
    // if end
    // if defer
    // function end
    // someDeferFunction()-end-2-1
    // someDeferFunction()-end-2-2
    // someDeferFunction()-end-1-1
    // someDeferFunction()-end-1-2</pre>
    

    dynamic

    由于 swift 是一个静态语言, 所以没有 Objective-C 中的消息发送这些动态机制, dynamic 的作用就是让 swift 代码也能有 Objective-C 中的动态机制, 常用的地方就是 KVO 了, 如果要监控一个属性, 则必须要标记为 dynamic

    typealias

    给一个类型取别名,例

    public typealias RxTime = Date

    用于协议中定义了泛型时,在实际使用的时候,需要给这个泛型确定一个真实类型

    associatedtype

    简单来说就是 protocol 使用的泛型,一般联合typealias使用

    protocol ListProtcol {
       associatedtype Element
       func push(_ element:Element)
       func pop(_ element:Element) -> Element?
    }
    

    实现协议的时候, 可以使用 typealias 指定为特定的类型, 也可以自动推断, 如

    class IntList: ListProtcol {
       typealias Element = Int // 使用 typealias 指定为 Int
       var list = [Element]()
       func push(_ element: Element) {
           self.list.append(element)
       }
       func pop(_ element: Element) -> Element? {
           return self.list.popLast()
       }
    }
    class DoubleList: ListProtcol {
       var list = [Double]()
       func push(_ element: Double) {// 自动推断
           self.list.append(element)
       }
       func pop(_ element: Double) -> Double? {
           return self.list.popLast()
       }
    }
    

    where

    可以限定泛型的类

    where语句在if中使用时,在swift4及以后,被,代替

    extension ListProtcol where Element == Int {
      func isInt() ->Bool {
          return true
      }
    }
    

    case

    case可在if、switch语句中使用

    //case 不只是在switch中使用
    //注意,where语句在if中使用时,在swift4及以后,被,代替
    /*
    if 中使用case,where
    */
    let tempInt = 23
    if case 10...30 = tempInt{
      print("if case")
    }
    
    if case 10...30 = tempInt, tempInt<25{
      print("if case where")
    }
    
    if tempInt<30,tempInt>20{
      print("if where")
    }
    
    /*
    switch 中使用where
    */
    let pointTemp = (10,20)
    switch pointTemp {
    case (let x,let y) where x == y/2 :
      print ("switch中使用where")
    default:
      print("default")
    }
    
    /*
    for in中使用where、case
    */
    for i in 1..<20 where I>10{
      print("for in中使用where,i = \(i)")
    }
    
    for case let i in 1..<20 where I>10{
      print("for in中使用case where,i = \(i)")
    }
    

    guard

    guard,保证符合条件,否则怎样(guard关键字,需要return或者throw配合使用,所以一般必须在函数体中使用)

    func testGuard(x:Int?)->(){
      guard let testGuardTemp = x,testGuardTemp>20 else {
          print("guard的用法")
          return
      }
      print("guard的用法:",testGuardTemp)
      return
    }
    testGuard(x:nil)
    testGuard(x: 23)
    
    //guard与if的区别,在于guard中进行可选型解包而声明的变量,能在方法体内下继续使用,if则只能在if体内使用
    

    guard 和 if 类似, 不同的是, guard 总是有一个 else 语句, 如果表达式是假或者值绑定失败的时候, 会执行 else 语句, 且在 else 语句中一定要停止函数调用 例如

    guard 1 + 1 == 2 else {
       fatalError("something wrong")
    }
    

    常用使用场景为, 用户登录的时候, 验证用户是否有输入用户名密码等

    guard let userName = self.userNameTextField.text,
     let password = self.passwordTextField.text else {
       return
    }
    

    inout

    输入输出参数, 如:

    func swap( a: inout Int, b: inout Int) {
       let temp = a
       a = b
       b = temp
    }
    var a = 1
    var b = 2
    print(a, b)// 1 2
    swap(a: &a, b: &b)
    print(a, b)// 2 1</pre>
    

    weak、unowned

    两者都是弱引用,都只能使用在类实例上面

    weak修饰的变量,对象释放后自动置为nil(因此被标记为 @weak 的变量一定需要是 Optional 值)

    weak弱引用多用于通常的解决循环引用问题场景。

    unowned修饰的变量,对象释放后不会自动置为nil,仍然保留释放对象的地址,所以可能发生野指针问题

    unowned无主引用用于一个属性允许设置为 nil,而另一个属性不允许设置为 nil,并会造成潜在的强引用循环的场景。

    从安全角度来说,weak优于unowned,但是从性能上说,unowned优于weak(weak的实质是对unowned的封装,包裹了一个可选值)

    1、Unowned和Weak的使用时机

    Unowned一般使用在其所修饰的对象和所处的block环境的生命周期一致的时候。 简单来说,Unowned修饰的对象,在整个block的使用期间都应该是有效的,即不可为nil。

    Weak则可以使用为block 的生命周期超出其对象进行修饰。 意思是可以修饰可能变成nil的对象。用Swift中的话语来说就是Optional对象。

    相比之下,weak的使用范围更加广泛,如果不考虑性能的话,我们大可以无论什么情况都使用weak将会更加安全。然而,既然Unowned存在,必将有他的意义 —— 出于性能考虑,我们应该在可以使用Unowned的时候尽可能的使用Unowned,具体原因请往下看。

    2、Unowned 比Weak的开销更小

    Swift 中的每个对象保持了两个引用计数器,一个是强引用计数器,用来决定 ARC 什么时候可以安全地析构这个对象,另外一个附加的弱引用计数器,用来计算创建了多少个指向这个对象的 unowned 或者 weak 引用,当这个计数器为零时,这个对象将被析构 。

    弱引用计数器在增加之前(这是一个原子操作),会事先检查一个对象的强引用计数器的值,当值大于0的时候,才确保这是有效的。不然我们访问一个无效的值将会引起程序运行时报错从而导致崩溃。

    Unowned 在编译的时候,进行了优化,它不会对有效只进行辨别:如果其引用的对象是一个有效值,它将会顺利在弱引用计数器原本的基础之上加1。如果是一个无效的值,那它将指向一个垃圾内存中的地址,在运行的时候,这将会产生错误,这就是为什么我们需要在使用Unowned时候,要保证对象生命周期的有效性。

    Weak针对Unowned 进行了包装(光凭这一点,Unowned 在性能上优于Weak)。Swift 的 weak 引用添加了附加层,间接地把 unowned 引用包裹到了一个可选容器里面,会对可选值进行相应的处理,这将带来一定的开销。所以尽管我们给一个nil对象添加Weak 修饰,程序运行中,依旧不会报错。

    这里的性能对比,验证了上面所说的,我们应该在对象的生命周期允许的情况下,尽量使用Unowned 。

    _

    "_"在swift中有特殊的意义,一般使用来,用于占位进行忽略.

    (1)函数参数名忽略;

    (2)10_000(跟10000一样,但是加_后更易读)

    mutating :

    struct 和 class 的差別是 struct 的 function 要去改变 property 的值的时候要加上 mutating,而 class 不用。

    throws 、 rethrows

    throws 用在函数上, 表示这个函数会抛出错误. 有两种情况会抛出错误, 一种是直接使用 throw 抛出, 另一种是调用其他抛出异常的函数时, 直接使用 try xx 没有处理异常. 如

    enum DivideError: Error {
       case EqualZeroError;
    }
    func divide(_ a: Double, _ b: Double) throws -> Double {
       guard b != Double(0) else {
           throw DivideError.EqualZeroError
       }
       return a / b
    }
    func split(pieces: Int) throws -> Double {
       return try divide(1, Double(pieces))
    }
    

    rethrows 与 throws 类似, 不过只适用于参数中有函数, 且函数会抛出异常的情况, rethrows 可以用 throws 替换, 反过来不行 如

     rethrows -> Double {
       return try function(a, b)
    }
    

    try? 、 try!、try

    用于处理可抛出异常的函数。
    try需要配合do catch使用。
    try? 、 try!, 使用这两个关键字可以不用写 do catch.
    区别在于, try? 在用于处理可抛出异常函数时, 如果函数抛出异常, 则返回 nil, 否则返回函数返回值的可选值, 如:

    print(try? divide(2, 1))
    // Optional(2.0)
    print(try? divide(2, 0))
    // nil
    

    而 try! 则在函数抛出异常的时候崩溃, 否则则返会函数返回值, 相当于(try? xxx)!, 如:

    print(try! divide(2, 1))
    // 2.0
    print(try! divide(2, 0))
    // 崩溃
    

    访问控制相关关键字(public等)

    open > public > internal > fileprivate > private
    open:在其他模块(命名空间)内使用可被访问、继承、重写
    public:在其他模块内只能被访问,不能被继承
    internal:仅在自身模块中能访问、继承、重写
    fileprivate:当前文件内访问
    private: 当前作用域内访问

    其他关键字

    相关文章

      网友评论

          本文标题:Swift基础:2-Swift常用关键字

          本文链接:https://www.haomeiwen.com/subject/jecaudtx.html