I'm pretty new to Swift. How do I define a function that has a VOID success callback block and a error callback block? I don't need to pass any objects on success, but I do need to know my error.
Example of a function using both success and error callback blocks that pass objects:
func searchForTweetsWithKeyword(searchString: String, geoCodeParameter: String, successCallback: (tweets :[Tweet]) ->(), errorCallback: (errorDictionary: Dictionary<String, String>) ->()) {
...do stuff
}
I want to accomplish something like this, but I'm not sure if I'm doing it correctly syntax wise:
func validateNewItemWithDescription(description: String, quantity: Int, successCallback: () ->(Void), errorCallback: (errorString: String) ->())
{
}
Do you definitely need two callback blocks? How about like call:
func parseCommand (inText: String) -> CommandParseResult
With CommandParseResult:
enum CommandParseResult{
case ValidCommand (Command)
case ErrorResponse (String) }
Then handle something like:
var validCommand: Command?
let commandResult = self.myDictionary.parseCommand(textCommand)
switch commandResult
{
case .ErrorResponse (let errorResponse):
completionMessage = errorResponse.stringByReplacingCaseFormat("<Person>", withString: self.currentPerson)
case .ValidCommand (let returnedCommand):
validCommand = returnedCommand
}
Related
func Test(clo: #escaping (String)->Void)
{
clo($0)
}
it return an error that says :
anonymous closure argument not contained in a closure
I want to be able to do:
Test{ n in
var name = n
name = "Taha"
print(name)}
instead of hard coded String
func Test(clo: #escaping (String)->Void)
{
clo("Taha")
}
That is not how closures work in Swift. And the code you wrote doesn't even make sense. Why do you assign n to name then change the value of name just to print it ?
The function with the closure will call the closure with a given value. You can think of closures as lambda functions. Here is an example:
func test(_ closure: #escaping (String) -> Void) {
closure("My string")
}
test { str in
print(str) //prints " My string"
}
For what you are trying to achieve, just use a String parameter in your function:
func test(_ str: String) {
print(str)
}
test("My string") // prints "My string"
Or use a closure that takes Void:
func test(_ closure: #escaping (Void) -> Void) {
closure()
}
test {
print("My string") // prints "My string"
}
I try to write a method as below:
class ThisIsExample{
func theMethod(inside:((Error?)->Void)->Void){
//some implementation
}
}
But, when I try to call this method, I don't know how to do that.
I wrote code below:
let example = ThisIsExample()
example.theMethod { ({(err) in }) in
print("print something")
}
I try to write another closure, which is { (err) in } inside the closure
But it is not workable, I'll receive error message like
Contextual closure type '((Error?) -> Void) -> Void' expects 1
argument, but 0 were used in closure body
So...could anyone please teach me how to call this method in correct way, thank you so much.
Although not sure what is the purpose of nested closure. But if you want to use this approach then you should call the closure in this way,
example.theMethod { (closure) in
closure(NSError.init())
}
You can do some thing like this:
func theMethod(inside:(Error?) -> ()) {
print("Closure as paramater")
}
This will take Error as closure parameter and return void.
you can call this function as below:
theMethod { (error) in
}
Something Like This
class NewClass
{
class func myCustomFunc(_ parameter1: String, parameterDict : [String : AnyObject]?, success:#escaping (String) -> Void, failure:#escaping (String) -> Void)
{
/// Just example Bool
var result : Bool = false
/// Get the parameter you sent while calling this Clousure block
let myParamString = parameter1
let paramDict = parameterDict
/// Share the output in case of Success and Failure
if (result){
success("success")
}
else{
failure("Failure")
}
}
}
Usage
NewClass.myCustomFunc("demoStr", parameterDict: [:], success: { (succesString) in
if succesString == "success"{
}
}) { (failureStr) in
if failureStr == "failure"{
}
}
This Function Accepts Parameter and Also give Different blocks depend upon closures
Introduction:
I'm introducing a Result framework (antitypical) in some points of my app. In example, given this function:
func findItem(byId: Int, completion: (Item?,Error?) -> ());
foo.findItem(byId: 1) { item, error in
guard let item = item else {
// Error case
handleError(error!)
return;
}
// Success case
handleSuccess(item)
}
I implement it this way with Result:
func findItem(byId: Int, completion: Result<Item,Error>) -> ());
foo.findItem(byId: 1) { result in
swith result {
case let success(item):
// Success case
handleSuccess(item)
case let failure(error):
// Error case
handleError(error!)
}
}
Question
What is the correct way of implementing a result where the success case returns nothing?. Something like:
func deleteItem(byId: Int, completion: (Error?) -> ());
foo.deleteItem(byId: 1) { error in
if let error = error {
// Error case
handleError(error)
return;
}
// Success case
handleSuccess()
}
In java I would implement a Result whats the correct way to do this in Swift
The best way is exactly what you've done: Error? where nil indicates success. It's quite clear and simple.
That said, another answer (and one that I've used) is exactly in your question: "How to handle Void success case with Result." The success case passes Void, so pass Void:
Result<Void, Error>
"Void" doesn't mean "returns nothing." It's a type in Swift, a type that has exactly one value: the empty tuple (). That also happens to be the type:
public typealias Void = ()
As a matter of convention, we use Void to mean the type, and () to mean the value. The one thing that's a bit strange about using Void this way in a Result is the syntax. You wind up with something like:
return .success(())
The double-parentheses are a little ugly and slightly confusing. So even though this is nicely parallel to other Result-using code, I typically just use Error? in this case. If I had a lot of it, though, I'd consider creating a new type for it:
enum VoidResult {
case .success
case .failure(Error)
}
You can add this extension, to simplify your life.
public extension Result where Success == Void {
/// A success, storing a Success value.
///
/// Instead of `.success(())`, now `.success`
static var success: Result {
return .success(())
}
}
// Now
return .success
Gists
I found Rob's answer really interesting and smart. I just want to contribute with a possible working solution to help others:
enum VoidResult {
case success
case failure(Error)
}
/// Performs a request that expects no data back but its success depends on the result code
/// - Parameters:
/// - urlRequest: Url request with the request config
/// - httpMethodType: HTTP method to be used: GET, POST ...
/// - params: Parameters to be included with the request
/// - headers: Headers to be included with the request
/// - completion: Callback trigered upon completion
func makeRequest(url: URL,
httpMethodType: HTTPMethodType,
params: [String:Any],
headers: [String:String],
completion: #escaping (VoidResult) -> Void){
let alamofireHTTPMethod = httpMethodType.toAlamofireHTTPMethod()
let parameterEncoder: ParameterEncoding
switch alamofireHTTPMethod {
case .get:
parameterEncoder = URLEncoding.default
case .post:
parameterEncoder = JSONEncoding.default
default:
parameterEncoder = URLEncoding.default
}
Log.d(message: "Calling: \(url.absoluteString)")
AF.request(url,
method: alamofireHTTPMethod,
parameters: params,
encoding:parameterEncoder,
headers: HTTPHeaders(headers)).response { response in
guard let statusCode = response.response?.statusCode,
(200 ..< 300) ~= statusCode else {
completion(.failure(NetworkFetcherError.networkError))
return
}
completion(.success)
}
}
Try this
Note this is example you can change as per your test
typealias resultHandler = (_ responseItems: AnyObject, _ error: Error) -> Void
func deleteItem(byId: Int, completion: resultHandler){
completion(Items, error)
}
Calling
self.deleteItem(byId: 1) { (result, error) in
if error ==nil{
}
}
A pretty handy feature of Swift functions is that function parameters can have default values:
func someFunction(parameterWithDefault: Int = 42) {
//if no arguments are passed to the function call,
//value of parameterWithDefault is 42
}
If a parameter is a closure, is there a way to make it have a default value? See the example below:
func sendBody(
body: NSData? = nil,
success: (data: NSData) -> Void,
failure: (data: NSData?) -> Void) {
}
Is there a way to not force the developer to pass a value for success or failure when calling sendBody?
Yes, functions are just values, so you can supply them as defaults
// just to show you can do it with inline closures or regular functions
func doNothing<T>(t: T) -> Void { }
func sendBody(
body: NSData? = nil,
success: (data: NSData) -> Void = { _ in return },
failure: (data: NSData?) -> Void = doNothing
)
{ }
Alternatively, you could make them optional, that way you can detect if the caller passed one:
func sendBody(
body: NSData? = nil,
success: ((NSData) -> Void)? = nil,
failure: ((NSData?) -> Void)? = nil
)
{ success?(NSData()) }
sendBody(success: { _ in print("ah, yeah!") })
Also worth noting if you’re doing this: if the caller uses the trailing closure syntax, this will be the last closure in the argument list. So you want the last one to be the one the user is most likely to want to supply, which is probably the success closure:
func sendBody(
body: NSData? = nil,
success: ((NSData) -> Void)? = nil,
failure: ((NSData?) -> Void)? = nil
)
{
if success != nil { print("passed a success closure") }
if failure != nil { print("passed a failure closure") }
}
// this prints "passed a failure closure"
sendBody { data in
print("which closure is this?")
}
Other than this, the order in the function declaration doesn’t matter to the caller – defaulted arguments can be supplied in any order.
You could do something like this,
let defaultSuccess: NSData -> Void = {
(data: NSData) in
}
let defaultFailure: NSData? -> Void = {
(data: NSData?) in
}
func sendBody( body: NSData? = nil, success: (data: NSData) -> Void = defaultSuccess, failure: (data: NSData?) -> Void = defaultFailure) {
}
Then, you may be able to call either one of these methods. Notice sendBody which is called with default parameters.
sendBody()
sendBody(body: , success: , failure: )
You can also call with all the variants like passing just one of the argument in the above method, for that you have to call it with named parameter.
sendBody()
sendBody(body:)
sendBody(failure: )
sendBody(success:)
sendBody(body: , success: , failure: )
How to set a default value for a function parameter. Swift 4 and (probably) 5.
func someFunction(age: Int, doSomething:#escaping () -> Void = {}){
//do work here
//
doSomething()
}
Then you can do this
someFunction(age: 18) {
print("hello")
}
someFunction(age: 19)
You may or may not need to use the #escaping keyword. See Swift #escaping and Completion Handler for that.
My preferred way to specify public facing closures - in particular completion closures which you might want to store somewhere for later - is to define a typealias for them, like this:
public typealias FooCompletion = (String) -> Void
Then in the public facing function you can easily make it optional like this:
var onCompletion: FooCompletion? = nil
public func foo(completion: FooCompletion? = nil) {
// Store completion for later
onCompletion = completion
}
The completion parameter is optional, so it's allowed to be nil, and the default value is nil, meaning the caller doesn't have to specify it. Also, because you use the type in more than one place, if you need to change its definition during development there's only one place to do so. It's easy to call too:
private func someBackgroundThing() {
var completionString = "done"
...
onCompletion?(completionString)
}
I've implemented a simple delegate pattern and I need to call delegate methods in the main queue. This is the code that perform this call:
dispatch_async(dispatch_get_main_queue()){
self.delegate?.readerDidCompleteDownload(self, data: tempData)
}
but I can't compile because of this error
Could not find member: readerDidCompleteDownload:
The method is implemented in the delegate and the protocol correctly defines it
#objc protocol DBDataReaderDelegate{
func readerDidCompleteDownload(reader: DBDataReader, data:String[])
#optional func readerDidFailDownload(reader: DBDataReader)
}
If I call this method outside the dispatch_async it works correctly.
What I'm doing wrong?!
Edit
I'm calling this method in NSURLSessionDownloadDelegate function... I report here the full code just to add more information to this question:
func URLSession(session: NSURLSession!, downloadTask: NSURLSessionDownloadTask!, didFinishDownloadingToURL location: NSURL!){
let data = NSData(contentsOfURL: location)
var error:NSError
let string = NSString(data: data, encoding: NSUTF8StringEncoding)
if let JSONObj:NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? NSDictionary {
var tempData:String[] = String[]()
if let shots = JSONObj["shots"] as? NSDictionary[]{
for (index, element) in enumerate(shots){
if let title:String = element["title"] as? String{
tempData += title
}
}
dispatch_async(dispatch_get_main_queue()){
self.delegate?.readerDidCompleteDownload(self, data: tempData)
}
}
}else{
delegate?.readerDidFailDownload?(self)
}
}
„The type of this function is () -> (), or “a function that has no parameters,
and returns Void.” Functions that don’t specify a return value always
return Void, which is equivalent to an empty tuple in Swift, shown as ().”
Apple Inc. „The Swift Programming Language”. iBooks
Because delegate is optional type and can be nil, and every function or method in Swift must return value, for example Void!, (), you just need to add tuple () at the end of dispatch_async
dispatch_async(dispatch_get_main_queue()){
self.delegate?.readerDidCompleteDownload(self, data: tempData)
()
}
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.delegate?.readerDidCompleteDownload(self, data: tempData)
}
Without () -> Void in, Swift infers the type of the closure. The inferred result comes from "optional chaining" readerDidCompleteDownload, so it is Void?. That makes the inferred closure type () -> Void? (optional Void) which is not the same as what dispatch_block_t is: () -> Void (non-optional Void).
This could use some syntactic sugar in Swift.