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传递数据,期望控制台打印顺序为:
- My Class initialized
- MyClass delegate set
- The getString() func run
- 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()
执行后打印顺序完全符合预期:
- My Class initialized
- MyClass delegate set
- The getString func run
- 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)
这种方式的打印顺序同样符合预期:
- My Class initialized
- MyClass delegate set
- The getString func run
- Delegate run and print the string: Hello World
两种方案都不需要延迟执行,纯靠初始化阶段的逻辑调整就能实现需求。前者逻辑更直接,适合固定数据源的场景;后者更灵活,支持后续动态修改数据源。
内容的提问来源于stack exchange,提问作者incelemeTRe
相关产品推荐
相关产品推荐

