一·单例Singleton
假设有一个用户设置的环境变量,需要给其他类使用的话我们可以把它变成单例
代码语言:javascript复制class Environment {
static let shared = Environment()
}
二·场景
当我们接收到一个 可以根据后端/北京时间来控制app的主题色有什么方法?
1.监听 2.代理 3.全局变量
现在我们来讨论第三种情况全局变量,这听起来有点不可思议。
1.定义环境变量里的设置类
代码语言:javascript复制class UserSetting {
var isBindingPhone = false
var phoneBindString: String {
if isBindingPhone {
return "已绑定手机"
}else {
return "未绑定手机"
}
}
}
Swift提供了一个Combine的功能,它可以使我们组合不同的框架使用包括UIKit跟SwiftUI
代码语言:javascript复制import Foundation
import Combine
import UIKit
现在我们需要把当前保存用户设置的环境变量添加上一个属性,它可以使其他类监听到属性的改变
现在环境变量需要有一个监听对象
代码语言:swift复制class UserSetting: ObservableObject {
var isBindingPhone = false
var phoneBindString: String {
if isBindingPhone {
return "已绑定手机"
}else {
return "未绑定手机"
}
}
}
class Environment {
static let updateChanged = Notification.Name("EnvironmentUpdate")
static let shared = Environment()
private var sinks = [AnyCancellable]()
var values = [Any]()
private init() {}
func register<T: ObservableObject>(_ value: T) { //由于我们规定 用户设置的类型为可监听的对象属性,所以传参必须也
value.append(value) //我们从所注册的类当中拿到改变的值,并储存在value数组里
let sink = value.objectWillChange.sink { _ in
DispatchQueue.mian.async{
//由于所发送的监听有可能会改变UI 所以需要从主线程当中发送
NotificationCenter.default.post(name: Self.updateChange, object: value)
//发送Self.updateChange 并带上 更改的值
}
}
sinks.append(sink)
}
}
protocol GlobalUpdating { //所注册的监听类需要实现update方法来完成所需要的逻辑操作
func updated()
}
extension GloablUpdating {
func registerForUpdates() {
//我们需要改变单个变量 而不是接收到监听改变所有
let mirror = Mirror(reflacting: self) //反射当前类
for child in mirror.children {
if let result = child.vallue as? AnyGlobal {
NotificationCenter.default.addObserve(forName:Environment.updateChanged,
object: result.anyWrappedValue, queue: .main, using: { _ in
self.update()
}
)
}
}
update()
}
}
@propertyWrapper struct Gloabl <ObjectiveType: ObservableObject>:AnyGlobal {
var wrappValue: ObjectiveType
var anyWrappedValue: Any {wrappValue}
inti() {
if let value = Environment.shared.values.first(where: {$0 is ObjectiveType}) as?
ObjectiveType {
self.wrappVlaue = value
}else { //如果找不到属性所对应的值 抛出异常
fatalError("MissingType in envrionment")
}
}
}
//最后代理协议还需要一个全局变量的修饰
protocol AnyGlobal {
var anyWrappedValue: Any { get }
}
明确一个目标我们需要监听的变化的值是需要储存下来的,意味着当前改变的变量是有可能持有引用状态,因为储存的是任何类型包括类,所以我们需要使用到Swfit提供的一个类型消除的结合 AnyCancellable 来确保不会出现引用状态,同时我们需要拿到从combine模块发来的notification ,并且保持combie是线程保活的。value数组能储存那些我们所改变的环境变量它有可能是int string color。然后我们还需要允许当前的环境单例 Environment 创建他们所独有的环境 例如AppSetting UserSetting PaySetting 等等。同时我们还需要提供一个注册方法,把它注册到你想要改变的类当中去