func customPrint(number: Int, via printingFunction: #escaping (Int) -> Void) {
printingFunction(number)
}
class Temp {
func tempPrintingFunction(number i: Int) {
print(i)
}
func print5() {
customPrint(number: 5) { [self] number in
tempPrintingFunction(number: number)
}
}
}
Temp().print5()
This code is fine: compiles and works as expected.
But when I pass function itself in capture list instead of self:
func print5() {
customPrint(number: 5) { [tempPrintingFunction] number in
tempPrintingFunction(number: number)
}
}
I get the error:
Extraneous argument label 'number:' in call
When I remove the label, everything backs to normal.
But it's weird. What is it? Bug or feature? I can't find any information about this neither in documentation nor on forums.
Bonus question:
Why doesn't the code crash, when I pass unowned self to the capture list? Shouldn't it crash? I want it to crash 🙂
Edited:
By the way, is there any difference in this situation between capturing self and function itself? In terms of retain cycles, etc. If we capture function, self will be captured as well, isn't it?
Related
In Swift I am trying to implement a method "tap" similar to the method which exists in Ruby.
I've come up with the following example code:
private protocol Tap {
mutating func tap(_ block: (inout Self) -> Void) -> Self
}
private extension Tap {
mutating func tap(_ block: (inout Self) -> Void) -> Self {
block(&self)
return self
}
}
extension Array: Tap {}
var a = Array(repeating: "Hello", count: 5)
a.tap {
$0.append("5")
}.tap {
$0.append("7")
}
print(a) // (Expected) => ["Hello", "Hello", "Hello", "Hello", "Hello", "5", "7"]
I'm not super familiar with mutating functions, inout parameters, or Swift in general, but the code above looks like it should work to me. tap works as expected when it's not being included in a method chain. When I include it as part of a method chain, like in the above example, the Swift compiler complains:
Cannot use mutating member on immutable value: function call returns immutable value
Can anyone explain to me why this doesn't work? Can anyone provide a working solution and explain why that solution works?
Edit:
Another example usage would be:
let user = User(fromId: someId).tap {
$0.firstName = someFirstName
$0.lastName = someLastName
}
tap is a convenience thing that comes from Ruby. I'm mainly interested in understanding why the types in my function aren't working out right.
The return self returns a copy of the original array, not the original array itself. Until this copy is stored as a var, it cannot be mutated. So, this would work:
var b = a.tap {
$0.append("5")
}
b.tap {
$0.append("7")
}
But not without storing b as a var first. Of course, you wouldn't create a b in the first place, you would just use a repeatedly as you already pointed out.
So, the issue is that you can accomplish tap once, but cannot chain taps. This is because the return of self is implicitly immutable, and you cannot call a mutating function on an immutable value. Changing tap to a non-mutating function could get you what you want:
private extension Tap {
func tap(_ block: (inout Self) -> Void) -> Self {
let copy = self
block(©)
return copy
}
}
var a = Array(repeating: "Hello", count: 5)
a = a.tap({$0.append("5")}).tap({$0.append("7")})
Because each invocation of tap( returns a copy of the original modified by the given block, you can call it on immutable types. That means that you can chain.
The only downside is that new a = in the beginning.
I've got an error "Closure cannot implicitly capture self parameter". Tell me please how it fix?
struct RepoJson {
...
static func get(url: String, completion: #escaping (RepoJson!) -> ()) {
...
}
}
struct UsersJson {
var repo: RepoJson!
init() throws {
RepoJson.get(url: rep["url"] as! String) { (results:RepoJson?) in
self.repo = results //error here
}
}
}
It's because you're using struct. Since structs are value, they are copied (with COW-CopyOnWrite) inside the closure for your usage. It's obvious now that copied properties are copied by "let" hence you can not change them. If you want to change local variables with callback you have to use class. And beware to capture self weakly ([weak self] in) to avoid retain-cycles.
I have an extension Array in the form of:
extension Array
{
private func someFunction(someClosure: (() -> Int)?)
{
// Do Something
}
func someOtherFunction(someOtherClosure: () -> Int)
{
someFunction(someClosure: someOtherClosure)
}
}
But I'm getting the error: Passing non-escaping parameter 'someOtherClosure' to function expecting an #escaping closure.
Both closures are indeed non-escaping (by default), and explicitly adding #noescape to someFunction yields a warning indicating that this is the default in Swift 3.1.
Any idea why I'm getting this error?
-- UPDATE --
Screenshot attached:
Optional closures are always escaping.
Why is that? That's because the optional (which is an enum) wraps the closure and internally saves it.
There is an excellent article about the quirks of #escaping here.
As already said, Optional closures are escaping. An addition though:
Swift 3.1 has a withoutActuallyEscaping helper function that can be useful here. It marks a closure escaping only for its use inside a passed closure, so that you don't have to expose the escaping attribute to the function signature.
Can be used like this:
extension Array {
private func someFunction(someClosure: (() -> Int)?) {
someClosure?()
}
func someOtherFunction(someOtherClosure: () -> Int) {
withoutActuallyEscaping(someOtherClosure) {
someFunction(someClosure: $0)
}
}
}
let x = [1, 2, 3]
x.someOtherFunction(someOtherClosure: { return 1 })
Hope this is helpful!
The problem is that optionals (in this case (()-> Int)?) are an Enum which capture their value. If that value is a function, it must be used with #escaping because it is indeed captured by the optional.
In your case it gets tricky because the closure captured by the optional automatically captures another closure. So someOtherClosure has to be marked #escaping as well.
You can test the following code in a playground to confirm this:
extension Array
{
private func someFunction(someClosure: () -> Int)
{
// Do Something
}
func someOtherFunction(someOtherClosure: () -> Int)
{
someFunction(someClosure: someOtherClosure)
}
}
let f: ()->Int = { return 42 }
[].someOtherFunction(someOtherClosure: f)
I am using Firebase to observe event and then setting an image inside completion handler
FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.img = UIImage(named:"Some-image")!
} else {
self.img = UIImage(named: "some-other-image")!
}
})
However I am getting this error
Closure cannot implicitly capture a mutating self parameter
I am not sure what this error is about and searching for solutions hasn't helped
The short version
The type owning your call to FirebaseRef.observeSingleEvent(of:with:) is most likely a value type (a struct?), in which case a mutating context may not explicitly capture self in an #escaping closure.
The simple solution is to update your owning type to a reference once (class).
The longer version
The observeSingleEvent(of:with:) method of Firebase is declared as follows
func observeSingleEvent(of eventType: FIRDataEventType,
with block: #escaping (FIRDataSnapshot) -> Void)
The block closure is marked with the #escaping parameter attribute, which means it may escape the body of its function, and even the lifetime of self (in your context). Using this knowledge, we construct a more minimal example which we may analyze:
struct Foo {
private func bar(with block: #escaping () -> ()) { block() }
mutating func bax() {
bar { print(self) } // this closure may outlive 'self'
/* error: closure cannot implicitly capture a
mutating self parameter */
}
}
Now, the error message becomes more telling, and we turn to the following evolution proposal was implemented in Swift 3:
SE-0035: Limiting inout capture to #noescape contexts
Stating [emphasis mine]:
Capturing an inout parameter, including self in a mutating
method, becomes an error in an escapable closure literal, unless the
capture is made explicit (and thereby immutable).
Now, this is a key point. For a value type (e.g. struct), which I believe is also the case for the type that owns the call to observeSingleEvent(...) in your example, such an explicit capture is not possible, afaik (since we are working with a value type, and not a reference one).
The simplest solution to this issue would be making the type owning the observeSingleEvent(...) a reference type, e.g. a class, rather than a struct:
class Foo {
init() {}
private func bar(with block: #escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
Just beware that this will capture self by a strong reference; depending on your context (I haven't used Firebase myself, so I wouldn't know), you might want to explicitly capture self weakly, e.g.
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
Sync Solution
If you need to mutate a value type (struct) in a closure, that may only work synchronously, but not for async calls, if you write it like this:
struct Banana {
var isPeeled = false
mutating func peel() {
var result = self
SomeService.synchronousClosure { foo in
result.isPeeled = foo.peelingSuccess
}
self = result
}
}
You cannot otherwise capture a "mutating self" with value types except by providing a mutable (hence var) copy.
Why not Async?
The reason this does not work in async contexts is: you can still mutate result without compiler error, but you cannot assign the mutated result back to self. Still, there'll be no error, but self will never change because the method (peel()) exits before the closure is even dispatched.
To circumvent this, you may try to change your code to change the async call to synchronous execution by waiting for it to finish. While technically possible, this probably defeats the purpose of the async API you're interacting with, and you'd be better off changing your approach.
Changing struct to class is a technically sound option, but doesn't address the real problem. In our example, now being a class Banana, its property can be changed asynchronously who-knows-when. That will cause trouble because it's hard to understand. You're better off writing an API handler outside the model itself and upon finished execution fetch and change the model object. Without more context, it is hard to give a fitting example. (I assume this is model code because self.img is mutated in the OP's code.)
Adding "async anti-corruption" objects may help
I'm thinking about something among the lines of this:
a BananaNetworkRequestHandler executes requests asynchronously and then reports the resulting BananaPeelingResult back to a BananaStore
The BananaStore then takes the appropriate Banana from its inside by looking for peelingResult.bananaID
Having found an object with banana.bananaID == peelingResult.bananaID, it then sets banana.isPeeled = peelingResult.isPeeled,
finally replacing the original object with the mutated instance.
You see, from the quest to find a simple fix it can become quite involved easily, especially if the necessary changes include changing the architecture of the app.
If someone is stumbling upon this page (from search) and you are defining a protocol / protocol extension, then it might help if you declare your protocol as class bound. Like this:
protocol MyProtocol: class {
...
}
You can try this! I hope to help you.
struct Mutating {
var name = "Sen Wang"
mutating func changeName(com : #escaping () -> Void) {
var muating = self {
didSet {
print("didSet")
self = muating
}
}
execute {
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 15, execute: {
muating.name = "Wang Sen"
com()
})
}
}
func execute(with closure: #escaping () -> ()) { closure() }
}
var m = Mutating()
print(m.name) /// Sen Wang
m.changeName {
print(m.name) /// Wang Sen
}
Another solution is to explicitly capture self (since in my case, I was in a mutating function of a protocol extension so I couldn't easily specify that this was a reference type).
So instead of this:
functionWithClosure(completion: { _ in
self.property = newValue
})
I have this:
var closureSelf = self
functionWithClosure(completion: { _ in
closureSelf.property = newValue
})
Which seems to have silenced the warning.
Note this does not work for value types so if self is a value type you need to be using a reference type wrapper in order for this solution to work.
I'm using a Swift learning book about extensions with a closure as a parameter.
In the book, it told me
extension Int {
func repeat(work: () -> ()) {
for _ in 0..<self {
work()
}
}
}
On the line
func repeat(work: () -> ()) {
Xcode tells me
Expected identifier in function declaration
and on the line:
for _ in 0..< self {
Xcode tells me
Braced block of statements is an unused closure
and
Expected ‘{’ to start the body of for-each loop
Can anyone can tell me why these errors occur and what should I do?
There are a number of problems with the posted code:
extensionInt should be extension Int, although I suspect this is a typo in you post
As #Zhao Yi pointed out, repeat is a Swift keyword, you need to rename your function (e.g. repeatWork)
The Swift Half-Open Range Operator requires either an empty space on both sides, or no space on both sides. Both these are valid:
0 ..< self
0..<self
Finally, you can call this function like this:
2.repeatWork({
print("Hello")
})
or this:
2.repeatWork {
print("Hola")
}
repeat is a keyword you can't use as a function name. Rename it to something else:
extension Int {
func repeat1(work: () -> ()) {
for _ in 0..<self {
work()
}
}
}