类型特点(Static)

class FFHobbyGirls {
   static var age: Int = 20
}
var age = FFHobbyGirls.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 FFHobbyGirls {
  @_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 FFHobbyGirls.age
sil_global hidden @static main.FFHobbyGirls.age : Swift.Int : $Int
// age
sil_global hidden @main.age : Swift.Int : $Int

FFHobbyGirls类型特点声明的过程中多了sil_Global

tatic FFHobbyGirls.age
sil_global hidden @static main.FFHobbyGirls.age : Swift.Int : $Int

这句话说明了当时声明的FFHobbyGirls.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 FFHobbyGirls.Type
  // function_ref FFHobbyGirls.age.unsafeMutableAddressor
  %5 = function_ref @main.FFHobbyGirls.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.FFHobbyGirls.age.unsafeMutableAddressor这个函数干了什么

// FFHobbyGirls.age.unsafeMutableAddressor
sil hidden [global_init] @main.FFHobbyGirls.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.FFHobbyGirls.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.FFHobbyGirls.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.FFHobbyGirls.age : Swift.Int       // id: %0
  %1 = global_addr @static main.FFHobbyGirls.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.FFHobbyGirls.age这个大局变量,把20赋值给了当时这个大局变量

需要注意的是:

在初始化的过程中,有一点的不一样,在@main.FFHobbyGirls.age.unsafeMutableAddressor 这个办法内,呈现了builtin “once”

%3 = builtin “once”(%1 : Builtin.RawPointer,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,这样就完成了单例