Swift中如何通过协议直接修改代理的嵌套属性?
直接修改同VC内视图属性的优雅实现
嘿,我完全懂你想要的那种“更直接不啰嗦”的实现——毕竟两个视图都在同一个ViewController里,用代理确实有点绕,直接操作属性反而更清爽。
先说说你提到的那个协议属性的疑问:那个问题里的场景大概率是跨ViewController或者视图层级独立的情况,所以需要用协议来抽象依赖、解耦代码。但咱们现在的情况是两个视图同属一个VC,完全可以跳过代理那套,用更简单的方式实现。
具体怎么做?
核心思路是给controllingView加一个对presentingView的弱引用(一定要弱引用,不然容易造成循环引用),然后直接在controllingView里修改目标属性。举个代码例子:
首先定义PresentingView,它有一个带子属性的目标属性:
class PresentingView: UIView { // 假设这个是带子属性的目标属性 struct DisplayConfig { var title: String var subtitle: String } var displayConfig = DisplayConfig(title: "默认标题", subtitle: "默认副标题") // 配置UI的方法,属性变化时更新界面 func updateUI() { // 根据displayConfig更新标签文字等UI元素 } }
然后是ControllingView,它持有presentingView的弱引用:
class ControllingView: UIView { // 弱引用避免循环引用——因为两个视图都被VC持有强引用 weak var targetPresentingView: PresentingView? // 比如一个按钮点击事件,触发修改属性的操作 @objc func modifyPresentingViewProperty() { guard let presentingView = targetPresentingView else { return } // 直接修改属性及其子属性 presentingView.displayConfig.title = "修改后的标题" presentingView.displayConfig.subtitle = "修改后的副标题" // 调用presentingView的UI更新方法 presentingView.updateUI() } }
最后在ViewController里初始化并关联两个视图:
class MainViewController: UIViewController { lazy var presentingView: PresentingView = { let view = PresentingView() view.frame = CGRect(x: 50, y: 100, width: 300, height: 100) view.backgroundColor = .lightGray return view }() lazy var controllingView: ControllingView = { let view = ControllingView() view.frame = CGRect(x: 50, y: 250, width: 300, height: 50) view.backgroundColor = .blue // 关联presentingView view.targetPresentingView = presentingView // 添加触发按钮 let button = UIButton(frame: view.bounds) button.setTitle("修改属性", for: .normal) button.addTarget(view, action: #selector(view.modifyPresentingViewProperty), for: .touchUpInside) view.addSubview(button) return view }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(presentingView) view.addSubview(controllingView) } }
为什么这比代理更优雅?
- 省去了定义代理协议、声明代理属性、实现代理方法的一堆模板代码,代码量更少
- 逻辑更直观:谁要修改谁,直接持有引用操作即可,不需要通过中间代理方法传递数据
- 灵活性更高:你可以直接修改任何属性,不需要提前在代理协议里定义对应的方法
关键注意点
- 必须用
weak引用presentingView,因为MainViewController已经对两个视图持有强引用,如果controllingView再强引用presentingView,就会形成循环引用导致内存泄漏 - 如果
presentingView可能被提前释放,一定要加guard let或者可选绑定,避免空指针崩溃
内容的提问来源于stack exchange,提问作者Marmelador
相关产品推荐
相关产品推荐

