Stack overflow caused by calling a swift closure in another closure - ios

UPDATE: This bug is confirmed by rdar://20931915 and is fixed in Xcode 7 beta 3.
I found a weird bug caused by calling a swift closure in another closure in debug build. My Xcode is version 6.3.1 with Swift version 1.2. Here's the code:
import Swift
class ClosureStackOverflow {
private var b: Bool = false
private func callClosure1(callback: Void -> Void) {
println("in closure 1")
callback()
}
private func callClosure2(callback: Void -> Void) {
println("in closure 2")
callback()
}
func call() {
callClosure1 { [weak self] in
self?.callClosure2 {
self?.b = true
}
}
}
}
let c = ClosureStackOverflow()
c.call()
The code above compiles well. However if you call its call() method, it will print "in closure 2" infinitely and eventually overflow the stack.
Could you please explain why calling one closure within another will cause this bug?
Thanks.

Change your code to this,and it will work
class ClosureStackOverflow {
private var b: Bool = false
private func callClosure1(callback: Void -> Void) {
println("in closure 1")
callback()
}
private func callClosure2(callback: Void -> Void) {
println("in closure 2")
callback()
}
func call() {
callClosure1 {
self.callClosure2 {
self.b = true
}
}
}
deinit{
print("deinit")
}
}
It seems that you declare [weak self] in in the function,and it cause the problem.
I also test this to call
let c = ClosureStackOverflow()
c.call()
It will output
in closure 1
in closure 2
deinit
It seems that it does not cause circular references if you donot use weak self
Besides
I also test to change the function to this
func call() {
callClosure1 {
[weak self] in
self!.callClosure2 {
self?.b = true
}
}
}
It will work as well. So I think this may be some compiler bug of swift.

Related

Should we continue explicitly capturing variable as weak in iOS

Suppose we got a chain of closures, like so:
var myOtherVc: UIViewController! // get it somehow
self.dismiss(animated: true, completion: { [weak myOtherVc] in
myOtherVc?.present(sthElse, animated: true, completion: { [weak myOtherVc] in // <-- HERE
})
})
My question is if we captured variable myOtherVc in the topmost block as weak should we keep being explicit about weak in all the children blocks or is compiler smart enough to tell ARC to not retain?
Update
I guess I need to clarify, what if the block was escaping?
Also, i DO care about delayed deallocation. This is the whole point of using weak for me.
public func doWhatever(_ success: #escaping () -> Void) {
// do whatever
})
var myOtherVc: UIViewController! // get it somehow
self.dismiss(animated: true, completion: { [weak myOtherVc] in
SomeClass.doWhatever({ [weak myOtherVc] in // <-- HERE
myOtherVc?.present(sthElse, animated: true, completion: { [weak myOtherVc] in // <-- and HERE, too
})
})
})
We suppose all closures are escaping, so I made this playground and I conclude that you must capture your variable as weak in the latest closure that is using your variable and it won't infer its reference type from the parent or top closure:
typealias Closure = () -> Void
class A {
var closureA : Closure?
func runClosureA(closure: #escaping Closure) {
self.closureA = closure
closureA?()
}
func print() {
debugPrint("A is here!")
}
deinit {
debugPrint("A deinited")
}
}
another class which operates on chained closure:
class B {
func runClosureB(closure: #escaping Closure) {
closure()
}
func operate() {
let a : A = A()
runClosureB { [weak a] in
a?.runClosureA { [a] in
a?.print()
}
}
}
deinit {
debugPrint("B deinited")
}
}
The code is:
var b: B? = B()
b?.operate()
b = nil
It will prints:
// "A is here!"
// "B deinited"
But by changing the operate function to this:
func operate() {
let a : A = A()
runClosureB { [a] in
a.runClosureA { [weak a] in
a?.print()
}
}
}
The result will change to this:
"A is here!"
"A deinited"
"B deinited"
Update: In class A I made a strong reference to the closure as closureA, if you don't create the reference, there is no need to capture self as weak in closures.
In fact, it depends on which closure you are using and the relations between them and if there can be retained cycle so you should consider capturing the right closure as weak.
In your case, with present(_, animated:, completion:), the completion block is non-escaping so if you want to use weak reference you can use it but it is not necessary to use.
Non-escaping closures do not require [weak self] unless you care about delayed deallocation
Please check the article about weak, unowned references in nested closures.
I made a small test in the playground that shows me that the compiler is indeed quite smart and tells ARC not to retain.
class WeakThingy {
var variable: Int
init(variable: Int) {
self.variable = variable
}
deinit {
print("deinit WeakThingy")
}
}
class ClosureTest {
var maybeNil: WeakThingy
init(maybeNil: WeakThingy) {
self.maybeNil = maybeNil
}
deinit {
print("deinit ClosureTest")
}
func bien() {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak maybeNil] in
print("first \(String(describing: maybeNil))")
maybeNil?.variable = 12
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
print("second \(String(describing: maybeNil))")
maybeNil?.variable = 12
}
}
}
}
var closureTest:ClosureTest? = ClosureTest(maybeNil: WeakThingy(variable: 12))
closureTest?.bien()
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
closureTest = nil
}
What's printed is the following
first Optional(__lldb_expr_34.WeakThingy)
deinit ClosureTest
deinit WeakThingy
second nil
What happen here is that I pass maybeNil in the first closure as weak, but not in the second. Then I make it nil before the second closure gets executed. We can see in the output that it is well deallocated before entering the second closure.

