Swift issue when storing Object inside a struct - swift

I am confused of how memory is managed here, lets say there is a scenario:
import Foundation
class SomeObject {
deinit {
print("deinitCalled")
}
}
struct SomeStruct {
let object = SomeObject()
var closure: (() -> Void)?
}
func someFunction() {
var someStruct = SomeStruct()
someStruct.closure = {
print(someStruct)
}
someStruct.closure?()
}
someFunction()
print("the end")
What I would expect here is:
Optional(test.SomeStruct(object: test.SomeObject, closure: Optional((Function))))
deinitCalled
the end
However what I get is this:
SomeStruct(object: test.SomeObject, closure: Optional((Function)))
the end
And if I look at memory map:
retain cycle
How do I manage memory in this case

First, you should be very, very careful about putting reference types inside of value types, and especially a mutable reference type that is visible to the outside world. Structs are always value types, but you also want them to have value semantics, and it's challenging to do that while containing reference types. (It's very possible, lots of stdlib types do it in order to implement copy-on-write; it's just challenging.)
So the short version is "you almost certainly don't want to do what you're doing here."
But if you have maintained value semantics in SomeStruct, then the answer is to just make a copy. It's always fine to make a copy of a value type.
someStruct.closure = { [someStruct] in
print(someStruct)
}
This gives the closure it's own immutable value that is a copy of someStruct. Future changes to someStruct won't impact this closure.
If you mean for future changes to someStruct to impact this closure, then you may be violating value semantics, and you should redesign (likely by making SomeStruct a class, if you mean it to have reference semantics).

Related

swift how to update viewModel parameter while init

I have encountered the problem "Cannot assign to property: 'self' is an immutable capture". How can i call API to check status and update "getUpdateSuccess" parameter
struct HomepageViewModel {
var getUpdateSuccess: Bool = false
init() {
getStatusUpdated.execute().done {
[self] isUpdated in
// Cannot assign to property: 'self' is an immutable capture
self.getUpdateSuccess = isUpdated
}
}
}
If you want to “reference” self later (e.g., update the same instance later), self should be a reference type, not a value type.
So you can solve this by making the view model a class (a reference type) rather than a struct (a value type).
“Model” objects are good candidates for value types, but “view models” are generally reference types. See Value and Reference Types for a discussion of when you might use a value type and when you might use a reference type. For a general discussion, see The Swift Programming Language: Structures and Classes.
By the way, the closure’s capture list syntax (the stuff in between the [ and the ]) has different practical implications if the captured variable is a reference type vs when it is a value type.
With a value type, the capture list makes sure you have a copy of the value:
struct Person {…}
var person = Person(…)
foo { [person] in
// this code will be dealing with a safe copy of the original `Person`
}
// maybe you’ll mutate the original `Person` instance here,
// but the above closure will have a copy of the original one
Contrast that with a reference type, where the capture list makes sure you have a strong reference to the reference type:
class ViewModel {
func bar() {
baz { [self] in
// this has a strong reference to this view model instance, not a copy of the instance
}
}
}
let viewModel = ViewModel(…)
viewModel.bar() // any updates that bar does asynchronously, will update this instance of the view model, not a copy of it
As an aside, with reference types, you will often see a capture list with the weak keyword, e.g., [weak self], if you want a “weak” reference to the class rather than a strong reference. This is common if you need to prevent a “strong reference cycle” (a topic beyond the scope of this conversation). This is discussed in The Swift Programming Language: Strong Reference Cycles for Closures.
But, whether a strong reference or weak reference, you are not dealing with a copy of the object, but rather a “reference” to the same original instance.

Is it safe to capture properties of `self` without capturing `self`?

