Closure cannot implicitly capture self parameter. Swift - swift

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.

Related

Cannot convert Generic value to AnyObject, when it is constrained by AnyObject

The error is Cannot convert value of type '(O?, ObservedType) -> Void' to expected argument type '(AnyObject?, ObservedType) -> Void, but I find this curious since O is constrained as AnyObject.
For context, I'm creating my own Observable class, but this question is actually about the specific error message above rather than how I might use any other third-party framework to use observables. That is, how can I properly cast my completion handler in this case.
public class Observable<ObservedType> {
struct Observer<ObservedType> {
weak var observer: AnyObject?
let completion: (AnyObject?, ObservedType) -> Void
}
private var observers: [Observer<ObservedType>]
public var value: ObservedType? {
didSet {
if let _ = value {
notifyObservers()
}
}
}
public init(_ value: ObservedType? = nil) {
self.value = value
observers = []
}
public func observe<O: AnyObject>(forward object: O?, completion: #escaping (O?, ObservedType) -> Void) {
observers.append(Observer(observer: object, completion: completion)) // error here
if let value = value {
completion(object, value)
}
}
private func notifyObservers() {
for observer in observers {
if let value = value {
DispatchQueue.main.async { observer.completion(nil, value) }
}
}
}
}
Is it possible to cast my completion handler in this case, or in some way equate O and AnyObject
According to your types, I can pass any object I want to the first parameter of Observer.completion. But the function you're assigning to .completion can only accept some specific type O.
You have to change completion to (AnyObject?, ObservedType) -> Void.
public func observe<O: AnyObject>(forward object: O?, completion: #escaping (AnyObject?, ObservedType) -> Void) {
^^^^^^^^^^
And the function you pass will have to deal with the fact that it can be passed anything. I suspect that this will break your whole system. But I don't believe this style of Observable is going to work, anyway, because of exactly these kinds of type problems.
There's really no good way to directly store the Observer inside the Observable. You're not currently using it, but I assume you want it for something like removing the observer. There are ways to do that, but you can't store the observer itself. You can return a unique identifier (UUID, for example), or you can work with ObjectIdentifiers or you can pass back "remove this item" closures that the observer must call. But you generally don't want to store the observer directly (and definitely not as an AnyObject).
I recommend using Combine for this, since that's what it's designed for. Or if you need to support older iOS versions, see this experiment for ways to make this work, or this experiment for a simplified version closer to what you're trying to do here.

Why is declaring self not required in structures where it's required in classes?

Why is declaring self not required in structures where it's required in classes? I don't know if there are other examples where this is the case but with escaping closures, it is. If the closure is non-optional (and thus non-escaping), there is no requirement to declare self in either of the two.
class SomeClass {
let someProperty = 1
func someMethod(completion: (() -> Void)?) {}
func anotherMethod() {
someMethod {
print(self.someProperty) // declaring self is required
}
}
}
struct SomeStruct {
let someProperty = 1
func someMethod(completion: (() -> Void)?) {}
func anotherMethod() {
someMethod {
print(someProperty) // declaring self is not required
}
}
}
The purpose of including self when using properties inside an escaping closure (whether optional closure or one explicitly marked as #escaping) with reference types is to make the capture semantics explicit. As the compiler warns us if we remove self reference:
Reference to property 'someProperty' in closure requires explicit use of 'self' to make capture semantics explicit.
But there are no ambiguous capture semantics with structs. You are always dealing with a copy inside the escaping closure. It is only ambiguous with reference types, where you need self to make clear where the strong reference cycle might be introduced, which instance you are referencing, etc.
By the way, with class types, referencing self in conjunction with the property is not the only way to make the capture semantics explicit. For example, you can make your intent explicit with a “capture list”, either:
Capture the property only:
class SomeClass {
var someProperty = 1
func someMethod(completion: #escaping () -> Void) { ... }
func anotherMethod() {
someMethod { [someProperty] in // this captures the property, but not `self`
print(someProperty)
}
}
}
Or capture self:
class SomeClass {
var someProperty = 1
func someMethod(completion: #escaping () -> Void) { ... }
func anotherMethod() {
someMethod { [self] in // this explicitly captures `self`
print(someProperty)
}
}
}
Both of these approaches also make it explicit what you are capturing.
For classes, closures provide a mechanism to increment a reference count, thus "keeping the object alive".
Maybe you're okay with just capturing someProperty. Maybe not! The compiler doesn't know if you're using a closure in order to increment the reference, so it makes you be explicit about your intentions.
Not only is that a non-issue with structs, but so is the possibility of mutation, which is strictly disallowed.
Let's say you wanted anotherMethod to allow mutation of any kind, in a struct. You could start by marking it as mutating…
struct SomeStruct {
func someMethod(completion: (() -> Void)?) {}
mutating func anotherMethod() {
someMethod {
self
}
}
}
…but no, that's an error:
Escaping closure captures mutating 'self' parameter
Capture self, though…
mutating func anotherMethod() {
someMethod { [self] in
self
}
}
…and that's fine.
And it's also the only option Swift allows. When you use an escaping closure from within a struct, you can only use an immutable capture of an instance. i.e. [self] in is implicit, for nonmutating methods.
This can yield unexpected results. Be careful.
struct SomeStruct {
var someProperty = 1
func anotherMethod() {
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
print(someProperty)
}
}
}
var s = SomeStruct()
s.anotherMethod() // 1, even though it's printed after the following reassignment
s.someProperty = 2
s.anotherMethod() // 2
I think it helps to think about what method syntax is shorthand for.
s.anotherMethod()
is really
SomeStruct.anotherMethod(s)()
You can visualize the immutability there, because there's no &.

Swift optional escaping closure

Compiler error Closure use of non-escaping parameter 'completion' may allow it to escape, Which make sense because it will be called after the function return.
func sync(completion:(()->())) {
self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
completion()
}
}
But if I make closure optional then no compiler error, Why is that? closure can still be called after the function returns.
func sync(completion:(()->())?) {
self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
completion?()
}
}
Wrapping a closure in an Optional automatically marks it escaping. It's technically already "escaped" by being embedded into an enum (the Optional).
Clarification:
For understanding the case, implementing the following code would be useful:
typealias completion = () -> ()
enum CompletionHandler {
case success
case failure
static var handler: completion {
get { return { } }
set { }
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler.handler = handlerParameter
}
At the first look, this code seems to be legal, but it's not! you would get compile-time error complaining:
error: assigning non-escaping
parameter 'handlerParameter' to an #escaping closure
let chObject = CompletionHandler.handler = handlerParameter
with a note that:
note: parameter 'handlerParameter' is implicitly non-escaping func
doSomething(handlerParameter: completion) {
Why is that? the assumption is that the code snippet has nothing to do with the #escaping...
Actually, since Swift 3 has been released, the closure will be "escaped" if it's declared in enum, struct or class by default.
As a reference, there are bugs reported related to this issue:
Optional closure type is always considered #escaping.
#escaping failing on optional blocks.
Although they might not 100% related to this case, the assignee comments are clearly describe the case:
First comment:
The actual issue here is that optional closures are implicitly
#escaping right now.
Second comment:
That is unfortunately the case for Swift 3. Here are the semantics for
escaping in Swift 3:
1) Closures in function parameter position are
non-escaping by default
2) All other closures are escaping
Thus, all generic type argument closures, such as Array and Optional, are escaping.
Obviously, Optional is enum.
Also -as mentioned above-, the same behavior would be applicable for the classes and structs:
Class Case:
typealias completion = () -> ()
class CompletionHandler {
var handler: () -> ()
init(handler: () -> ()) {
self.handler = handler
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
Struct Case:
typealias completion = () -> ()
struct CompletionHandler {
var handler: completion
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
The two above code snippets would leads to the same output (compile-time error).
For fixing the case, you would need to let the function signature to be:
func doSomething( handlerParameter: #escaping completion)
Back to the Main Question:
Since you are expecting that you have to let the completion:(()->())? to be escaped, that would automatically done -as described above-.

Complex Swift closure with generic argument

I have a scenario where I need to call a method with an optional closure argument where the closure receives a generic argument. Here's my simplified code:
class FooModel
{
}
class FooSubClass1 : FooModel
{
}
class FooSubClass2 : FooModel
{
}
class Client
{
func httpGet<T:FooModel>(closure:((T) -> Void)? = nil)
{
// Doing some network request stuff here and call onHTTPRequestComplete() when done!
onHTTPRequestComplete(data: result, closure: closure)
}
func onHTTPRequestComplete<T:FooModel>(data:[String:Any], closure:((T) -> Void)? = nil)
{
if let c = closure
{
switch(T)
{
case is FooSubClass1:
var foo = FooSubClass1()
// Process data into new FooSubClass1 object here!
c(foo)
case is FooSubClass2:
var foo = FooSubClass2()
// Process data into new FooSubClass2 object here!
c(foo)
}
}
}
}
class App
{
func someFunc()
{
client.httpGet()
{
response in
print("\(response)")
}
}
}
What I'm trying to do here:
I have a data model with a super class and several subclasses. In Client I do http requests to retrieve data and want to populate model objects with the data retrieved. The calling method in App should be able to provide a closure that is called after the asynchronous network request is done and in which I get back the correct data model object.
There are several issues with my code:
switch(T): Error: expected member name or constructor call after type name
c(foo): Error: '(FooSubClass1) -> Void' is not convertible to '(T) -> Void'
Not sure my closure definition makes sense for what I'm trying to do.
Updated code:
protocol FooModel
{
init()
}
class FooModelBase : FooModel
{
}
class FooSubClass1 : FooModelBase
{
}
class FooSubClass2 : FooModelBase
{
}
class Client
{
func httpGet<T:FooModel>(closure:((T) -> Void)? = nil)
{
// Doing some network request stuff here and call onHTTPRequestComplete() when done!
onHTTPRequestComplete(data: result, closure: closure)
}
func onHTTPRequestComplete<T:FooModel>(data:[String:Any], closure:((T) -> Void)? = nil)
{
if let c = closure
{
switch T.self
{
case is FooSubClass1.Type:
var foo = FooSubClass1()
// Assign retrieved values to model!
closure(foo)
case is FooSubClass2.Type:
var foo = FooSubClass2()
// Assign retrieved values to model!
closure(foo)
default:
break
}
}
}
}
class App
{
func someFunc()
{
client.httpGet()
{
response in
print("\(response)") // Should output FooSubClass1 instance with assigned values!
}
}
}
Almost works but I get the following compile error:
'closure(foo): Error: '(#lvalue FooSubClass1) -> Void' is not convertible to '(T) -> Void'
for the switch(T) error of course you get this error. Because you're trying to switch a type but you should be switching a value. For your second error it makes perfect sense because then what would closure be expecting then because T is generic.
For more info on generics in closures have a look at this stackoverflow thread
generics as parameters to a closure in swift
All in all what you're trying to do there just isn't possible and at first glance I believe this isn't the correct direction to go in (Although I could be wrong without seeing the whole context). One thing you can do instead maybe is have your closure be ((Any) -> Void)? but then unfortunately the type would be of Any and you would have to do a switch inside of the closure.
The value of T in the closure will be passed to the closure itself. You can't switch on it. But what I think you want is to switch on the type. You could do something like this:
let type = String(reflecting: T.self)
switch (type) {
case "Module.FooSubClass1":
var foo = FooSubClass1()
}
Or you could say:
if FooSubClass1.self == T.self {
var foo = FooSubClass1();
} else if FooSubClass2.self == T.self {
var foo = FooSubClass2();
}
However, this code smells. You seem to want to use generics but then have a hardcoded set of classes inside your generic method, which half-defeats the entire purpose of generics. Why not just define FooModel as
protocol FooModel {
init()
}
Then instead of your switch statement, just create one and pass it to your closure.
func onHTTPRequestComplete<T: FooModel>(data: [String: Any], closure: ((T) -> Void)? = nil) {
guard let closure = closure else { return }
closure(T())
}
Or why not create T outside of onHTTPRequestComplete and pass it?
onHTTPRequestComplete(data: data: model: FooSubClass1()) { model in
// Do something awesome with `model` right here.
}
However, what I'd probably do is this:
func httpGet(callback: (([String: Any]) -> Void)? = nil) {
// Do some network stuff and get the data
callback?(data)
}
Then inside of callback, just create whatever type you want:
httpGet { data in
let foo = FooSubClass1(data: data)
// foo on you
}

"Closure cannot implicitly capture a mutating self parameter" - after updating to Swift 3 [duplicate]

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.