Not receiving inputs when using `.receive(on: DispatchQueue.main)`

I’m trying to change to the main thread in the downstream with .receive(on: DispatchQueue.main) but then I don’t receive inputs when using either .subscribe(:) or .sink(receiveValue:). If I don’t change threads I do receive the proper inputs.
Publisher
extension URLSessionWebSocketTask {
struct ReceivePublisher: Publisher {
typealias Output = Message
typealias Failure = Error
let task: URLSessionWebSocketTask
func receive<S>(subscriber: S) where S: Subscriber, Output == S.Input, Failure == S.Failure {
task.receive { result in
switch result {
case .success(let message): _ = subscriber.receive(message)
case .failure(let error): subscriber.receive(completion: .failure(error))
}
}
}
}
}
extension URLSessionWebSocketTask {
func receivePublisher() -> ReceivePublisher {
ReceivePublisher(task: self)
}
}
Subscriber
extension ViewModel: Subscriber {
typealias Input = URLSessionWebSocketTask.Message
typealias Failure = Error
func receive(subscription: Subscription) {}
func receive(_ input: URLSessionWebSocketTask.Message) -> Subscribers.Demand {
// Handle input here.
// When using `.receive(on:)` this method is not called when should be.
return .unlimited
}
func receive(completion: Subscribers.Completion<Error>) {}
}
Subscribe
socketTask.receivePublisher()
.receive(on: DispatchQueue.main)
.subscribe(viewModel)
socketTask.resume()
The AnyCancellable returned by subscribe<S>(_ subject: S) -> AnyCancellable will call cancel() when it has been deinitialized. Therefore if you don't save it it will be deinitialized when the calling block goes out of scope.
Out of the videos and tutorials I have seen from WWDC, how to work with this was never addressed. What I've seen is that people are drifting towards RxSwift's DisposeBag solution.
Update Beta 4:
Combine now comes with a method on AnyCancellable called: store(in:) that does pretty much what my old solution does. You can just store the AnyCancellables in a set of AnyCancellable:
var cancellables = Set<AnyCancellable>()
...
override func viewDidLoad() {
super.viewDidLoad()
...
socketTask.receivePublisher()
.receive(on: DispatchQueue.main)
.subscribe(viewModel)
.store(in: &cancellables)
}
This way the array (and all AnyCancellables) will be deinitialized when the containing class is deinitialized.
Outdated:
If you want a solution for all Cancellables that can be used in a way that flows better you could extend Cancellable as such:
extension Cancellable {
func cancel(with cancellables: inout [AnyCancellable]) {
if let cancellable = self as? AnyCancellable {
cancellables.append(cancellable)
} else {
cancellables.append(AnyCancellable(self))
}
}
}

Closure recursion and retain cycles

