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

iOS Swift:为UIViewController实现添加对象的协议方案咨询

最优方案:用协议扩展复用新增对象视图控制器的Done按钮逻辑

你的思路完全正确——用协议扩展来消除这类重复模板代码是非常合适的。我们只需要调整协议的定义方式,解决weak属性和Storyboard关联的问题,就能实现一次性编写、多VC复用的目标。

核心问题分析

你遇到的主要问题是Swift协议无法直接声明weak属性,但IBOutlet要求属性必须是weak的。不过这个问题很好解决:协议只需要约定属性的存在和类型,具体的weak修饰交给视图控制器的IBOutlet属性来处理即可。

完整实现方案

1. 定义协议与扩展

我们先完善AddingHandler协议,同时在扩展中实现通用的配置逻辑和默认的按钮点击行为:

import UIKit

// 协议要求遵守者是UIViewController,确保能使用导航栏、dismiss等方法
protocol AddingHandler: UIViewController {
    var doneButton: UIBarButtonItem? { get set }
    func doneButtonPressed()
}

extension AddingHandler {
    // 通用的Done按钮配置方法
    func configureDoneButton() {
        guard let doneButton = doneButton else {
            print("Warning: Done button not connected in Storyboard!")
            return
        }
        doneButton.isEnabled = false
        doneButton.target = self
        doneButton.action = #selector(doneButtonPressed)
    }
    
    // 默认的Done按钮点击行为,子类可重写
    @objc func doneButtonPressed() {
        dismiss(animated: true, completion: nil)
    }
    
    // 通用的按钮状态更新方法,子类直接调用即可
    func updateDoneButtonEnabled(_ enabled: Bool) {
        doneButton?.isEnabled = enabled
    }
}

2. 在视图控制器中使用

现在任何需要新增对象的VC都可以快速接入这个逻辑,只需要3步:

  • 遵守AddingHandler协议
  • 关联Storyboard中的Done按钮为weak IBOutlet
  • 在viewDidLoad中调用配置方法
class AddContactViewController: UIViewController, AddingHandler {
    // 用weak修饰IBOutlet,符合Storyboard关联要求
    @IBOutlet weak var doneButton: UIBarButtonItem?
    
    // 示例:输入框监听,用来判断是否满足启用按钮的条件
    @IBOutlet weak var nameTextField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureDoneButton() // 调用协议扩展的配置方法
        
        // 监听输入变化,更新按钮状态
        nameTextField.addTarget(self, action: #selector(checkInputValidity), for: .editingChanged)
    }
    
    // 自定义的Done按钮行为,重写默认实现
    @objc func doneButtonPressed() {
        guard let name = nameTextField.text, !name.isEmpty else { return }
        // 执行新增联系人的业务逻辑...
        print("新增联系人:\(name)")
        
        // 调用默认的dismiss逻辑
        super.doneButtonPressed()
    }
    
    // 检查输入有效性,更新按钮状态
    @objc private func checkInputValidity() {
        let isInputValid = !(nameTextField.text?.isEmpty ?? true)
        updateDoneButtonEnabled(isInputValid) // 调用协议扩展的状态更新方法
    }
}

关键细节说明

  • Weak属性处理:协议不强制属性的引用类型,VC中的IBOutlet用weak修饰即可满足内存管理要求,协议只关心属性的存在性。
  • 安全防护:configureDoneButton中加入guard let检查,避免因Storyboard未关联按钮导致的崩溃,同时给出警告提示。
  • 灵活性:默认的doneButtonPressed实现提供了通用的dismiss逻辑,子类可按需重写;updateDoneButtonEnabled封装了按钮状态更新,子类无需直接操作按钮。
  • 复用性:所有新增对象的VC(比如AddProductViewController、AddTaskViewController等)都可以直接套用这个模式,无需重复编写配置代码。

内容的提问来源于stack exchange,提问作者ajrlewis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:04:02