Store a closure as a variable in Swift
The compiler complains on
var completionHandler: (Float)->Void = {}
because the right-hand side is not a closure of the appropriate signature, i.e. a closure taking
a float argument. The following would assign a "do nothing" closure to the
completion handler:
var completionHandler: (Float)->Void = {
(arg: Float) -> Void in
}
and this can be shortened to
var completionHandler: (Float)->Void = { arg in }
due to the automatic type inference.
But what you probably want is that the completion handler is initialized to nil
in the same way that an Objective-C instance variable is inititialized to nil
. In Swift
this can be realized with an optional:
var completionHandler: ((Float)->Void)?
Now the property is automatically initialized to nil
("no value").
In Swift you would use optional binding to check of a the
completion handler has a value
if let handler = completionHandler {
handler(result)
}
or optional chaining:
completionHandler?(result)
swift closure stored and access as a variable
Here is your working example. You have a number of mistakes which the attached illustrates. Note
I had the download()
method return Bool
so that the result can be see in this screen shot.
But, your use of an implicitly unwrapped optional (aka '!') is incorrect. Such an optional is used when the value may be nil
but will be assigned at a known time and not changed (see Apple documentation for a description). Your downloadCompleted
is a true optional (at least in your example use). Thus, better code, which turns out to be slightly simpler is:
Swift closure giving function to variable
Adding ()
to someFunc
means that you are calling the function and this will evaluate to the return value of someFunc
, which is Void
.
You need to refer to the function directly, without calling it. Just remove the ()
:
a.callback = someFunc
Add value to variable inside closure in swift
The problem is that geocodeAddressString
runs asynchronously (i.e. it takes so long they have written it to return immediately and call its closure later, when the request is done), so viewDidLoad
is printing latLong
well before this property was eventually set in the geocodeAddressString
completion handler closure.
The solution is to adopt asynchronous programming pattern in your own code. For example, employ your own completion handler pattern:
override func viewDidLoad() {
super.viewDidLoad()
findCordiante(adress: "Cupertino, California, U.S.") { string in
// use `string` here ...
if let string = string {
self.latLong = string
print(string)
} else {
print("not found")
}
}
// ... but not here, because the above runs asynchronously and it has not yet been set
}
func findCordiante(adress:String, completionHandler: @escaping (String?) -> Void) {
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(adress) { placemarks, error in
if let location = placemarks?.first?.location, location.horizontalAccuracy >= 0 {
completionHandler("\(location.coordinate.latitude), \(location.coordinate.longitude)")
} else {
completionHandler(nil)
}
}
}
Setting a closure as a variable in Swift and trying to call from Objective C class
Seems you just need to explicitly annotate some properties and types with @objc
:
@objc public enum IAPHelperAlertType: Int {
case disabled
case restored
case purchased
func message() -> String{
switch self {
case .disabled:
return "Purchases are disabled in your device!"
case .restored:
return "You've successfully restored your purchase!"
case .purchased:
return "You've successfully bought this purchase!"
}
}
}
(Added :Int
as suggested by Xcode.)
class IAPHelper: NSObject {
@objc static let shared = IAPHelper()
@objc var purchaseStatusBlock: (@convention(block) (IAPHelperAlertType) -> Void)?
}
(Added two @objc
and @convention(block)
. @convention(block)
makes the closure type compatible with Objective-C blocks.)
With these changes above, you can write something like this in your Objective-C code:
IAPHelper.shared.purchaseStatusBlock(IAPHelperAlertTypeDisabled)
Assign Value from Closure to Variable Swift
change var userId: Int
to var userId: Int!
The reason is that the closure is expecting a value to be in the variable when you "capture it". By using a forcefully unwrapped variable, the closure will be able to capture it as it holds a value of nil, which you can then assign a value to when the closure is called.
How to save variable in closure to external variable?
In the completion block of makeApiCall
simply reload your pickerView's
component on main thread and you all set to go.
SomeClass.makeApiCall(completionHandler: { customds in
self.customDS = customds
DispatchQueue.main.async {
self.reloadComponent(0)
}
})
Related Topics
Swift Package Manager - Uikit Dependency
Print() to Console Log with Color
Bold Part of String in Uitextview Swift
Apply Vertical Alpha Gradient to Uitableview
How to Display Realm Results in Swiftui List
What Is the Advantage of a Lazy Var in Swift
Extend Existing Protocols to Implement Another Protocol with Default Implements
iOS 10 Imessage App Extension: How to Calculate the Height of the Extra Tall Navbar
How to Add an Optional String Extension
How to Set Addobserver in Swiftui
How to Auto Clear Nsuserdefault Values in Swift
How to Declare Enums in Swift of a Particular Class Type
Checking If a Double Value Is an Integer - Swift
How to Write Inline Assembly in Swift
How to Calculate the 21! (21 Factorial) in Swift
Swift 3: Convert a Null-Terminated Unsafepointer<Uint8> to a String