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

Swift调用函数时Delegate变量始终为nil的问题排查

问题:调用reconcile()时selectedTransaction始终为nil

我实现了Delegate模式处理对账逻辑,但调用reconcile()函数时selectedTransaction始终返回nil。子视图的onChange回调中能正确打印选中的交易数据,但父视图通过按钮触发调用时,该值就变成了nil。

相关代码如下:

Delegate实现类

class MatchReconciliationViewState: ReconciliationDelegate {
    var selectedTransaction: Transaction?
    let statementLine: StatementLine
    
    init(selectedTransaction: Transaction? = nil, statementLine: StatementLine) {
        self.selectedTransaction = selectedTransaction
        self.statementLine = statementLine
    }
    
    func canReconcile() -> Bool {
        return nil != selectedTransaction
    }
    
    func reconcile() {
        print("reconcile: \(String(describing: selectedTransaction))")
        guard let selectedTransaction = selectedTransaction else { return }
        
        ReconciliationFunctions.match(statementLine: statementLine, toTransaction: selectedTransaction)
    }
}

子视图onChange回调(数据持有正常)

.onChange(of: selectedTransaction) { newValue in
    print("onChange: \(String(describing: selectedTransaction))")
    reconciliationDelegate.selectedTransaction = newValue
    parentState.canReconcile = reconciliationDelegate.canReconcile()
    print("onChangeDelegate: \(String(describing: reconciliationDelegate.selectedTransaction))")
}

父视图触发代码(调用时selectedTransaction为nil)

private func reconcileStatementLine() {
    print("delegate: \(String(describing: state.reconciliationDeleage))")
    state.reconciliationDeleage?.reconcile()
//        persistence.commit()
//        presentationMode.wrappedValue.dismiss()
}

协议定义

public protocol ReconciliationDelegate: AnyObject {
    func canReconcile() -> Bool
    func reconcile()
}

父视图及状态类

// 父视图代码
@StateObject var state: ReconciliationViewState

var body: some View {
    Button(action: reconcileStatementLine) {
        Text("Reconcile")
    }
}

private func reconcileStatementLine() {
    print("delegate: \(String(describing: state.reconciliationDeleage))")
    state.reconciliationDeleage?.reconcile()
//        persistence.commit()
//        presentationMode.wrappedValue.dismiss()
}
// 持有Delegate的状态类
class ReconciliationViewState: ObservableObject {
    var reconciliationDeleage: ReconciliationDelegate? = nil
}

问题原因及解决方案

核心问题:拼写错误+实例不统一

  1. 致命拼写错误:代码中存在属性名拼写不一致——reconciliationDeleage(少了一个字母t)和reconciliationDelegate。这直接导致父视图操作的Delegate属性,和子视图中修改的Delegate属性不是同一个,自然无法同步数据。
  2. 实例不共享:如果子视图和父视图使用的是不同的MatchReconciliationViewState实例,即使拼写正确,也会出现数据不同步的情况。

修复步骤

  1. 统一属性名拼写
    把所有reconciliationDeleage修正为reconciliationDelegate:

    • 修正状态类:
      class ReconciliationViewState: ObservableObject {
          var reconciliationDelegate: ReconciliationDelegate? = nil
      }
      
    • 修正父视图调用代码:
      private func reconcileStatementLine() {
          print("delegate: \(String(describing: state.reconciliationDelegate))")
          state.reconciliationDelegate?.reconcile()
      }
      
  2. 确保Delegate实例唯一共享
    在初始化子视图时,直接传入父视图状态中的reconciliationDelegate实例,避免创建新的对象:

    ChildView(
        reconciliationDelegate: state.reconciliationDelegate,
        parentState: state
    )
    
  3. 提前初始化Delegate实例
    在ReconciliationViewState的初始化方法中创建Delegate实例,确保使用前已存在:

    class ReconciliationViewState: ObservableObject {
        var reconciliationDelegate: ReconciliationDelegate?
        
        init(statementLine: StatementLine) {
            self.reconciliationDelegate = MatchReconciliationViewState(statementLine: statementLine)
        }
    }
    

验证要点

修复后,可通过以下方式确认问题解决:

  • 打印state.reconciliationDelegate和子视图的reconciliationDelegate内存地址,确认是同一个实例
  • 子视图选中交易后,打印state.reconciliationDelegate?.selectedTransaction,确认值已同步
  • 点击父视图按钮时,reconcile()方法中打印的selectedTransaction不为nil

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 18:23:11