聊聊一Swift关键字strong、weak、unowned的区别?

858 阅读2分钟

我正在参加「掘金·启航计划」

聊一聊关键字strong、weak、unowned的区别?

  • Swfit的内存管理机制同OC一致, 都是ARC, strongweak同OC一样.
  • unowned(无主引用), 不会产生强引用, 实例销毁后仍然存储着实例的内存地址(类似于OC中的unsafe_unretained), 它仍然会保持对被已经释放了的对象的一个"无效的"引用, 它不是Optional, 也不会被指向nil, 如果试图在实例销毁后访问无主引用unowned, 会产生运行时错误(悬垂指针).
  • weak, 当我们赋值给一个被标记为weak的变量时, 它的引用计数不会被改变. 而且当这个弱引用变量所引用的对象被释放时, 这个变量将被自动设为nil. 这也是弱引用必须被声明为Optional的原因.
  • 在引用对象的生命周期内, 如果它可能为nil, 那么就用weak引用. 反之, 当你知道引用对象在初始化后永远都不会为nil, 就用unowned.
  • 如果你知道你引用的对象会在正确的时机释放掉, 且它们是相互依存的, 而你不想写一些多余的代码来情况你的引用指针, 那么你就应该使用unowned引用而不是weak引用.
class SwiftViewControllerA: UIViewController {

    var person : Person?

    override func viewDidLoad() {
        super.viewDidLoad()

        person = Person()

        person?.testClosure()

        person = nil
        
    }
}

// 测试unowned和weak

class SomeSigleton {

    static let share = SomeSigleton()

    func closure(closure: (() -> Void)?) {

        DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
            closure?()
        }

    }

}


class Person {

    let someSigleton = SomeSigleton.share
    let portrait = UIImage()

    func testClosure() {

        someSigleton.closure { [unowned self] in
            print(self.portrait)
        }
        
        // 使用weak修饰就不会有问题!
        //        someSigleton.closure { [weak self] in
//            print(self?.portrait)
//        }

    }

    deinit {
        print("Person is deinited")
    }

}

image.png

  • Apple文档使用建议
Define a capture in a closure as an unowned reference when the closure and the instance it captures will always refer to each other, and will always be deallocated at the same time.

Conversely, define a capture as a weak reference when the captured reference may become nil at some point in the future. Weak references are always of an optional type, and automatically become nil when the instance they reference is deallocated. This enables you to check for their existence within the closure’s body.
  • 当我们知道两个对象的生命周期并不相关, 那么我们必须使用weak. 相反, 非强引用对象拥有和强引用对象同样或者更长的声明周期的话, 则应该使用unowned.
  • 例如, ViewController对它的SubView的引用可以使用unowned. 因为ViewController的生命周期一定比它的SubView长. 而在使用服务时, 则需要看情况使用weak. 因为服务的初始化方法可能是被工厂模式或Service Locator所封装. 这些服务可能在某些时候被重构为单例, 此时它们的生命周期发生了改变.

发文不易, 喜欢点赞的人更有好运气👍 :), 定期更新+关注不迷路~

ps:欢迎加入笔者18年建立的研究iOS审核及前沿技术的三千人扣群:662339934,坑位有限,备注“掘金网友”可被群管通过~