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

多UIViewController数据依赖对象构建的设计模式方案

在嵌套UINavigationController的多VC场景下构建依赖数据的对象(机票Demo示例)

咱们来聊聊在多个嵌入UINavigationController的UIViewController场景里,怎么构建一个依赖这些控制器数据的对象——拿一个简化的机票购买Demo来举例,一看就懂。

首先先定义核心的Ticket结构体,它的字段分别由不同的VC提供数据:

struct Ticket {
    let originAirport: Airport    // 由UIViewController 1提供数据
    let destinationAirport: Airport // 由UIViewController 1提供数据
    let departureDate: Date       // 由UIViewController 2提供数据
    let returnDate: Date?         // 由UIViewController 2提供数据(可选,对应单程/往返)
    let passengerCount: Int       // 由UIViewController 3提供数据
    let cabinClass: CabinClass    // 由UIViewController 3提供数据
}

// 补充依赖的枚举定义
enum Airport: String {
    case PEK, SHA, CAN, SZX // 简化示例,代表国内主要机场
}

enum CabinClass: String {
    case economy, business, first
}

核心思路:用共享数据容器逐步填充

直接让每个VC各自持有部分数据再最后拼接太零散,咱们可以搞一个共享的临时数据容器,让所有参与流程的VC都能访问并更新这个容器,最后在流程收尾时组装成完整的Ticket对象。

1. 创建可变的临时数据草稿类

先做一个可以逐步填充的草稿类,还得加验证和组装逻辑:

class TicketDraft {
    var originAirport: Airport?
    var destinationAirport: Airport?
    var departureDate: Date?
    var returnDate: Date?
    var passengerCount: Int?
    var cabinClass: CabinClass?
    
    // 检查是否具备生成完整Ticket的条件
    func canBuildTicket() -> Bool {
        return originAirport != nil && destinationAirport != nil && departureDate != nil && passengerCount != nil && cabinClass != nil
    }
    
    // 组装成最终Ticket,失败则抛出错误
    func buildTicket() throws -> Ticket {
        guard let origin = originAirport,
              let dest = destinationAirport,
              let depDate = departureDate,
              let paxCount = passengerCount,
              let cabin = cabinClass else {
            throw TicketError.incompleteData
        }
        return Ticket(originAirport: origin,
                      destinationAirport: dest,
                      departureDate: depDate,
                      returnDate: returnDate,
                      passengerCount: paxCount,
                      cabinClass: cabin)
    }
    
    enum TicketError: Error {
        case incompleteData
    }
}

2. 在导航流程中传递草稿容器

启动购票流程时,先初始化草稿实例,然后把它传递给第一个VC:

// 假设从首页跳转进入购票流程
let ticketDraft = TicketDraft()
let firstVC = AirportSelectionViewController(draft: ticketDraft)
let navController = UINavigationController(rootViewController: firstVC)
present(navController, animated: true)

每个VC持有草稿的引用,用户完成输入后直接更新对应字段,再跳转到下一个VC时继续传递草稿:

class AirportSelectionViewController: UIViewController {
    private let ticketDraft: TicketDraft
    
    init(draft: TicketDraft) {
        self.ticketDraft = draft
        super.init(nibName: nil, bundle: nil)
    }
    
    // 用户选好出发/到达机场后的回调
    func onAirportsSelected(origin: Airport, dest: Airport) {
        ticketDraft.originAirport = origin
        ticketDraft.destinationAirport = dest
        // 跳转到日期选择VC,继续传递草稿
        let dateVC = DateSelectionViewController(draft: ticketDraft)
        navigationController?.pushViewController(dateVC, animated: true)
    }
}

3. 最终组装完整Ticket

当最后一个VC完成用户输入后,调用草稿的buildTicket()方法生成完整对象:

class PassengerSelectionViewController: UIViewController {
    private let ticketDraft: TicketDraft
    
    init(draft: TicketDraft) {
        self.ticketDraft = draft
        super.init(nibName: nil, bundle: nil)
    }
    
    // 用户点击确认按钮的逻辑
    func onConfirmButtonTapped() {
        do {
            let finalTicket = try ticketDraft.buildTicket()
            // 这里可以发起购票请求、跳转到订单确认页等
            print("成功生成机票订单:\(finalTicket)")
        } catch {
            // 处理数据不完整的情况,比如弹出提示
            let alert = UIAlertController(title: "提示", message: "请完善所有必填信息", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "确定", style: .default))
            present(alert, animated: true)
        }
    }
}

额外优化小建议

  • 如果不想让VC直接持有草稿,可以用闭包回调的方式,让每个VC只负责收集自己的输入,通过回调把数据传递给上层,最后在导航根VC或者专门的协调器里组装。
  • 对于更复杂的流程,推荐用Coordinator模式,把导航逻辑和数据组装逻辑从VC里剥离出来,让VC只专注于UI展示和用户交互,代码会更清晰易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:15:37