• 每天一小结,必须读几篇博客在闲暇时,下面开始进入正题: ARC ARC 苹果版本的自动内存管理的编译时间特性。它代表了自动引用计数(Automatic Reference Counting)。也就是对于一个对象来说,只有在引用计数为0...

    每天一小结,必须读几篇博客在闲暇时,下面开始进入正题:

    ARC

    ARC 苹果版本的自动内存管理的编译时间特性。它代表了自动引用计数(Automatic Reference Counting)。也就是对于一个对象来说,只有在引用计数为0的情况下内存才会被释放。

    Strong(强引用)

    让我们从什么是强引用说起。它实质上就是普通的引用(指针等等),但是它的特殊之处在于它能够通过使对象的引用计数+1来保护对象,避免引用对象被ARC机制销毁。本质上来讲,任何对象只要有强引用,它就不会被销毁掉。记住这点对我接下来要讲的引用循环等其他知识来说很重要。

    强引用在swift中无处不在。事实上,当你声明一个属性时,它就默认是一个强引用。一般来说,当对象之间的关系为线性时,使用强引用是安全的。当对象之间的强引用是从父层级流向子层级时,用强引用通常也是ok的。

    下面是一些强引用的例子

    class Kraken {
        let tentacle = Tentacle() //strong reference to child.
    }
    
    class Tentacle {
        let sucker = Sucker() //strong reference to child
    }
    
    class Sucker {}

    示例代码展示了线性关系。Kraken有一个指向Tentacle实例对象的强引用,而Tentacle又有一个指向Sucker实例对象的强引用。引用关系从父层级(Kraken)一直流到子层级(Sucker)。

    同样的,在动画blocks中,引用关系也类似:

    UIView.animateWithDuration(0.3) {
        self.view.alpha = 0.0
    }

    由于animateWithDuration是UIView的一个静态方法,这里的闭包作为父层级,self作为子层级。

    那么当一个子层级想引用父层级会怎么样呢?这里我们就要用到 weak 和 unowned 引用了。

    Weak 和 unowned 引用

    weak

    weak 引用并不能保护所引用的对象被ARC机制销毁。强引用能使被引用对象的引用计数+1,而弱引用不会。此外,若弱引用的对象被销毁后,弱引用的指针会被清空。这样保证了当你调用一个弱引用对象时,你能得到一个对象或者nil. 

    在swift中,所有的弱引用都是非常量的可选类型(对比 var 和 let) ,因为当没有强引用对象引用的的时候,弱引用对象能够并且会变成nil。 

    例如,这样的代码不会通过编译 

    class Kraken {
        weak let tentacle = Tentacle() //let is a constant! All weak variables MUST be mutable.
    }

    因为tentacle是一个let常量。Let常量在运行的时候不能被改变。因为弱引用变量在没有被强引用的条件下会变成nil,所以Swift 编译器要求你必须用var来定义弱引用对象。 

    值得注意的地方是,使用弱引用变量能够避免你出现可能的引用循环。当两个对象相互强引用的时候会出现一个引用循环。如果2个对象相互引用对方,ARC就不能给这两个对象发出合适的释放信息,因为这两个对象彼此相互依存。下图是从苹果官方简洁的图片,它很好的解释了这种情况: 

    44.png

    一个比较恰当的例子就是通知APIs,看一下下面的代码: 

    class Kraken {
        var notificationObserver: ((NSNotification) -> Void)?
        init() {
            notificationObserver = NSNotificationCenter.defaultCenter().addObserverForName("humanEnteredKrakensLair", object: nil, queue: NSOperationQueue.mainQueue()) { notification in
                self.eatHuman()
            }
        }
        
        deinit {
            if notificationObserver != nil {
                NSNotificationCenter.defaultCenter.removeObserver(notificationObserver)
            }
        }
    }

    在这种情况下我们有一个引用循环。你会发现,Swift中的闭包的表现类似与Objective-C的blocks。如果在闭包范围之外声明变量,那么在闭包中使用这个变量时,会对该变量产生另一个强引用。唯一的例外是使用值类型的变量,比如Swift中的 Ints、Strings、Arrays以及Dictionaries等。

    在这里,当你调用eatHuman( ) 时,NSNotificationCenter就保留了一个闭包以强引用方式捕获self。经验告诉我们,你应该在deinit方法中清除通知监听对象。这段代码的问题在于我们没有清除掉block直到deinit.但是deinit 永远都不会被ARC机制调用,因为闭包对Kraken实例有强引用。 

    另外在NSTimers和NSThread也可能会出现这种情况。 

    解决这种情况的方法就是在闭包的捕获列表中使用对self的弱引用。这样就能够打破强引用循环。那么,我们的对象引用图就会像这样: 

    26.png

    把self变成weak不会让self 的引用计数+1,因此ARC机制就能在合适的时间释放掉对象。 

    想要在闭包使用 weak 和 unowned 变量,你应该用[]把它们括起来。如:

    let closure = { [weak self] in 
        self?.doSomething() //Remember, all weak variables are Optionals!
    }

    在上面的代码中,为什么要把 weak self 要放在方括号内?看上去简直秀逗了!在Swift中,我们看到方括号就会想到数组。你猜怎么着?你可以在在闭包内定义多个捕获值!例如: 

    let closure = { [weak self, unowned krakenInstance] in //Look at that sweet Array of capture values.
        self?.doSomething() //weak variables are Optionals!
        krakenInstance.eatMoreHumans() //unowned variables are not.
    }

    这样看上去更像是数组了,对吧?现在你知道为什么把捕获值放在方括号里面了吧。那么用我们已了解的东西,通过在闭包捕获列表中加上[weak self],我们就可以解决之前那段有引用循环的通知代码。 

    NSNotificationCenter.defaultCenter().addObserverForName("humanEnteredKrakensLair", object: nil, queue: NSOperationQueue.mainQueue()) { [weak self] notification in //The retain cycle is fixed by using capture lists!
        self?.eatHuman() //self is now an optional!
    }

    其他我们用到weak和unowned变量的情况是当你使用协议在多个类之间实现代理时,因为Swift中类使用的是reference semantics。在Swift中,结构体和枚举同样能够遵循协议,但是它们用的是value semantics。如果像这样一个父类带上一个子类使用委托使用了代理: 

    class Kraken: LossOfLimbDelegate {
        let tentacle = Tentacle()
        init() {
            tentacle.delegate = self
        }
        
        func limbHasBeenLost() {
            startCrying()
        }
    }
    
    protocol LossOfLimbDelegate {
        func limbHasBeenLost()
    }
    
    class Tentacle {
        var delegate: LossOfLimbDelegate?
        
        func cutOffTentacle() {
            delegate?.limbHasBeenLost()
        }
    }

    在这里我们就需要用weak变量了。在这种情况下,Tentacle以代理属性的形式对Kraken有着一个强引用,而Kraken在它的Tentacle属性中对Tentacle也有一个强引用。我们通过在代理声明前面加上weak来解决这个问题: 

    weak var delegate: LossOfLimbDelegate?

    是不是发现这样写不能通过编译?不能通过编译的原因是非 class类型的协议不能被标识成weak。这里,我们必须让协议继承:class,从而使用一个类协议将代理属性标记为weak。 

    protocol LossOfLimbDelegate: class { //The protocol now inherits class
        func limbHasBeenLost()
    }

    我们什么时候用 :class,通过苹果官方文档: 

    “Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics.” 

    本质上来讲,当你有着跟我上述代码一样的引用关系,你就用:class。在结构体和枚举的情况下,没有必要用:class,因为结构体和枚举是value semantics,而类是 reference semantics.  

    UNOWNED 

    weak引用和unowned引用有些类似但不完全相同。Unowned 引用,像weak引用一样,不会增加对象的引用计数。然而,在Swift里,一个unowned引用有着非可选类型的优点。这样相比于借助和使用optional binding更易于管理。这和隐式可选类型(Implicity Unwarpped Optionals)区别不大。此外,unowned引用是non-zeroing(非零的) ,这表示着当一个对象被销毁时,它指引的对象不会清零。也就是说使用unowned引用在某些情况下可能导致 dangling pointers(野指针url)。你是不是跟我一样想起了用Objective -C的时候, unowned引用映射到了 unsafe_unretained引用。 http://www.krakendev.io/when-to-use-implicitly-unwrapped-optionals/

    看到这里是不是有点蛋疼了。既然Weak和unowned引用都不会增加引用计数,它们都能用于解除引用循环。那么我们该在什么使用它们呢?根据苹果文档: 

    “Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialization.”

    翻译:在引用对象的生命周期内,如果它可能为nil,那么就用weak引用。反之,当你知道引用对象在初始化后永远都不会为nil就用unowned. 

    现在你就知道了:就像是implicitly unwrapped optional(隐式可选类型),如果你能保证在使用过程中引用对象不会为nil,用unowned 。如果不能,那么就用weak 

    下面就是个很好的例子。Class 里面的闭包捕获了self,self永远不会为nil。 

    class RetainCycle {
        var closure: (() -> Void)!
        var string = "Hello"
        init() {
            closure = {
                self.string = "Hello, World!"
            }
        }
    }
    //Initialize the class and activate the retain cycle.
    let retainCycleInstance = RetainCycle()
    retainCycleInstance.closure() //At this point we can guarantee the captured self inside the closure will not be nil. Any further code after this (especially code that alters self's reference) needs to be judged on whether or not unowned still works here.

    在这种情况下,闭包用强引用形式捕获了self,而self也通过闭包属性保留了一个对闭包的强引用,这就出现了引用循环。只要给闭包添加[unowned self] 就能打破引用循环: 

    closure = { [unowned self] in
        self.string = "Hello, World!"
    }

    在这个例子中,由于我们在初始化RetainCycle类后立即调用了闭包,所以我们可以认为self永远不会为nil。

    苹果在unowned references也说明了这点: 

    “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.”

    如果你知道你引用的对象会在正确的时机释放掉,且它们是相互依存的,而你不想写一些多余的代码来清空你的引用指针,那么你就应该使用unowned引用而不是weak引用。

    像下面这种懒加载在闭包中使用self就是一个使用unowned的很好例子: 

    class Kraken {
        let petName = "Krakey-poo"
        lazy var businessCardName: () -> String = { [unowned self] in
            return "Mr. Kraken AKA " + self.petName
        }
    }

    我们需要用unowned self 来避免引用循环。Kraken 和 businessCardName在它们的生命周期内都相互持有对方。它们相互持有,因此总是被同时销毁,满足使用unowned 的条件。 

    然而,不要把下面的懒加载变量与闭包混淆: 

    class Kraken {
        let petName = "Krakey-poo"
        lazy var businessCardName: String = {
            return "Mr. Kraken AKA " + self.petName
        }()
    }

    在懒加载变量中调用closure时,由于没有retain closure,所以不需要加 unowned self。变量只是简单的把闭包的结果assign 给了自己,闭包在使用后就被立即销毁了。下面的截图很好的证明了这点。(截图是厚着脸皮评论区Алексей的拷贝) 

    下载.jpg


    展开全文
  • 因为 Playground 本身会持有所有声明在其中的东西,因此本节的示例代码需要在 Xcode 项目环境运行。在 Playground 可能无法得到正确的结果。 不管在什么语言里,内存管理的内容都很重要,所以我打算花上比...

    因为 Playground 本身会持有所有声明在其中的东西,因此本节中的示例代码需要在 Xcode 项目环境中运行。在 Playground 中可能无法得到正确的结果。

    不管在什么语言里,内存管理的内容都很重要,所以我打算花上比其他 tip 长一些的篇幅仔细地说说这块内容。

    Swift 是自动管理内存的,这也就是说,我们不再需要操心内存的申请和分配。当我们通过初始化创建一个对象时,Swift 会替我们管理和分配内存。而释放的原则遵循了自动引用计数 (ARC) 的规则:当一个对象没有引用的时候,其内存将会被自动回收。这套机制从很大程度上简化了我们的编码,我们只需要保证在合适的时候将引用置空 (比如超过作用域,或者手动设为 nil 等),就可以确保内存使用不出现问题。

    但是,所有的自动引用计数机制都有一个从理论上无法绕过的限制,那就是循环引用 (retain cycle) 的情况。

    什么是循环引用

    虽然我觉得循环引用这样的概念介绍不太应该出现在这本书中,但是为了更清晰地解释 Swift 中的循环引用的一般情况,这里还是简单进行说明。假设我们有两个类 A 和 B , 它们之中分别有一个存储属性持有对方:

    class A {
    	let b: B
    	init() {
    		b = B()
    		b.a = self
    	}
    	deinit {
    		println("A deinit")
    	}
    }
    class B {
    	var a: A? = nil
    	deinit {
    		println("B deinit")
    	}
    }
    
    

    在 A 的初始化方法中,我们生成了一个 B 的实例并将其存储在属性中。然后我们又将 A 的实例赋值给了 b.a 。这样 a.b 和 b.a 将在初始化的时候形成一个引用循环。现在当有第三方的调用初始化了 A ,然后即使立即将其释放, A 和 B 两个类实例的 deinit 方法也不会被调用,说明它们并没有被释放。

    func application(application: UIApplication!, 
    				 didFinishLaunchingWithOptions launchOptions: NSDictionary!) 
    				 -> Bool 
    {
    	// Override point for customization after application launch.
    	var obj: A? = A()
    	obj = nil
    	// 内存没有释放
    	return true
    }
    
    

    因为即使 obj 不再持有 A 的这个对象,b 中的 b.a 依然引用着这个对象,导致它无法释放。而进一步,a 中也持有着 b,导致 b 也无法释放。在将 obj 设为 nil 之后,我们在代码里再也拿不到对于这个对象的引用了,所以除非是杀掉整个进程,我们已经 永远 也无法将它释放了。多么悲伤的故事啊..

    在 Swift 里防止循环引用

    为了防止这种人神共愤的悲剧的发生,我们必须给编译器一点提示,表明我们不希望它们互相持有。一般来说我们习惯希望 "被动" 的一方不要去持有 "主动" 的一方。在这里 b.a 里对 A 的实例的持有是由 A 的方法设定的,我们在之后直接使用的也是 A 的实例,因此认为 b 是被动的一方。可以将上面的 class B 的声明改为:

    class B {
        weak var a: A? = nil
        deinit {
            println("B deinit")
        }
    }
    

    在 var a 前面加上了 weak ,向编译器说明我们不希望持有 a。这时,当 obj 指向 nil 时,整个环境中就没有对 A 的这个实例的持有了,于是这个实例可以得到释放。接着,这个被释放的实例上对 b 的引用 a.b 也随着这次释放结束了作用域,所以 b 的引用也将归零,得到释放。添加 weak 后的输出:

    A deinit
    B deinit
    

    可能有心的朋友已经注意到,在 Swift 中除了 weak 以外,还有另一个冲着编译器叫喊着类似的 "不要引用我" 的标识符,那就是 unowned 。它们的区别在哪里呢?如果您是一直写 Objective-C 过来的,那么从表面的行为上来说 unowned 更像以前的 unsafe_unretained ,而 weak 就是以前的 weak 。用通俗的话说,就是 unowned 设置以后即使它原来引用的内容已经被释放了,它仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil。如果你尝试调用这个引用的方法或者访问成员属性的话,程序就会崩溃。而 weak 则友好一些,在引用的内容被释放后,标记为 weak 的成员将会自动地变成 nil (因此被标记为 @ weak的变量一定需要是 Optional 值)。关于两者使用的选择,Apple 给我们的建议是如果能够确定在访问时不会已被释放的话,尽量使用 unowned ,如果存在被释放的可能,那就选择用 weak 。

    我们结合实际编码中的使用来看看选择吧。日常工作中一般使用弱引用的最常见的场景有两个:

    1. 设置 delegate 时
    2. 在 self 属性存储为闭包时,其中拥有对 self 引用时

    前者是 Cocoa 框架的常见设计模式,比如我们有一个负责网络请求的类,它实现了发送请求以及接收请求结果的任务,其中这个结果是通过实现请求类的 protocol 的方式来实现的,这种时候我们一般设置 delegate 为 weak :

    // RequestManager.swift
    class RequestManager: RequestHandler {
    	func requestFinished() {
    		println("请求完成")
    	}
    	func sendRequest() {
    		let req = Request()
    		req.delegate = self
    		req.send()
    	}
    }
    // Request.swift
    @objc protocol RequestHandler {
    	optional func requestFinished()
    }
    class Request {
    	weak var delegate: RequestHandler!;
    	func send() {
    		// 发送请求
    		// 一般来说会将 req 的引用传递给网络框架
    	}
    	func gotResponse() {
    		// 请求返回
    		delegate?.requestFinished?()
    	}
    }
    
    

    req 中以 weak 的方式持有了 delegate,因为网络请求是一个异步过程,很可能会遇到用户不愿意等待而选择放弃的情况。这种情况下一般都会将 RequestManager 进行清理,所以我们其实是无法保证在拿到返回时作为 delegate 的 RequestManager 对象是一定存在的。因此我们使用了 weak 而非 unowned ,并在调用前进行了判断。

    闭包和循环引用

    另一种闭包的情况稍微复杂一些:我们首先要知道,闭包中对任何其他元素的引用都是会被闭包自动持有的。如果我们在闭包中写了 self 这样的东西的话,那我们其实也就在闭包内持有了当前的对象。这里就出现了一个在实际开发中比较隐蔽的陷阱:如果当前的实例直接或者间接地对这个闭包又有引用的话,就形成了一个 self -> 闭包 -> self 的循环引用。最简单的例子是,我们声明了一个闭包用来以特定的形式打印 self 中的一个字符串:

    class Person {
    	let name: String
    	lazy var printName: ()->() = {
    		println("The name is \(self.name)")
    	}
    	init(personName: String) {
    		name = personName
    	}
    	deinit {
    		println("Person deinit \(self.name)")
    	}
    }
    func application(application: UIApplication!, 
    		didFinishLaunchingWithOptions launchOptions: NSDictionary!) 
    		-> Bool 
    {
    	// Override point for customization after application launch.
    	var xiaoMing: Person = Person(personName: "XiaoMing")
    	xiaoMing.printName()
    	return true
    }
    // 输出:
    // The name is XiaoMing
    
    

    printName 是 self 的属性,会被 self 持有,而它本身又在闭包内持有 self ,这导致了 xiaoMing 的 deinit 在自身超过作用域后还是没有被调用,也就是没有被释放。为了解决这种闭包内的循环引用,我们需要在闭包开始的时候添加一个标注,来表示这个闭包内的某些要素应该以何种特定的方式来使用。可以将 printName 修改为这样:

    lazy var printName: ()->() = {
        [weak self] in
        if let strongSelf = self {
            println("The name is \(strongSelf.name)")
        }
    }
    

    现在内存释放就正确了:

    // 输出:
    // The name is XiaoMing
    // Person deinit XiaoMing
    

    如果我们可以确定在整个过程中 self 不会被释放的话,我们可以将上面的 weak 改为unowned ,这样就不再需要 strongSelf 的判断。但是如果在过程中 self 被释放了而printName 这个闭包没有被释放的话 (比如 生成 Person 后,某个外部变量持有了 printName ,随后这个 Person 对象被释放了,但是 printName 已然存在并可能被调用),使用 unowned 将造成崩溃。在这里我们需要根据实际的需求来决定是使用 weak 还是 unowned 。

    这种在闭包参数的位置进行标注的语法结构是将要标注的内容放在原来参数的前面,并使用中括号括起来。如果有多个需要标注的元素的话,在同一个中括号内用逗号隔开,举个例子:

    // 标注前
    { (number: Int) -> Bool in
    	//...
    	return true
    }
    // 标注后
    { [unowned self, weak someObject] (number: Int) -> Bool in
    	//...
    	return true
    }	
    展开全文
  • Swift中weak修饰符

    2016-10-18 16:56:18
    Swift中weak修饰必须用var,weak指向的对象一旦被释放,就会变为nil,用var就是一个可选类型。
    Swift中的weak修饰必须用var,weak指向的对象一旦被释放,就会变为nil,用var就是一个可选类型。
    
    展开全文
  • weak与unowned的区别: unowned设置以后即使它原来引用的内容已经被释放了,它仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil 。如果你尝试调用这个...

    在闭包里面为了解决循环引用问题,使用了 `[unowned self]`。如果回调在self已经被释放后再调用,会导致crash掉。

    解决:使用weak修饰。

    weak与unowned的区别:

         unowned设置以后即使它原来引用的内容已经被释放了,它仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil 。如果你尝试调用这个引用的方法或者访问成员属性的话,程序就会崩溃。而 weak 则友好一些,在引用的内容被释放后,标记为 weak 的成员将会自动地变成 nil (因此被标记为 @ weak 的变量一定需要是 Optional 值)。

    展开全文
  • /**  (6)循环强引用  ARC不是万能的,它可以很好的解决内存过早释放的问题,  但是在某些场合下不能很好的解决内存泄漏的问题。  */ ...接下来我们还是用代码来给大家讲解什么是循环强引用。

            /**

             6)循环强引用

             ARC不是万能的,它可以很好的解决内存过早释放的问题,

             但是在某些场合下不能很好的解决内存泄漏的问题。

             */

            

            /**

             循环强引用是造成内存泄漏的原因。接下来我们还是用代码来给大家讲解什么是循环强引用。

             直接用官方例子

             */

            

            class Person {

                let name:String

                init(name:String) {

                    self.name = name

                }

                var apartment:Apartment?

                deinit {

                    print("\(name) is being deininialized")

                }

            }

            

            

            class Apartment {

                let number:Int

                init(number:Int) {

                    self.number = number

                }

                var tenant:Person?

                deinit {

                    print("Apartment #\(number) is being deininialized")

                }

            }

            

            /**

             两个类各有一个属性,每个属性都是对方类的类型的属性,而这两个属性互相持有对方。

             这就是所谓的循环强引用

             */

            

            // 这是强引用,不要认为可选类型就是弱引用啊,只有通过weak unowned才是弱引用

            var john:Person?

            var number73:Apartment?

            

            john = Person.init(name:"Johu Appleseed")

            number73 = Apartment.init(number:73)

            

            /**

             上面的四句换对应 循环强引用讲解图1.png

             */

            

            




            /**

             这里面 apartment tenant两个对象是强引用,

             也就是下面的johnnumber73设置为nil只是他们的强引用断开。

             */

            john!.apartment = number73

            number73!.tenant = john

            

            

            

            /**

             我们可以看到在析构方法中没有打印,也就是这两个对象他们没有被销毁,造成了内存泄漏。但是我们没有办法在访问他们。

             对应的循环强引用讲解图2.png

             */

            john = nil

            number73 = nil

            

            

            

            /**

             相互强引用或者说循环强引用会造成内存泄漏,为什么?

             因为一块内存的释放的判断是没有对象占用它,相互强引用,那到底谁先释放呢?谁也不愿意先释放。

             */

            

            



            

            

            

            

            

            

            

            

            

            

            /**

             在变量tenant加上 weak修饰,

             也就是将其中的一个变量设置为弱引用就行了。

             */

            

            class Apartment1 {

                let number:Int

                init(number:Int) {

                    self.number = number

                }

                weakvar tenant: Person?

                deinit {

                    print("Apartment #\(number) is being deininialized")

                }

            }

            

            print("--------------------->>")

            

            

            var john1:Person?

            var number74:Apartment1?


            john1 = Person.init(name:"Johu Appleseed1")

            number74 = Apartment1.init(number:74)

            

            /**

             上面的四句换对应 循环强引用讲解图3.png

             */

            

            

            /**

             这里面 apartment tenant两个对象是强引用,

             也就是下面的johnnumber73设置为nil只是他们的强引用断开。

             */

            john1!.apartment = number73

            number74!.tenant = john

            

            

            /**

             打印出来

             --------------------->>

             Apartment #74 is being deininialized

             Johu Appleseed1 is being deininialized


             循环强引用讲解图4.png

             

             john1 对象的强引用没有了,设置为nil时被销毁,释放内存。同时number74所指向的内存也被释放了。

             */

            john1 = nil

            number74 = nil


    展开全文
  • 1.Swift内存管理、weak和unowned以及两者区别(如何使用Swift weak与unowned?) 2.Swift:Weak 和 Unowned 3.扒一扒swift中的unowned和weak下 总结: 1.共同点: 1.1 引用对象的自动引用计数都不会加1,...
  • 通常的解释是,考虑到对象的生命周期,您应该在unowned和weak之间进行选择,但有时您可能仍然怀疑应该实际使用哪一个,并且想知道unowned和weak哪一个更好。 众所周知,Swift利用良好的旧ARC(自动引用计数)来管理...
  • /**  14.4-weak引用.mp4  */    /**  (4)weak引用(弱引用)  */    class Ref {  deinit {  print
  • Swift中的struct和enums是值对象类型(当一个新的实例生成时只是值复制),不是引用类型,所以它们不会引起强引用闭环; 3.weak引用是可选的(optional),所以必须使用var修饰词,这样在释放时...
  • swift 使用weak self

    2017-12-29 15:46:19
    controlEvent(.touchUpInside).subscribe({ [weak self] _ in //必须要加[weak self],否则释放不掉,不会执行deinit self?.navigationController?.popViewController(animated: true) }) [/code] 不管用哪...
  • 当我们知道两个对象的生命周期并不相关,那么我们必须使用 [weak self]。相反,非强引用对象拥有和强引用对象同样或者更长的生命周期的话,则应该使用 [unown self]。 例如,ViewControler 对它的 SubView 的引用...
  • swift中闭包 OCBlock 解决循环引用 OC全局宏定义 #define WS(weakSelf) __weak __typeof(&*self)weakSelf = self; 用法如下: WS(weakself) [self.tableView addHeaderWithCallback:^{ ...
  • Swift 用自动引用计数ARC(Automatic Reference Counting)方式来跟踪和管理app的内存使用。这使得内存管理成为swift内部的机制,不需要认为考虑。ARC会自动释放那些不再被需要的变量。ARC如何工作每次创建一个类的...
  • Swift的循环引用以weak

    2016-07-21 00:55:57
    Swift 是自动管理内存的,这也就是说,我们不再需要操心内存的申请和分配。当我们通过初始化创建一个对象时,Swift 会替我们管理和分配内存。而释放的原则遵循了自动引用计数 (ARC) 的规则:当一个对象没有引用的...
  • weak 一般我们用来修饰delegate ,block使用 __weak typeof(self) weakSelf = self; 这两者都是为了避免产生循环引用 循环引用的产生(如): @class Dog; @interface Person : NSObject ///人有一条宠物狗 @...
  • 如果是引用类型,则是捕获了对象的引用,即在闭包复制了一份对象的引用,对象的引用计数加1;如果是值类型呢,捕获的是值类型的指针,如果在闭包修改值类型的话,同样会改变外界变量的值。 func delay(_ d...
  • 一篇好文章,从内存的角度上说明了这些问题 https://www.jianshu.com/p/bf2b8f278a81
  • 之前我在CSDN上写过一篇博客:OC内存管理、ARC、property属性、__strong、__weak(),大家有兴趣的可以去看看。 今天我们来整理一下Swift的内存管理与循环引用的解决问题-weak、unowned: 内存管理 swift的内存...
  • Swift中没有了strong, assign, copy关键字,对于所有的class类型变量都默认采用了strong类型,如果需要指定使用weak,则需要添加weak关键字修饰。 正是由于这种默认的strong类型,在闭包会引起循环引用,导致内存...
1 2 3 4 5 ... 20
收藏数 6,677
精华内容 2,670