通过SIL理解Swift的属性与单例

类型属性(Static)

  • 线程安全的
  • 全局的
Swift 复制代码
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.

Swift 复制代码
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,接下来再看在赋值的过程中做了什么事情

Swift 复制代码
// 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这个函数干了什么

Swift 复制代码
// 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,接着找到这个方法,

Swift 复制代码
// 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 : <math xmlns="http://www.w3.org/1998/Math/MathML"> B u i l t i n . R a w P o i n t e r , Builtin.RawPointer, %2 : </math>Builtin.RawPointer,@convention(c) () -> ()) : $()

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

Swift 复制代码
/// 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中的单例写法:

Swift 复制代码
#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中的单例写法:

Swift 复制代码
class FFManager {
    static let sharedInstance: FFManager = FFManager()
    private init() {}
}

总结:

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

相关推荐
报错小能手3 小时前
ios开发方向——swift错误处理:do/try/catch、Result、throws
开发语言·学习·ios·swift
小夏子_riotous6 小时前
openstack的使用——5. Swift服务的基本使用
linux·运维·开发语言·分布式·云计算·openstack·swift
mCell10 小时前
MacOS 下实现 AI 操控电脑(Computer Use)的思考
macos·agent·swift
用户794572239541310 小时前
【DGCharts】iOS 图表渲染事实标准——8 种图表类型、高度可定制,3 行代码画出一条折线
swiftui·swift
chaoguo12341 天前
Any metadata 的内存布局
swift·metadata·value witness table
tangweiguo030519872 天前
SwiftUI布局完全指南:从入门到精通
ios·swift
用户79457223954132 天前
【RxSwift】Swift 版 ReactiveX,响应式编程优雅处理异步事件流
swift·rxswift
战族狼魂3 天前
XCode 发起视频 和 收到视频通话邀请实现双语功能 中文和俄语
swift
UXbot3 天前
2026年AI全链路产品开发工具对比:5款从创意到上线一站式平台深度解析
前端·ui·kotlin·软件构建·swift·原型模式
报错小能手3 天前
ios开发方向——swift并发进阶核心 @MainActor 与 DispatchQueue.main 解析
开发语言·ios·swift