Swift两类互相嵌套实例化的循环引用问题及解决方法
解决Swift中两个类互相嵌套实例化的问题
兄弟,你现在的代码会直接触发无限递归初始化的问题——OfferItem创建时会实例化Item,Item初始化又会立刻创建OfferItem,循环往复直接把栈撑爆,肯定跑不起来。给你几个靠谱的解决方案,看你需求选:
方案1:使用可选类型延迟关联
把其中一个类的关联属性改成可选类型(默认nil),初始化时不立刻创建对方实例,之后手动完成双向关联。这种方式灵活可控,适合需要明确控制实例生命周期的场景。
class OfferItem { var _id : Int? = 0 var _OfferId : Int? = 0 var _ItemId : Int? = 0 var _Discount : Int? = 0 var _item: Item? // 改为可选类型,默认nil // 可选初始化方法,方便直接关联Item init() {} init(with item: Item) { self._item = item item._Offer = self // 反向关联当前OfferItem实例 } // 你的业务方法示例 func applyDiscount() { print("应用折扣:\(_Discount ?? 0)%") } } class Item { var _id : Int! = 0 var _RateCount : Int? = 0 var _Offer: OfferItem? // 改为可选类型,默认nil // 你的业务方法示例 func showRating() { print("评分次数:\(_RateCount ?? 0)") } }
使用示例:
// 方式1:先创建实例再关联 let item = Item() let offer = OfferItem() offer._item = item item._Offer = offer // 方式2:用初始化方法直接关联 let item2 = Item() let offer2 = OfferItem(with: item2)
方案2:延迟初始化(lazy)+ 弱引用避免循环引用
如果希望属性在第一次访问时自动初始化,可以用lazy关键字,同时为了避免循环引用(两个对象互相强引用导致内存泄漏),把其中一个属性设为weak。
class OfferItem { var _id : Int? = 0 var _OfferId : Int? = 0 var _ItemId : Int? = 0 var _Discount : Int? = 0 // lazy属性:第一次访问时才创建Item实例 lazy var _item: Item = { let newItem = Item() newItem._Offer = self // 关联当前OfferItem return newItem }() func applyDiscount() { print("应用折扣:\(_Discount ?? 0)%") } } class Item { var _id : Int! = 0 var _RateCount : Int? = 0 weak var _Offer: OfferItem? // 用weak修饰,避免循环引用 func showRating() { print("评分次数:\(_RateCount ?? 0)") } }
说明:
lazy闭包里可以安全引用self,因为闭包是在第一次访问_item时才执行,此时OfferItem已经完成初始化。Item的_Offer用weak修饰,因为OfferItem已经强引用了Item,如果Item再强引用OfferItem,会形成循环引用,导致两个对象永远无法被ARC回收。
方案3:用ID关联替代实例持有(推荐给数据模型)
如果这两个类是数据模型(比如从接口返回的实体),更合理的做法是只持有对方的ID,而不是直接持有实例。需要访问关联对象时,再通过ID从数据源(比如数组、数据库)中查询。这种方式完全避免了初始化循环和内存泄漏问题。
class OfferItem { var _id : Int? = 0 var _OfferId : Int? = 0 var _ItemId : Int? = 0 // 只存Item的ID,不存实例 var _Discount : Int? = 0 // 根据ID获取关联的Item实例 func getAssociatedItem() -> Item? { // 假设你有一个全局数据源可以通过ID查询Item return DataStore.shared.getItem(by: _ItemId) } func applyDiscount() { print("应用折扣:\(_Discount ?? 0)%") } } class Item { var _id : Int! = 0 var _RateCount : Int? = 0 var _OfferId: Int? // 只存OfferItem的ID,不存实例 // 根据ID获取关联的OfferItem实例 func getAssociatedOffer() -> OfferItem? { return DataStore.shared.getOfferItem(by: _OfferId) } func showRating() { print("评分次数:\(_RateCount ?? 0)") } } // 模拟全局数据源 class DataStore { static let shared = DataStore() private var offerItems: [Int: OfferItem] = [:] private var items: [Int: Item] = [:] func saveOfferItem(_ offer: OfferItem) { guard let id = offer._id else { return } offerItems[id] = offer } func saveItem(_ item: Item) { items[item._id] = item } func getItem(by id: Int?) -> Item? { guard let id = id else { return nil } return items[id] } func getOfferItem(by id: Int?) -> OfferItem? { guard let id = id else { return nil } return offerItems[id] } }
使用示例:
let item = Item() item._id = 1001 item._RateCount = 50 DataStore.shared.saveItem(item) let offer = OfferItem() offer._id = 2001 offer._ItemId = 1001 offer._Discount = 20 DataStore.shared.saveOfferItem(offer) // 通过ID获取关联对象 if let associatedItem = offer.getAssociatedItem() { associatedItem.showRating() } if let associatedOffer = item.getAssociatedOffer() { associatedOffer.applyDiscount() }
内容的提问来源于stack exchange,提问作者user4643296
相关产品推荐
相关产品推荐

