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

Swift中如何在初始化后通过委托模式实现类间正确数据传递?

问题描述

我正在测试在初始化器中使用委托模式,以下是数据供应测试类及其数据源的代码:

protocol MyClassDataSource : AnyObject{
    func returnString(string: String)
}

protocol MyClassProtocol: AnyObject {
    var dataSource : MyClassDataSource? { get set }
}

class MyClass : MyClassProtocol {
    weak var dataSource: MyClassDataSource?
    
    init() {
        print("1. My Class initialized")
        getString()
    }

    func getString() {
        let myString = "Hello World"
        print("3. The getString func run")
        dataSource?.returnString(string: myString)
    }
}

接收数据的OtherClass代码如下:

class OtherClass : MyClassDataSource {
    
    weak var myClass : MyClassProtocol?
    
    init(myClass: MyClassProtocol?) {
        self.myClass = myClass
        self.myClass?.dataSource = self
        print("2. MyClass delegate set")
    }
    
    func returnString(string: String) {
        print("4. Delegate run and print the string: \(string)")
    }
}

初始化代码为:

let myClass = MyClass()
let otherClass = OtherClass(myClass: myClass)

我希望通过初始化类完成委托设置并实现MyClass向OtherClass传递数据,期望控制台打印顺序为:

  1. My Class initialized
  2. MyClass delegate set
  3. The getString() func run
  4. DataSource run in OtherClass and print the string: Hello World

但实际getString()在委托设置前执行,打印顺序不符。仅通过延迟执行getString()可正常运行,请问如何仅通过初始化类实现该需求?

解决方案

核心问题是MyClass初始化时立刻调用了getString(),但此时OtherClass还未创建,委托没有绑定机会。要在初始化阶段完成委托绑定后再触发数据传递,可通过调整初始化逻辑实现,以下是两种可行方案:

方案一:给MyClass添加带数据源参数的初始化方法

直接在MyClass初始化时传入数据源,确保绑定完成后再调用getString():

protocol MyClassDataSource : AnyObject{
    func returnString(string: String)
}

protocol MyClassProtocol: AnyObject {
    var dataSource : MyClassDataSource? { get set }
    func getString()
}

class MyClass : MyClassProtocol {
    weak var dataSource: MyClassDataSource?
    
    // 新增带数据源参数的初始化方法
    init(dataSource: MyClassDataSource?) {
        self.dataSource = dataSource
        print("1. My Class initialized")
        getString()
    }

    func getString() {
        let myString = "Hello World"
        print("3. The getString func run")
        dataSource?.returnString(string: myString)
    }
}

// 调整OtherClass的初始化逻辑
class OtherClass : MyClassDataSource {
    
    weak var myClass : MyClassProtocol?
    
    init() {
        // 先创建MyClass并传入自身作为数据源
        self.myClass = MyClass(dataSource: self)
        print("2. MyClass delegate set")
    }
    
    func returnString(string: String) {
        print("4. Delegate run and print the string: \(string)")
    }
}

// 初始化代码简化为
let otherClass = OtherClass()

执行后打印顺序完全符合预期:

  1. My Class initialized
  2. MyClass delegate set
  3. The getString func run
  4. Delegate run and print the string: Hello World

方案二:利用didSet监听数据源变化

如果不想修改初始化方法,给dataSource添加didSet回调,当委托设置完成后自动触发getString():

class MyClass : MyClassProtocol {
    weak var dataSource: MyClassDataSource? {
        didSet {
            // 数据源绑定完成后调用getString()
            getString()
        }
    }
    
    init() {
        print("1. My Class initialized")
        // 移除初始化时的getString()调用
    }

    func getString() {
        let myString = "Hello World"
        print("3. The getString func run")
        dataSource?.returnString(string: myString)
    }
}

// 初始化代码保持不变
let myClass = MyClass()
let otherClass = OtherClass(myClass: myClass)

这种方式的打印顺序同样符合预期:

  1. My Class initialized
  2. MyClass delegate set
  3. The getString func run
  4. Delegate run and print the string: Hello World

两种方案都不需要延迟执行,纯靠初始化阶段的逻辑调整就能实现需求。前者逻辑更直接,适合固定数据源的场景;后者更灵活,支持后续动态修改数据源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 23:42:36