You can copy this playground verbatim:
var closures=[() -> Void]()
class Thing {
let name: String
init(_ name: String) { self.name=name }
}
class RefThingWrapper {
let thing: Thing
init(_ t: Thing) {
self.thing=t
closures.append { [thing, weak self] in // Even though `thing` captured strongly, `self` could still get deallocated.
print((self == nil) ? "`self` deallocated" : "`self` not deallocated")
print(thing.name) // Decided to use `thing` within closure to eliminate any chance of optimizations affecting the test results — which I found when I captured `self` strongly without using it.
}
}
}
struct ValThingWrapper {
let thing: Thing
init(_ t: Thing) {
self.thing=t
closures.append { [weak thing] in
print((thing == nil) ? "`thing` deallocated" : "`thing` not deallocated")
}
}
}
var wrapper=Optional(RefThingWrapper(Thing("Thing 1"))) // Test with reference type.
//var wrapper=Optional(ValThingWrapper(Thing("Thing 1"))) // Test with value type.
closures[0]()
wrapper=nil
closures[0]()
It demonstrates how a property of self — whether self is a reference or value type — can be captured within a closure independently of self. Running the program as is demonstrates a captured property existing after self has been deallocated. Testing with the value type wrapper demonstrates that, if weakly captured, the instance will be deallocated once the referencing value instance is deallocated.
I wasn't sure this was possible because when creating the closure at first, I forgot to initialize the property I was capturing. So the compiler complained — in the capture list — 'self' used before all stored properties are initialized. So I figured self was being captured implicitly, and only after digging deeper discovered otherwise.
Is this documented somewhere? I found this post by Joe Groff where he proposes:
For 'let' properties of classes, it'd be reasonable to propose having
closures capture the property directly by default in this way
instead of capturing 'self' (and possibly allowing referencing them
without 'self.', since 'self' wouldn't be involved in any cycle formed
this way).
This was back in 2015, and I didn't find any implemented proposals that arose from the discussion. Is there any authoritative source that communicates this behavior?
If you’re just asking for documentation on capture lists and reference types, see The Swift Programming Language Resolving Strong Reference Cycles for Closures. Also see the Language Reference: Capture Lists
If your capture list includes value type, you’re getting copy of the value.
var foo = 1
let closure = { [foo] in
print(foo)
}
foo = 42
closure() // 1; capturing value of `foo` as it was when the closure was declared
If your capture list includes a reference type, you’re getting a copy of the reference to that current instance.
class Bar {
var value: Int
init(value: Int) { self.value = value }
}
var bar = Bar(value: 1)
let closure = { [bar] in
print(bar.value)
}
bar.value = 2
bar = Bar(value: 3)
closure() // 2; capturing reference to first instance that was subsequently updated
These captured references are strong by default, but can optionally be marked as weak or unowned, as needed, too.
That Capture Lists document outlines the way that you can capture a property without capturing self:
You can also bind an arbitrary expression to a named value in a capture list. The expression is evaluated when the closure is created, and the value is captured with the specified strength. For example:
// Weak capture of "self.parent" as "parent"
myFunction { [weak parent = self.parent] in print(parent!.title) }
I’m not crazy about their code sample, but it illustrates the capture of a property without capturing self, nonetheless.

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

Weak reference to closure in Swift

I have the following code to create an observable property for data binding. It's in the works so I'm not sure what the final implementation is going to be and I'm still pretty new to Swift.
class Observable<T> {
typealias Observer = T -> Void
var value: T {
didSet {
for observer in self.observers {
observer?(self.value)
}
}
}
var observers: [Observer?] = []
init(_ val: T) {
self.value = val
}
}
I would like to keep weak references to the Observer closures. I don't want to rely on the client to ensure that the closure is weak/unowned before passing it in, via the capture list. Especially because there can be many observable properties on a given class.
Is it possible to make the closure references weak in my Observable class?
UPDATE:
I found a couple of resources that I think will help me accomplish what I want:
Make self weak in methods in Swift
specifically,
func methodPointer<T: AnyObject>(obj: T, method: (T) -> () -> Void) -> (() -> Void) {
return { [unowned obj] in method(obj)() }
}
The following link refers to the above stackoverflow answer and goes into some more detail:
http://blog.xebia.com/2014/10/09/function-references-in-swift-and-retain-cycles/
and this is a two-way binding example:
http://five.agency/solving-the-binding-problem-with-swift/
specifically,
class BondBox<T> {
weak var bond: Bond<T>?
init(_ b: Bond<T>) { bond = b }
}
where the listener is wrapped in a class called Bond, which is weakly referenced in the BondBox.
Is it possible to make the closure references weak in my Observable class
No. Only class instances can be referred to via weak references in Swift, and a function is not a class instance. (And not only must they be class instances, they must be an Optional wrapping a class instance.)
There are some pretty obvious ways around this, or course - the simplest being a wrapper class. But I do not actually recommend that in this situation, because you have not convinced me that weak references to functions are needed here in the first place. Remember, a weak reference to an object to which there is no strong reference will instantly lose the reference and will be pointing at nil. I can't believe that is what you want. I think you're barking up a wrong tree here.
Weak/strong are for memory management of objects, so only apply for variables of reference types (i.e. types which point to objects). Function types in Swift are not reference types, and therefore it does not make sense to talk about weak/strong for their variables.
Plus, you do not actually have variables of function type in your code (except in the middle of the iteration). You simply have a variable of array type. Even in Objective-C, you can only mark variables as weak or strong, not values that are stored inside other things.
And if you were to write the thing you are writing in Objective-C, you would want the "Observable" to have strong references to the closures. Otherwise, who else would have a strong reference to the closure?

Can 'mutating' be inferred for functions inside structs?

Why should we be required to specify mutating for a function in a struct explicitly? Can't it be inferred automatically from the function body while compiling? If it can't, can you please give me an example where it can't...
There are some special examples when the compiler cannot infer mutability because it's the programmer decision to say whether the behavior should be considered as mutable.
For example, when the struct is backed up by a class:
struct MyArray<T : AnyObject> {
let buffer: NSMutableArray = NSMutableArray()
func append(item: T) {
buffer.addObject(item)
}
}
let myArray = MyArray<NSString>()
myArray.append("something")
Note that the append function is modifying the struct but it doesn't have the mutating attribute, so you can use it even on constant variables. If you want to prevent that, you need to add the mutating attribute.
I didn't choose the array example accidentally. The dictionaries and arrays in Swift are backed up by classes and they had to choose which methods would be mutating and which wouldn't.