I'm new to Swift and looking at how the dispatch_async function works. The API doc shows dispatch_async having two parameters. However, I'm able to pass in one argument and it's okay.
dispatch_async(dispatch_get_main_queue()) {
}
How come I don't need to pass in two arguments?
Thank you,
API Doc:
It is a trailing closure syntax
func someFunctionThatTakesAClosure(closure: () -> ()) {
// function body goes here
}
// here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure({
// closure's body goes here
})
// here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html
This is how the dispatch_async looks like..
dispatch_async(dispatch_get_main_queue(), ^{
});
this part
^{
}
is the second parameter to your function, which is an anonymous code block used for callBack implementation.
Related
In addition to function dispatch_async, that submits a block for asynchronous execution, iOS provides another function dispatch_async_f to submit a function with a single parameter for asynchronous execution.
in Swift, I can call dispatch_async as DispatchQueue.global().async {}, but I did not find any way to call dispatch_async_f.
So, how do I pass a parameter to a block executed asynchronously?
dispatch_async_f() can be used in C code, which has no blocks or closures.
In Swift you simply pass a closure, and the closure calls the function:
DispatchQueue.global().async {
let theParameter = ...
theFunction(theParameter)
}
The closure can also capture values when created:
let theParameter = ...
DispatchQueue.global().async {
theFunction(theParameter)
}
I have an error when I try to assign a value to the function parameter while inside a completion block, I get an error that reads 'escaping closures can only capture inout parameters explicitly by value' .
How could I fix this? Any tip is much appreciated!
func fetchCurrentUser(user: inout User? ) {
self.fetchUser(withId: AuthProvider.sharedInstance.currentUserId(), completionHandler: {
fetchedUser in
guard let newUser = fetchedUser else { return }
user = newUser // error Here
})
}
This will not work, because you use a completion handler. The self.fetchUser will (almost) immediately return and the completion handler will be executed whenever the background work (most likely a network request) is finished.
Your function fetchCurrentUser calls self.fetchUser and than returns so it will return before the completion block is even executed.
You cannot use inout parameter on escaping closures (this is what the error message also tells you). A escaping closure is a closure which will be executed after the function which you pass it in returns.
You can either rewrite your function to also use a completion hander or change you function to wait for the completion handler to run before ending the fetchCurrentUser function. But for the second approach please be aware that this also will block the caller of the function from executing anything else.
I suggest this refactor:
func fetchCurrentUser(callback: #escaping (User) -> ()) {
self.fetchUser(withId: AuthProvider.sharedInstance.currentUserId(), completionHandler: {
fetchedUser in
guard let newUser = fetchedUser else { return }
callback(newUser)
})
}
or if you want fetchCurrentUser to be synchronous you could use semaphores
I was checking through the Alamofire documentation and found the below code
Alamofire.request("https://httpbin.org/get").responseJSON { response in
debugPrint(response)
if let json = response.result.value {
print("JSON: \(json)")
}
}
It seems as if the function is written as
Class.Function().Function{
}
Is this called a nested function? If so how would I create a simple nested function to know the syntax
this is not a nested function but a chain of functions.
class Alamofire {
static func request(_ url: String)->Request {
//... code ...
return aRequest
}
}
class Request {
func responseJson(completion: (response: Response)->()) {
//code
}
}
So this is what is happening.
The request function of Alamofire is returning a Request object which has the responseJson function that accepts a closure as parameter.
In swift if the closure parameter is the last one, the function call can be synthesized by removing the parameter name and define the closure as a function so to do
Alamofire.request("whatever").responseJson(completion: { (response) in
//whatever
})
is exactly the same as doing
Alamofire.request("whatever").responseJson(){ (response) in
//whatever
}
This is a trailing closure. You can find more info about it here in the "Trailing Closure" paragraph.
Hope it helps
It's Method chaining and last one is the syntax of trailing closures.
Closures are self-contained blocks of functionality that can be passed
around and used in your code.
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
// closure's body goes here
})
// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
For more information about closures read it
I have a function with this prototype:
func myFunction(completionHandler:((response:[NSString:AnyObject])->Void)?))
The completionHandler prototype can be passed as closure or as a function... passing it as closure I know how to define a capture list with this syntax [weak self], but how can I define a capture list if instead of defining the closure directly in the function argument I want to pass a function name?
myFunction(anotherFunction) // how to set capture list from here?
VS
myFunction{
[weak self] (response) in
}
```
EDIT-----
A possible solution is to wrap the function code into a block, set the capture list and execute the block... but it sounds so strange :/
myFunction(anotherFunction) // how to set capture list from here?
.
.
.
func anotherFunction(response:[NSString:AnyObject]) {
let safeBlock = {
[weak self] in {
self?.callSomethingSafely()
}
}
safeBlock()
}
EDIT (based on correction from Hamish below):
I'm not aware of a way to force a referenced method to internally use a weak version of a captured variable. As you have in your example, it's up to to the actual method implementation to do that or not.
However, it's worth noting that unless you are going to be storing a reference to that completion handler indefinitely, you don't need to worry about weak self.
I assume that completion handler will be called as soon as some asynchronous task that myFunction kicks off is completed. In that case, any references captured by the completion handler will only be held until the completion handler runs. Then those references will be released and there won't be any retain cycles. Weak self in closures in only important if "self" retains the closure and the closure captures "self", setting up a circular reference / retain cycle.
#MatterGoal your solution will still produce a reference cycle.
I am assuming you are aware of the situations where we should use a capture list. For a scenario like myFunction(anotherFunction), we cannot define a capture list for a method (func) named anotherFunction itself. At least for now, lets hope in future we can.
We can only define a capture for a closure. A method can act as a closure with same signature but it (method) does not support capture list for itself.
Solutions:
Make a lazy var anotherFunction = { } in which we can define capture list.
Make your function return a closure:
func anotherFunction() -> (() -> Void) {
return { [weak self] in
// do anything you want with self? properties or methods.
// this won't create a strong reference cycle
}
}
I have come across this code:
class WebServerTests: XCTestCase {
let webServer: GCDWebServer = GCDWebServer()
var webServerBase: String!
/// Setup a basic web server that binds to a random port and that has one default handler on /hello
private func setupWebServer() {
webServer.addHandlerForMethod("GET", path: "/hello", requestClass: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in
return GCDWebServerDataResponse(HTML: "<html><body><p>Hello World</p></body></html>")
}
I am confused by the webServer.addHandlerForMethod part. It seems to me it is already a complete function call (webServer.addHandlerForMethod("GET", path: "/hello", requestClass: GCDWebServerRequest.self)). Therefore I do not understand why it is followed by a closure ( {(request) -> ... )
EDIT: Clarify what I do not understand
According to the documentation on https://github.com/swisspol/GCDWebServer, the function signature in obj-c is:
[webServer addDefaultHandlerForMethod:#"GET"
requestClass:[GCDWebServerRequest class]
asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
Therefore I expect its swift counterpart will be called somewhat like this:
webServer.addHandlerForMethod("GET", path: "/hello", requestClass: GCDWebServerRequest.self, { (request) -> GCDWebServerResponse! in
return GCDWebServerDataResponse(HTML: "<html><body><p>Hello World</p></body></html>")
})
i.e. the handling of the incoming request is passed as the third parameter. But since the closure comes after the closing ')', it does not look like part of the function call at all.
Why the function signature is mapped from obj-c to swift this way?
In Swift, you can use this syntax if the last argument to a function is a closure. Here's the example from the Swift language guide section about closures (scroll down to Trailing Closures):
func someFunctionThatTakesAClosure(closure: () -> ()) {
// function body goes here
}
// here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure({
// closure's body goes here
})
// here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
And then there's also this note:
If a closure expression is provided as the function’s only argument and you provide that expression as a trailing closure, you do not need to write a pair of parentheses () after the function’s name when you call the function.
This means it's also legal to write this:
someFunctionThatTakesAClosure {
// closure body
}
… which helps provide a nice meta-programming syntax. For example:
let lock = NSLock()
func locked(closure: () -> ()) {
lock.lock();
closure()
lock.unlock();
}
locked {
NSLog("Hello, world!")
}
The closure is where the handling of the incoming request is done. It tells the server to run the closure's code when a GET method that requests /hello path comes.
In the code you posted code in the closure creates a response that the server returns.