Reputation: 998
import UIKit
class ViewController: UIViewController
{
var icnNum : Int64 = 0
let stopHandler =
{
(action:UIAlertAction!) -> Void in
let num = icnNum
}
func showAlert( userStatus: String )
{
let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)
alert.title = "What you want to do?"
alert.addAction(UIAlertAction(title: "Stop", style: .default, handler: stopHandler))
}
}
I don't know how to access that icnNum
from the handler. Am getting following error. I know that I can't access that variable directly but what is the way.
Upvotes: 4
Views: 295
Reputation: 42588
You can pass a method as the handler. This avoids needing to have a bare closure floating around.
class ViewController: UIViewController {
var icnNum : Int64 = 0
func stopHandler(_ action: UIAlertAction) {
let num = icnNum
}
func showAlert(userStatus: String) {
let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)
alert.title = "What you want to do?"
alert.addAction(UIAlertAction(title: "Stop", style: .default, handler: stopHandler))
}
}
UPDATE
The expected behavior for handlers like this is to use a closure which can include the local context.
func showAlert(userStatus: String) {
let localContext = "Local information"
// …
alert.addAction(UIAlertAction(title: "Stop", style: .default) { action in
if localContext == "Local information" {
// Do Something
}
})
}
However, you don't have a local context. The context you are working from is contained with in the object instance.
func showAlert(userStatus: String) {
// …
alert.addAction(UIAlertAction(title: "Stop", style: .default, handler: stopHandler))
}
Because you don't have anything local used in your handler, you don't need a closure.
func stopHandler(_ action: UIAlertAction) {
let num = icnNum
}
will do the same thing as the closure handler, but gives you the context of the object instance.
Upvotes: 1
Reputation: 1390
Define the stopHandler closure inside the showAlert()
function and it should work.
class ViewController: UIViewController
{
var icnNum : Int64 = 0
func showAlert( userStatus: String ) {
let stopHandler = { (action:UIAlertAction!) -> Void in
let num = self.icnNum
}
let alert = UIAlertController(title: "", message: "", preferredStyle: .Alert)
alert.title = "What you want to do?"
alert.addAction(UIAlertAction(title: "Stop", style: .Default, handler: stopHandler))
}
}
}
The compiler will force you to write self.icnNum
instead of icnNum
to make it obvious that the closure will hold a reference to self.
Storing the stopHandler closure as a variable, like you did in your example, would create a cyclic reference. Your ViewController instance holds a strong reference to the stopHandler closure, the closure holds a strong reference to self (which is a pointer to you ViewController instance).
class ViewController: UIViewController {
var icnNum : Int64 = 0
var stopHandler: ((action:UIAlertAction!) -> Void)?
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.stopHandler = { [weak self] (action:UIAlertAction!) -> Void in
let num = self?.icnNum
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func showAlert( userStatus: String )
{
let alert = UIAlertController(title: "", message: "", preferredStyle: .Alert)
alert.title = "What you want to do?"
alert.addAction(UIAlertAction(title: "Stop", style: .Default, handler: stopHandler))
}
}
Notice the [weak self]
when setting the stopHandler closure. This will prevent the closure from keeping a strong reference to self and avoid the cyclic reference described above.
Upvotes: 5
Reputation: 3310
you can write your closer like this way
let stopHandler = {
(icnNum: Int64 ,action:UIAlertAction!) -> Void in
let num = icnNum
}
while calling this closer like this way
alert.addAction(UIAlertAction(title: "Stop", style: .default, handler: stopHandler(self.icnNum, UIAlertAction!)))
Upvotes: 2