You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:25:40