1.原来视图的架构:我们需要监听一个通知
父VC弹出一个子View,其中子View需要接收父VC发出的通知:
[父VC]--------弹出-------->[View]
[View]--------监听-------->[父VC]
由于View的特殊性,我们不能直接将监听回调放在View本身,而是要另外写一个类似协调器的东东:
class Coordinator {
let slaView:SLAView
init(_ slaView:SLAView){
self.slaView = slaView
}
@objc func volChanged(_ notify: NSNotification){
if let info = notify.userInfo as? [String:Float]{
let valString = String(format: "%.2f ", info["Vol"]!)
slaView.text += valString
}
}
}
下面是子View的代码:
@available(iOS 13.0, *)
struct SLAView: View {
@State var text = ""
/// 上面协调器类的定义在这里(省略之) ;)
weak var rcsMgr: RCSManager?
var dismiss: (()->Void)? = nil
@State private var _coordinator:Coordinator!
private var coordinator:Coordinator{
if _coordinator == nil{
_coordinator = Coordinator(self)
}
return _coordinator
}
var body: some View {
VStack {
/// 视图的内容,你不用操心哦 ;)
}.onAppear {
NotificationCenter.default.addObserver(self.coordinator, selector: #selector(Coordinator.volChanged(_:)), name: NSNotification.Name.VolumeDidChanged, object: nil)
}.onDisappear {
NotificationCenter.default.removeObserver(self)
}
}
}
看上去貌似很好,不过现在我们需要另外写一个其他功能的View,该View同样需要监听父VC发出的通知。
如果不对Views的代码进行重新组织,我们很快就会在Repeat Self可耻的路上越走越远了…
所以我们必须做出改变!!!
2.一个专用的监听View
现在我们把所需的监听功能统一放在一个单独的View中。
创建一个新的View: VolumeChangeListenerView
struct VolumeChangeListenerView<Content>: View where Content:View{
}
因为View的内容和对通知的处理需要由使用者决定,所以我们接下来在View定义中创建两个与之对应的闭包属性:
var content:()->Content
var volumeDidChanged:(Float)->()
我们现在可以把协调器的定义以及其对应的属性放在VolumeChangeListenerView里了,
只不过协调器中对于监听的处理需要略作修改,代码如下:
class Coordinator {
let view:VolumeChangeListenerView
init(_ view:VolumeChangeListenerView){
self.view = view
}
@objc func volChanged(_ notify: NSNotification){
if let info = notify.userInfo as? [String:Float]{
// 实际处理我们交给view来做
view.volumeDidChanged(info["Vol"]!)
}
}
}
现在到了最关键的body代码了,我们基本可以轻车熟路的这样写:
var body: some View {
content()
.onAppear {
NotificationCenter.default.addObserver(self.coordinator, selector: #selector(Coordinator.volChanged(_:)), name: NSNotification.Name.VolumeDidChanged, object: nil)
}.onDisappear {
NotificationCenter.default.removeObserver(self)
}
}
搞定!!!
3.重构原来的视图
现在我们有了新的VolumeChangeListenerView视图,我们可以将开头的SLAView重构如下:
struct SLAView: View {
@State var text = ""
weak var rcsMgr: RCSManager?
var dismiss: (()->Void)? = nil
var body: some View {
VolumeChangeListenerView(content: {
// 原来View中的显示内容在此,你同样不用操心哦 ;)
}){vol in
let valString = String(format: "%.2f ", vol)
self.text += valString
}
}
}
我们同样可以非常轻松的基于VolumeChangeListenerView,创建一个新功能的监听视图了:
struct SLAView2: View {
var body: some View {
VolumeChangeListenerView(content: {
// 显示内容在此,你还是不用操心哦 ;)
}){vol in
// 你想要对vol数据做神马都可以... ;)
}
}
}
好啦!这样我们之后无论再写多少个带有监听功能的不同View,都可以直接借助于VolumeChangeListenerView类了。这样简化了代码,消除了重复,你是不是值得拥有呢? 😉
4.结语
就一句话:其实偶尔重构一下挺好的!!!
转载:https://blog.csdn.net/mydo/article/details/103918874