美文网首页
Swift类型属性、单例

Swift类型属性、单例

作者: BBLv | 来源:发表于2021-01-11 17:07 被阅读0次

    类型属性(Static)

    • 线程安全的
    • 全局的
    class LGTeacher {
       static var age: Int = 20
    }
    var age = LGTeacher.age
    

    在SIL角度来剖析一下原理:
    打开项目文件夹目录

    cd /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice

    把 mian.swift编译成main.sil并打开(推荐使用vs code)

    swiftc -emit-sil main.swift | xcrun swift-demangle >> ./main.sil && open main.sil
    No application knows how to open /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice/main.sil.

    class LGTeacher {
      @_hasStorage @_hasInitialValue static var age: Int { get set }
      @objc deinit
      init()
    }
    
    @_hasStorage @_hasInitialValue var age: Int { get set }
    
    // globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0
    sil_global private @globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0 : $Builtin.Word
    
    // static LGTeacher.age
    sil_global hidden @static main.LGTeacher.age : Swift.Int : $Int
    
    // age
    sil_global hidden @main.age : Swift.Int : $Int
    

    LGTeacher类型属性声明的过程中多了sil_Global

    // static LGTeacher.age
    sil_global hidden @static main.LGTeacher.age : Swift.Int : $Int

    这句话说明了当前声明的LGTeacher.age声明的类型属性变成了一个全局变量,变成了一个golbal,接下来再看在赋值的过程中做了什么事情

    // main
    sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
    bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
      alloc_global @main.age : Swift.Int                   // id: %2
      %3 = global_addr @main.age : Swift.Int : $*Int       // user: %9
      %4 = metatype $@thick LGTeacher.Type
      // function_ref LGTeacher.age.unsafeMutableAddressor
      %5 = function_ref @main.LGTeacher.age.unsafeMutableAddressor : Swift.Int : $@convention(thin) () -> Builtin.RawPointer // user: %6
      %6 = apply %5() : $@convention(thin) () -> Builtin.RawPointer // user: %7
      %7 = pointer_to_address %6 : $Builtin.RawPointer to [strict] $*Int // user: %8
      %8 = begin_access [read] [dynamic] %7 : $*Int   // users: %10, %9
      copy_addr %8 to [initialization] %3 : $*Int     // id: %9
      end_access %8 : $*Int                           // id: %10
      %11 = integer_literal $Builtin.Int32, 0         // user: %12
      %12 = struct $Int32 (%11 : $Builtin.Int32)      // user: %13
      return %12 : $Int32                             // id: %13
    } // end sil function 'main'
    

    第一点,当我去访问他的时候把%8给到了%3,%3是声明的全局age变量,%8是怎么来的,%8是在%6处调用了函数%5得来的,让我们去看@main.LGTeacher.age.unsafeMutableAddressor这个函数干了什么

    // LGTeacher.age.unsafeMutableAddressor
    sil hidden [global_init] @main.LGTeacher.age.unsafeMutableAddressor : Swift.Int : $@convention(thin) () -> Builtin.RawPointer {
    bb0:
      %0 = global_addr @globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0 : $*Builtin.Word // user: %1
      %1 = address_to_pointer %0 : $*Builtin.Word to $Builtin.RawPointer // user: %3
      // function_ref globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0
      %2 = function_ref @globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0 : $@convention(c) () -> () // user: %3
      %3 = builtin "once"(%1 : $Builtin.RawPointer, %2 : $@convention(c) () -> ()) : $()
      %4 = global_addr @static main.LGTeacher.age : Swift.Int : $*Int // user: %5
      %5 = address_to_pointer %4 : $*Int to $Builtin.RawPointer // user: %6
      return %5 : $Builtin.RawPointer                 // id: %6
    } // end sil function 'main.LGTeacher.age.unsafeMutableAddressor : Swift.Int'
    

    这这里里面它又执行了我们全局的方法@globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0,接着找到这个方法,

    // globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0
    sil private @globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0 : $@convention(c) () -> () {
    bb0:
      alloc_global @static main.LGTeacher.age : Swift.Int       // id: %0
      %1 = global_addr @static main.LGTeacher.age : Swift.Int : $*Int // user: %4
      %2 = integer_literal $Builtin.Int64, 20         // user: %3
      %3 = struct $Int (%2 : $Builtin.Int64)          // user: %4
      store %3 to %1 : $*Int                          // id: %4
      %5 = tuple ()                                   // user: %6
      return %5 : $()                                 // id: %6
    } // end sil function 'globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0'
    

    这个是全局的初始化方法,这个方法是为了初始化main.LGTeacher.age这个全局变量,把20赋值给了当前这个全局变量

    需要注意的是:

    在初始化的过程中,有一点的不一样,在@main.LGTeacher.age.unsafeMutableAddressor 这个方法内,出现了builtin "once"

    %3 = builtin "once"(%1 : Builtin.RawPointer, %2 :@convention(c) () -> ()) : $()

    如果通过断点调试,这个builtin "once",调用的是swift_once,打开swift源码找到Once.cpp会看到swift_once方法

    /// Runs the given function with the given context argument exactly once.
    /// The predicate argument must point to a global or static variable of static
    /// extent of type swift_once_t.
    void swift::swift_once(swift_once_t *predicate, void (*fn)(void *),
                           void *context) {
    #if defined(__APPLE__)
      dispatch_once_f(predicate, context, fn);
    #elif defined(__CYGWIN__)
      _swift_once_f(predicate, context, fn);
    #else
      std::call_once(*predicate, [fn, context]() { fn(context); });
    #endif
    }
    
    总结:

    看到这里就特别熟悉了,看到了GCD的dispatch_once_f,证明了static只会初始化age这个变量一次,所以在这个过程中,相比较lazy来说,static声明的类型属性有两个方式,他是一个全局的,并且他是线程安全的!

    swift单例

    在OC中的单例写法:

    #import "FFManager.h"
    
    @implementation FFManager
    
    + (instancetype)sharedInstance {
        static FFManager *sharedInstance = nil;
        static dispatch_once_t onceToken;
        
        dispatch_once(&onceToken, ^{
            sharedInstance = [[FFManager alloc]init];
        });
        return  sharedInstance;
    }
    
    @end
    

    在swift中的单例写法:

    class FFManager {
        static let sharedInstance: FFManager = FFManager()
        private init() {}
    }
    
    总结:

    第一在这个里面给sharedInstance一个全局状态,第二给初始化方法init添加了访问控制权限private,这样就完成了单例

    相关文章

      网友评论

          本文标题:Swift类型属性、单例

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