My closure retains itself. It causes capturing all other objects inside. I can pass such objects using weak reference, but it doesn't solve the problem of retain cycle. What's the right way to do recursion with closures without retain cycles?
class Foo {
var s = "Bar"
deinit {
print("deinit") // Won't be executed!
}
}
class TestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo() // Weak works, but not the right solution.
var closure: () -> Void = { return }
closure = {
print(foo.s)
if true {
return
} else {
closure()
}
}
}
}
You have an unusual setup where your closure retains itself. Note that Swift doesn't allow you to create a weak reference to a closure.
To break the retain cycle, set closure to { } in the base case of the recursion. Here's a test macOS command-line program:
func test() {
var closure: ((Int) -> ()) = { _ in }
closure = { i in
if i < 10 {
closure(i + 1)
} else {
// Comment out this line for unbounded memory consumption.
closure = { _ in }
}
}
closure(0)
}
while true {
test()
}
If you run this, its memory consumption is flat.
If you comment out the line in the base case that resets closure, its memory consumption grows without bound.
Your closure is holding foo instance reference.
foo will be released as soon as the closure is released.
closure is calling itself. If we pass weak self inside closure then that should be fine. OR by resetting closure
below code should work fine.
var closure: () -> Void = { return }
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
closure = { [weak self] in
print(foo.s)
if true {
return
} else {
self?.closure()
}
}
}
OR initialize foo inside closure
override func viewDidLoad() {
super.viewDidLoad()
var closure: () -> Void = { return }
closure = { [weak self] in
let foo = Foo()
print(foo.s)
if true {
return
} else {
self?.closure()
}
}
}
Turn your closure into a nested function:
class Foo {
var s = "Bar"
deinit {
print("deinit")
}
}
class TestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
func nestedFunction() {
print(foo.s)
if true {
return
} else {
nestedFunction()
}
}
nestedFunction()
}
}
In Swift nested functions can refer to themselves synchronously (recursive functions) or asynchronously (typically for asynchronous iteration), can do so without any reference cycle, and can capture variables just as well as closures do. You can even have mutually recursive nested functions.
You could instead reset the closure-containing variable to a dummy closure once done, I am not saying this does not work, but this is very error-prone, especially when the closure calls itself asynchronously: the reset has to be done asynchronously as well in that case. Better have the lack of a reference cycle be ensured statically, as can be done most everywhere else in Swift.
(The concept used to have a bad rap due to an implementation in the C language by gcc that introduced security holes as a result of attempting to squeeze a closure reference into a C function pointer i.e. a code address, but Swift nested functions have nothing to do with that)

Lazy function in Swift

Could anyone tell me why in this 'odd' code (I'm having fun with Swift ;D) in lazy functions runEngine and stopEngine, print method is never executed?
(please run this code in playground).
Thanks!
protocol EngineDelegate {
func engineDidStart()
func engineDidStop()
}
class Engine {
var delegate: EngineDelegate?
lazy var runEngine : () -> () = {
print("Engine has been started")
self.delegate?.engineDidStart()
}
lazy var stopEngine : () -> () = {
print("Engine has been stoped")
self.delegate?.engineDidStop()
}
}
class Car: EngineDelegate {
let engine = Engine()
init() {
engine.delegate = self
}
func engineDidStop() {
print("MyOwnStop")
}
func engineDidStart() {
print("MyOwnStart")
}
}
let car = Car()
car.engine.runEngine()
The code runs as expected for me.
At first I thought that the lazy modifier was unnecessary but it is. When Engine is instantiated, its delegate is nil and that value is what is captured by the closure. Using lazy deferred that capture until its use which by that time engine.delegate had been set. While we might be able to use #autoclosure somehow, the best solution is to just make runEngine and stopEngine functions.
func runEngine() {
print("Engine has been started")
delegate?.engineDidStart()
}
func stopEngine() {
print("Engine has been stoped")
delegate?.engineDidStop()
}

Closure property bad access in swift (EXC_BAD_ACCESS)

I have the Test class with button_action optional closure:
class Test : CustomViewFromXib {
var button_action : (() -> ())?
#IBAction func button_pressed(sender: AnyObject) {
if let action = button_action {
action()
}
}
}
This is how I use this class:
let test_view = Test(frame: CGRect.nullRect)
self.view.addSubview(test_view)
test_view.button_action = {
() -> () in
print("test")
}
I get EXC_BAD_ACCESS error at line:
test_view.button_action = {
() -> () in
print("test")
}
I don't know why, because I just want to set initial value. Is it possible to do it that way?
UPDATE:
I understood, that no one property or method can't be called from my object. Not only closures, but Strings (for example) too.
UPDATE 2:
This is my little example of code that reproduces the problem. I think I have a problem with initializers...
https://www.dropbox.com/s/1d8fvxm0es9b5n4/TestInit.zip
(XCode 6 Beta 5)
Write code
let test_view = Test(frame: CGRect.nullRect)
self.view.addSubview(test_view)
test_view.button_action = {
() -> () in
print("test")
}
instead of
let test_view = Test(frame: CGRect.nullRect)
self.view.addSubview(test_view)
test_view.button_action = { [unowned self]
() -> () in
print("test")
}
Here is exact detail theoretical answer
Shall we always use [unowned self] inside closure in Swift
https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html

Resources