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

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 &.

Related

Variable of type Self in static context

I have to modify an existing static method with return type Self.
I am using Self as it is required to work for subclasses of A as well. As the modification potentially needs a dispatch sync block to create the data for the returnee, I have to introduce a local variable of type Self.
Error:
'Self' is only available in a protocol or as the result of a method in a class;
class A {
//...
}
class B:A {
//...
}
extension A {
static private func foo() -> Self {
var myVar: Self? //Error: 'Self' is only available in a protocol or as the result of a method in a class;
// Get data for myVar, potentially in a dispatch sync block on another queue
guard let safeVar = myVar else {
return someGarbagr
}
return myVar
}
}
Intended usage:
func someFunctionSomewhere() {
let instanceOfB = B.foo()
// use instanceOfB
}
I have tried all I can think of already:
type(of:Self)
Self.Type
...
I would like to avoid modifying it to a generic method for several reasons. The main reason is that we would have to mention the type explicitly to make a generic version be able to refer the return type:
let instanceOfB: B = B.foo()

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-.

Closure cannot implicitly capture self parameter. 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.

"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.

Escaping closure captures mutating 'self' parameter

I'm trying to subscribe to an observable generated by a combineLatest, after flatMap. If I'm running this code in a struct I get this error:
Escaping closure captures mutating 'self' parameter
If I change to a class the error does not occurs. I understand that with struct I cannot asynchronously mutate the state of the struct, but, in this case I'm actually not mutating it, or am I?
There's another way to fix it without using a class?
public struct ViewModel {
let disposeBag = DisposeBag()
var relay1: PublishRelay<()>
var relay2: PublishRelay<()>
init() {
relay1 = PublishRelay<()>()
relay2 = PublishRelay<()>()
Observable.combineLatest(relay1, relay2)
.filter { tuple in 1 == 1 } // some boolean logic here
.flatMap { _ in return Observable<Void>.just(()) } // some map filter here
.subscribe(onNext: { _ in
self.doCoolStuff()
}).disposed(by: disposeBag)
}
func doCoolStuff() {
// Do cool Stuff here
}
}
All instances methods receive a reference to self as an implicit first parameter, which is why you have to capture self to call the instance method. Is you don't actually need any instance variables then make doCoolStuff() a static function and you will no longer need to call it with self. (you can use Self. as of Swift 5, or just the type name ViewModel.). You can similarly avoid this issue if doCoolStuff is a closure defined inside of init.