Closure property bad access in swift (EXC_BAD_ACCESS) - ios

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

Related

How to use below closure variable in Swift

I am working on clouser in swift iOS, I have tried to create variable using clouser and add 2 clouser in single variable, variable declaration I did right, but I don't understand how to access it in my code.
here is the variable declaration.
var multipleClouser: ((_ success: (Bool), _ failer:(Error) -> Void)?
Most probably you meant callback, like
var multipleClouser: ((_ success: (Bool), _ failer: (Error?)) -> Void)?
and usage, like
multipleClouser?(true, nil)
or
multipleClouser?(false, SomeErrorHere)
set up like
multipleClouser = { success, error in
if success {
print("Done!")
} else {
print("Failure")
if let error = error {
print("\t with error: \(error)")
}
}
}

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()
}

Stack overflow caused by calling a swift closure in another closure

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.

Function signature error (Swift 1.2)

I get error after update XCode to 6.3 Function signature '(TimeInterval) -> ()' is not compatible with expected type '(value: TimeInterval) -> ()'.
Code is following:
//in `editView` property signature
var changeAction: ((value: TimeInterval)->())?
//usage
editView?.changeAction = { [unowned self] (newValue: EditDateView.TimeInterval) in
self.presentTime = newValue
wPopup?.dismiss(true)
}
Edit:
I found one solution for this:
#IBAction func timePressed() {
// some code
weak var wPopup = popup
func timeChanged(#value: EditDateView.TimeInterval) {
self.presentTime = value
wPopup?.dismiss(true)
}
editView?.changeAction = timeChanged
}
Or:
#IBAction func timePressed() {
// some code
weak var wPopup = popup
editView?.changeAction = timeChanged(wPopup)
}
func timeChanged(wPopup: KLCPopup?)(value: EditDateView.TimeInterval) {
self.presentTime = value
wPopup?.dismiss(true)
}
But this may handle self reference, not sure.
It looks like you might be confusing the type of the closure's parameter with the argument supplied to the closure upon call. It look like this assuming that TimeInterval is a valid type.
editView?.changeAction = { [unowned self] (newValue: TimeInterval) in
self.presentTime = newValue
wPopup?.dismiss(true)
}
Which you would call like this, assuming that EditDateView.TimeInterval is a valid instance of the TimeInterval type.
editView?.changeAction?(value: EditDateView.TimeInterval)

block in Swift : return error " is not convertible to "

I made a mistake but I cannot see how to solve it. I would like to load all the assets from GameScene and send a Bool in a completion method. I use typealias : should it be renamed twice for the two files (gameScene and gameController)?
Then I have got an error on this line GameScene.loadSceneAssetsWithCompletionHandler{ :
((Bool) -> Void) is not convertible to 'GameScene'
Here is the code :
//gameController:
typealias OnComplete = (Bool) -> ()
override func viewDidLoad() {
super.viewDidLoad()
GameScene.loadSceneAssetsWithCompletionHandler{ (success:Bool)->Void in
println("2/ yes")
return
}
//gameScene : rewrite typealias?
typealias OnComplete = (Bool) -> ()
func loadSceneAssetsWithCompletionHandler( completion:OnComplete ) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { () -> Void in
self.loadSceneAssets()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
println("1/ yes")
completion(true)
})//main
})//global
}
I read some threads that said to add a "return", but it does not solve the error here.
Thanks
It's almost working, but you've got a couple things going wrong here. First of all, you can't redeclare a typealias. Second of all you're calling loadSceneAssetsWithCompletionHandler as a class function when it's set up as an instance function. Note changes:
typealias OnComplete = (Bool) -> ()
class GameController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
GameScene.loadSceneAssetsWithCompletionHandler { success in
println("2/ yes")
return
}
}
}
class GameScene: UIViewController {
func loadSceneAssets() {
}
class func loadSceneAssetsWithCompletionHandler( completion:OnComplete ) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
let gameScene = GameScene()
gameScene.loadSceneAssets()
dispatch_async(dispatch_get_main_queue()) {
println("1/ yes")
completion(true)
}
}
}
}

Resources