我遇到了最奇怪的事情,也许有人能解释.

  1. 创建UIA视图
  2. 创建对
  3. 向视图层次 struct 中添加
  4. 从视图层次 struct 中删除
  5. 将A设为零
  6. 弱引用仍然存在.

如果跳过第3步和第4步,弱引用将如预期的那样变为零.

Code to test:

TestView to check deinit

class TestView: UIView {
    deinit {
        print("deinit")
    }
}

单元测试

class RetainTests: XCTestCase {
    
    func testRetainFails() {
        let holderView = UIView()
        var element: TestView? = TestView()

        holderView.addSubview(element!)
        element?.removeFromSuperview()

        weak var weakElement = element
        XCTAssertNotNil(weakElement)
        // after next line `weakElement` should be nil
        element = nil
        // console will print "deinit"
        XCTAssertNil(weakElement) // fails!
    }

    func testRetainPasses() {
        var element: TestView? = TestView()

        weak var weakElement = element
        XCTAssertNotNil(weakElement)
        // after next line `weakElement` should be nil
        element = nil
        // console will print "deinit"
        XCTAssertNil(weakElement)
    }
}

这两个测试都会在控制台上打印出deinit,但是如果测试失败,如果element在任何时候都在视图层次 struct 中,weakElement仍然保留引用,尽管element成功地解除了分配.怎么会这样?

(编辑:这是在应用程序中,而不是在playground 中)

推荐答案

将TestView添加到superview并将其删除时,TestView会附带一个自动释放.如果确保排空自动释放池,则此测试的行为与预期的一样:

autoreleasepool {
    holderView.addSubview(element!)
    element?.removeFromSuperview()
}

也就是说,你不能依赖这种行为.关于什么时候一个物体会被摧毁,没有任何promise .你只知道它会在你发布最后一次对它的强烈引用之后.对象上可能有其他保留或自动删除.而且也没有promise 会打deinit,所以一定不要把任何强制性的逻辑放在那里.它应该只执行内存清理.(由于稍有不同的原因,Mac和iOS在程序终止时从不拨打deinit.)

在失败的测试用例中,如果断言失败,则打印deinit.可以通过在失败的断言和print上放置断点来演示这一点.这是因为自动释放池在测试用例结束时被排空.

基本的经验是,在传递给ObjC代码的对象上放置平衡的retain/AUTORELASE调用是非常常见的(UIKit在很大程度上是ObjC).您通常不应该期望在当前事件循环结束之前销毁UIKit对象.不要相信这一点(这不是promise ),但这通常是真的.

Swift相关问答推荐

TabView中的视频播放器意外播放

查找数组中 ** 元素 ** 的属性的最小值和最大值

为什么要在SWIFT RandomAccessCollection协议中重新定义元素类型?

Swift图表';chartXVisibleDomain挂起或崩溃

使用 @resultBuilder 的通用 buildList 函数

为什么我的Swift app不能用xcodebuild构建,但是用XCode可以构建?

如何在不将变量转换为字符串的情况下判断变量在 Swift 中是否为 Optional(nil)?

如何在一个视图控制器中创建具有相同行为的多个集合视图?

当使用 CGFloat 而不是数字文字时,为什么 node 的位置会发生变化?

Swift 有没有办法在不使用 switch 语句的情况下获取关联值?

使用 swift 运行 pod install 时出错

Swift:在子类中覆盖 == 导致仅在超类中调用 ==

在 iOS 中使用 Swift 保存 PDF 文件并显示它们

从 NSData 对象在 Swift 中创建一个数组

如何更改弹出框的大小

将强制向下转换视为可选将永远不会产生零

使用 Swift 以编程方式自定义 UITableViewCell

如何交换快速数组中的元素?

Swift 2.0 最低系统版本要求(部署目标)

如何使用 Swift 枚举作为字典键? (符合 Equatable)