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

含弱引用可选属性的类深拷贝问题:父属性赋值后为空

问题分析与解决方案

你的核心问题出在**weak属性的ARC特性**以及拷贝时未正确建立强引用链:parent是弱引用,若没有其他强引用指向拷贝后的父节点对象,它会被ARC立即释放,最终变为nil。同时你之前的拷贝逻辑存在混乱,比如重复创建拷贝、未正确维护父子间的强引用关系,导致parent无法被保留。

先修正基础定义

首先统一代码里的拼写(你代码里混用了child/childs,这里统一为children),并添加Equatable实现用于定位目标节点:

class A: Equatable {
    var children: [A] = []
    weak var parent: A?
    
    // 根据实际需求判断节点相等,这里用对象引用判断
    static func == (lhs: A, rhs: A) -> Bool {
        return lhs === rhs
    }
}

正确实现深拷贝逻辑

重新实现NSCopying,让拷贝逻辑分层处理:节点拷贝只创建空壳,父子关系由上层节点递归建立,确保强引用链完整:

extension A: NSCopying {
    // 基础拷贝:只创建当前节点的空实例,不处理父子关系
    func copy(with zone: NSZone? = nil) -> Any {
        A()
    }
    
    // 深拷贝整个树形结构的核心方法
    func deepCopy() -> A {
        let nodeCopy = self.copy() as! A
        // 递归处理子节点:每个子节点深拷贝后,绑定父节点并加入children数组(强引用)
        for child in self.children {
            let childCopy = child.deepCopy()
            childCopy.parent = nodeCopy
            nodeCopy.children.append(childCopy)
        }
        return nodeCopy
    }
}

获取目标节点的拷贝

修正copyOfChildObject逻辑:先深拷贝整个树,再在拷贝后的树中定位目标节点,此时目标节点的parent已被正确绑定且不会被释放:

extension A {
    var copyOfChildObject: A? {
        guard let root = findRoot() else { return nil }
        // 深拷贝整个根节点树
        let rootCopy = root.deepCopy()
        // 在拷贝后的树中找到对应原节点的拷贝
        return findTargetNode(original: self, in: rootCopy)
    }
    
    // 找到当前节点的根节点
    private func findRoot() -> A? {
        var current: A? = self
        while let parentNode = current?.parent {
            current = parentNode
        }
        return current
    }
    
    // 在拷贝树中递归查找目标节点
    private func findTargetNode(original: A, in copyNode: A) -> A? {
        if original == copyNode {
            return copyNode
        }
        for childCopy in copyNode.children {
            if let target = findTargetNode(original: original, in: childCopy) {
                return target
            }
        }
        return nil
    }
}

为什么这样能解决问题?

  1. 强引用链完整:父节点拷贝的children数组会强引用子节点拷贝,子节点拷贝的parent(弱引用)指向父节点拷贝,既避免了循环引用,又保证父节点拷贝不会被ARC释放。
  2. 拷贝逻辑分层:基础copy()只负责创建节点,deepCopy()递归维护父子关系,逻辑清晰,不会出现重复创建或引用丢失的问题。
  3. 目标节点定位准确:通过Equatable的引用判断,能精准找到拷贝后的目标节点,此时它的parent已经被上层节点正确设置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 23:23:08