Swift 内存管理

简介

不管什么语言,内存管理始终是重中之重,所以作为苹果推荐使用的后起之秀Swift也不例外,Swift的内存管理是使用的ARC

Automatic Reference Counting: Swift uses Automatic Reference Counting (ARC) to track and manage your app’s memory usage. In most cases, this means that memory management “just works” in Swift, and you do not need to think about memory management yourself. ARC automatically frees up the memory used by class instances when those instances are no longer needed.

iOS5之前,iOS的内存管理是MRC,那时候的内存管理全靠程序猿。iOS5之后才有了ARC,也是苹果一大改进我们一般情况下不需要对对象的release进行特别管理(除通知/Timer/Block等)。 iOS ARC和MRC区别


工作机制

  • Swift内存管理和OC一样: 管理引用类型的内存, 不会管理值类型, 值类型不需要管理
    • 采用自动引用计数来管理内存, 默认情况下所有的引用都是强引用
    • 当有一个强引用指向某一个对象时,该对象的引用计数会自动+1
    • 当该强引用消失时,引用计数会自动-1

一般循环引用

  • 👆也介绍了,Swift使用的是ARC,它会自动帮助我们管理内存的
  • But 我们开发中,经常会出现有耦合的两个类相互持有对方属性,造成循环引用的问题,看👇:
    • Master -> Dog 有一个强引用
    • Dog -> Master 有一个强引用
    • 手动给对象置nil (没有deinit)
// master 主人
class Master: NSObject {

    // 持有一条狗
    var dog: Dog?
    
    deinit {
        print("---------Master deinit---------")
    }
    
}
---------------------------------------------------------------
// Dog 狗狗
class Dog: NSObject {

    // 狗狗有个主人
    var master: Master?
    
    deinit {
        print("---------Dog deinit---------")
    }
    
}
---------------------------------------------------------------
class ViewController: UIViewController {

    var d: Dog?
    var m: Master?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 狗狗
        d = Dog()
        // 主人
        m = Master()
        
        // 给狗狗个主人
        d?.master = m
        // 给主人个狗狗
        m?.dog = d
        
        // 手动置nil
        d = nil
        m = nil
        
    }
}

解决问题

  • weak: 和OC中的__weak一样是一个弱引用.当指向的对象销毁时,会自动将指针指向nil
  • unowned: 和OC中的__unsafe_unretained.当对象销毁时依然指向原来的内存地址, 该修饰不能指向nil

unownedweak是有区别的,看看官方的解释:
“If the captured reference will never become nil, it should always be captured as an unowned reference, rather than a weak reference.”

如果该引用不会变成nil,那么你应该使用unowned引用,而不是weak。所以unowned其实有点儿像Objective - C里面的unsafe_unretained。而且这里有一点需要注意:不要使用weak去修饰一个let,因为该引用之后会变,所以只能是var,这一点在官方文档里面也有提示:
“Weak references must be declared as variables, to indicate that their value can change at runtime. A weak reference cannot be declared as a constant.”

// Dog 狗狗
class Dog: NSObject {

    // 狗狗有个主人
    weak var master: Master?
    
    deinit {
        print("---------Dog deinit---------")
    }
    
}
---------------------------------------------------------------
---------Master deinit---------
---------Dog deinit---------


闭包循环引用

Swift中的闭包(closure)Objective - C中的block一样,会引起循环引用,从而导致内存泄露。解决办法👇:

  • 使用weak修饰变量, 打破强引用, 因为使用weak修饰的变量有一次变成nil的机会
  • 使用[weak self] 修饰闭包原理跟__weak类似, 这样在闭包中使用self, 就是弱引用
  • 使用[unowned self ] 修饰闭包, 跟__unsafe_unretained类似, 不安全
class NextViewController: UIViewController {

    var completionHandler:((_ name: String)->())?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.purple
        view.alpha = 0.4
        
        //0. 循环引用
        self.retainMethod()
        
        //1. weak var weakSelf = self weak
        self.weakSelfMethod1()
        
        //2. [weak self] 跟OC __weak 相似  [weak self]
        self.weakSelfMethod2()
        
        //3. [unowned self] 跟 _unsafe_unretained 类似  不推荐使用
        self.unownedMethod()
    }

    func retainMethod() {
        networkWithPath(path: "www.baidu.com", param: ["name":"haha"]) { (name) in
            print("\(self.view)")
        }
    }
    
    func weakSelfMethod1 () {
        
        weak var weakSelf = self
        
        networkWithPath(path: "www.baidu.com", param: ["name":"haha"]) { (name) in
            
            print("\(String(describing: weakSelf?.view))")
            
        }
    }
    
    func weakSelfMethod2(){
        
        networkWithPath(path: "www.baidu.com", param: ["name":"haha"]) { [weak self] (name) in
            print("\(String(describing: self?.view))")
        }
    }
    
    func unownedMethod() {
        networkWithPath(path: "www.baidu.com", param: ["name":"haha"]) { [unowned self](name) in
            print("\(self.view)")
        }
    }
    
    func networkWithPath(path: String, param:[String: String], completionHandle:@escaping (_ name: String)->())->(){
        self.completionHandler = completionHandle
        self.completionHandler!("hello")
    }
    
    deinit {
        print("---------- NextViewController deinit ----------")
    }
    

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 不管什么语言,内存管理始终是重中之重,所以Swift也不例外 Swift采用了和Objective - C相同的A...
    庸者的救赎阅读 9,333评论 8 13
  • Swift使用自动引用计数(ARC)机制来处理内存。通常情况下,Swift内存管理机制会自动管理内存,无须我们考虑...
    透支未来阅读 2,350评论 0 2
  • 之前我在CSDN上写过一篇博客:OC内存管理、ARC、property属性、__strong、__weak、__b...
    ShayneFcf阅读 3,907评论 0 4
  • 内存管理 ARC是Swift默认的内存管理机制,其针对堆上的对象,由编译器自动生成操作引用计数的指令(retain...
    AAup阅读 3,795评论 0 1
  • 当一个人出生时,这个世界便有人为他付出,从衣食住行,到琴棋书画,都有人在为他无私奉献,虽然这付出不一定是永远的,但...
    浅思念阅读 903评论 0 0