Dear Blog Park's attention to Bo main article friends tell you a very unfortunate news oh,
This article will be the blogger in the blog Park published the last article,
Because after the article blogger will only be posted here Oh http://daiweilai.github.io/
New Blog layout better, reading experience better, welcome to vomit Groove, message, subscribe yo
Soon again the new year, eh, can no longer like the original Shameless tease is (we Guangdong dialect for red envelopes meaning)
Figure 1
Figure 2
Looks like it's out of this year.
Who let brother already work?
The company's development mission this year is finished, and Apple is very hǎo (yàng) (DE) Let the Christmas do not review, so this half a month should be idle.
Bo Master pinch refers to a calculation, Swift has been raised to 2.1, and also open source, so it seems that Swift is also fat enough, grammar will never have big changes, it is time to catch up again.
Why, in fact, at the time of the Swift Beta, our project manager tried out Palyground, clapped, Bang Bang, "we use Swift to develop the next project," then Swift1.0 ... 2.0, every upgrade, every grammar change, every time Xcode opened the moment is Azolla, that shocking scenes countless times let Bo master tortured. Finally, fortunately, this project is dead, oh yes!
OK, pick up the swift again, today's article is a Passion translation masterpiece, and my English level has been fully affirmed by the original author:
Figure 3
See, no obstacles to communication!! We chatted happily for a long time ~, passionate, Biu biu ~
Okay, back to the subject of the blog post, this time we're talking about "Weak/strong Dance."
Resolving circular references in block search for the WWDC Session #322 The amazing code is like this:
- (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:_observer];}- (void)loadView{ [super loadView]; __weak TestViewController *wself = self; _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey" object:nil queue:nil usingBlock:^(NSNotification *note) { TestViewController *sself = wself; [sself dismissModalViewControllerAnimated:YES]; }];}
Or you can see how afnetworking is using block:
__weak __typeof(self)weakSelf = self;AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {__strong __typeof(weakSelf)strongSelf = weakSelf;strongSelf.networkReachabilityStatus = status;if (strongSelf.networkReachabilityStatusBlock) {strongSelf.networkReachabilityStatusBlock(status);}};
We are all very familiar with the "Weak/strong Dance" in objective-c, but I suddenly want to know how to do it in the swift language. Is there a legendary best practice?
All right, translation begins!
Original
First, let's give an example of a circular reference that is caused by a reference in a closure that does not use weak.
class C { let name: String var block: (() -> Void)? init(name: String) { self.name = name block = { self.doSomething() } } deinit { print("Destroying \(name)") } func doSomething() { print("Doing something for \(name)") }}var c = C(name: "one")print(c.name)c = C(name: "two")print(c.name)
Output
onetwo
This is an example of a huge base and obvious circular reference, self--block->self
So, the deinit
method is absolutely not enforced, even if you put the c
re-pointing nil
or other instances, c
will not be destroyed, this is stubborn and naughty circular reference, especially when you c
point to the nil
object, you can no longer quote, It lies quietly in the heap of memory, leaving the world and independent, and then you will be a heap of memory leaks, and then you faint sadness from the lower body came ~ ~ No Then
In fact, the list of parameters of the closure in Swift (Capture list) has been able to get you weak self
to avoid circular references, but it does not reach our requirements, only the weak
construction of "Weak/strong Dance" drops.
Using the closure parameter list
class C { let name: String var block: (() -> Void)? init(name: String) { self.name = name block = { [weak self] in // <-- 这里做出一些改变 self?.doSomething() } } deinit { print("Destroying \(name)") } func doSomething() { print("Doing something for \(name)") }}var c = C(name: "one")print(c.name)c = C(name: "two")print(c.name)
Output
oneDestroying onetwo
So there is no circular reference ~
Use in closures
self
The use [weak self]
of a detail, that is self
in the closure will become Optional
from the above code self?.doSomething()
can be seen.
But if you use it in this closure self?
(multiple use), the problem is, self?
because this self?
is a weak reference, then you cannot be sure that all the operations in this closure self?
can be done, after all, if the reference self
may be hung at any time, Then he raised a chestnut with rage:
Figure 4
class C { deinit { println("Destroying C") } func log(msg: String) { println(msg) } func doClosure() { dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in self?.log("before sleep") usleep(500) self?.log("after sleep") } }}var c: C? = C() // Optional, so we can set it to nilc?.doClosure()dispatch_async(dispatch_get_global_queue(0, 0)) { usleep(100) c = nil // This will dealloc c}dispatch_main()
Output
before sleepDestroying C
Tip: Of course, in general dispatch_async()
you don't have to worry about having a circular reference, because self does not hold dispatch_async()
a block, so the above code does not really cause a circular reference, and if your closure is not very results-oriented, then the self
closure will not be nil
executed, This is still very useful.
The code above does not print after sleep
, because self?
it has been hung up before printing this sentence.
Usually this root-free bug can turn you half to death. So often encountered in this closure of the trial self?
operation of the times, generally will turn self?
into thick and strong strong self
, (Bo is also thick and strong, cover face ~ ~) This is the legendary "Weak/strong Dance", this dance, the amount, what ghost, Why this technology is called dance Ah, I think is called 美队解禁奥义技
still good, the United States Women's Federation inside the captain of the U.S. is also from weak
strong
the ~, well, pull too far, chrysanthemum is painful, we are in the technical translation! Be serious! Be respectful to the original author! Let's call dance, after this dance, we can make sure that once the closure is executed, it will not be self
nil
.
But, as I said at the beginning of the article, what's the Swift
best practice for getting back to strong in the "Weak/strong dance" I'm not sure ...
Get some ideas for strong references use optional bindings
if let
func doClosure() { dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in if let strongSelf = self { // <-- 这里就是精髓了 strongSelf.log("before sleep") usleep(500) strongSelf.log("after sleep") } }}// or in Swift 2, using `guard let`:dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in guard let strongSelf = self else { return } // <-- 这里就是精髓了 strongSelf.log("before sleep") usleep(500) strongSelf.log("after sleep")}
Output
before sleepafter sleepDestroying C
Advantages:
- It's obvious that the whole process of operation
- I got a non-optional local variable in the closure.
Disadvantages:
- Unfortunately we cannot
if let self = self
, because self
it is constant, immutable, so that we can only in the scope of the if let strongSelf = self
closure to use the ugly strongSelf
.
- In Swift's closure, if you have not tried it
strongSelf
, use it self
so the compiler warns you! Because this time self
is optional, compared to OC, will not be warned. (This sentence has been read 21 times, why do you think this is not a disadvantage?)
Use
withExtendedLifetime
There is a function in Swift's standard library: It withExtendedLifetime()
feels like Apple, the goldfish, deliberately induced us to use this function to implement "Weak/strong dance".
/// Evaluate `f()` and return its result, ensuring that `x` is not/// destroyed before f returns.func withExtendedLifetime<T, Result>(x: T, @noescape _ f: () -> Result) -> Result
Then try it.
func doClosure() { dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in withExtendedLifetime(self) { self!.log("before sleep") usleep(500) self!.log("after sleep") } }}
Advantages:
- There's no need to use ugly in closures
strongSelf
.
Disadvantages:
self
Or a damn choice, call the method or something!? , or to unpack, Bo Master suddenly think of one of his skills: one-handed solution, hehe
Customize a
withExtendedLifetime()
This is the way @jtbandes this guy thinks, probably like this:
extension Optional { func withExtendedLifetime(body: Wrapped -> Void) { if let strongSelf = self { body(strongSelf) } }}// Then:func doClosure() { dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] () -> Void in self.withExtendedLifetime { $0.log("before sleep") usleep(500) $0.log("after sleep") } return }}
Advantages:
- Follows naming conventions set by the standard library. Feel no Merit ~
Disadvantages:
strongSelf
Become used $0
, bloggers think Oh, still ugly, and less readable
- In this case, I had to add some extra type info to the
dispatch_async()
closure. I ' m not totally sure why. I don't know what the hell he said.
The translation is over.
Postscript
For Swift's "Weak/strong Dance", in the Weak section, you can refer to this article on Meow for memory management,Weak and unowned .
It's been a lot of sense to use swift back for more than a week, although Xcode is writing swift like a plain text editor, but I'd like to say: Swift is safe! It's hard to crash.
and Happy christmas!.
Collect your pen and leave.
Weak strong Dance in Swift