類型屬性(Static)
- 線程安全的
- 全局的
class LGTeacher {
static var age: Int = 20
}
var age = LGTeacher.age
在SIL角度來剖析一下原理:
打開項(xiàng)目文件夾目錄
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
這句話說明了當(dāng)前聲明的LGTeacher.age聲明的類型屬性變成了一個(gè)全局變量准验,變成了一個(gè)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'
第一點(diǎn)蛉加,當(dāng)我去訪問他的時(shí)候把%8給到了%3同衣,%3是聲明的全局age變量竟块,%8是怎么來的,%8是在%6處調(diào)用了函數(shù)%5得來的耐齐,讓我們?nèi)タ碄main.LGTeacher.age.unsafeMutableAddressor這個(gè)函數(shù)干了什么
// 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'
這這里里面它又執(zhí)行了我們?nèi)值姆椒ˊglobalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0浪秘,接著找到這個(gè)方法蒋情,
// 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'
這個(gè)是全局的初始化方法,這個(gè)方法是為了初始化main.LGTeacher.age這個(gè)全局變量耸携,把20賦值給了當(dāng)前這個(gè)全局變量
需要注意的是:
在初始化的過程中棵癣,有一點(diǎn)的不一樣,在@main.LGTeacher.age.unsafeMutableAddressor 這個(gè)方法內(nèi)夺衍,出現(xiàn)了builtin "once"
%3 = builtin "once"(%1 :
@convention(c) () -> ()) : $()
如果通過斷點(diǎn)調(diào)試狈谊,這個(gè)builtin "once",調(diào)用的是swift_once,打開swift源碼找到Once.cpp會(huì)看到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
}
總結(jié):
看到這里就特別熟悉了沟沙,看到了GCD的dispatch_once_f河劝,證明了static只會(huì)初始化age這個(gè)變量一次,所以在這個(gè)過程中矛紫,相比較lazy來說赎瞎,static聲明的類型屬性有兩個(gè)方式,他是一個(gè)全局的颊咬,并且他是線程安全的煎娇!
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() {}
}
總結(jié):
第一在這個(gè)里面給sharedInstance一個(gè)全局狀態(tài),第二給初始化方法init添加了訪問控制權(quán)限private贪染,這樣就完成了單例