Two Weak Variables Referencing Each Other in Swift

Two weak variables referencing each other in Swift?

You can do that. The only side effect is that you need to ensure that something else is retaining the people and the apartments. In the original code you just need to retain the people and the apartments (associated with people) will be retained for you.

Strictly speaking the people aren't killed when the apartments are demolished and the apartments aren't demolished when the people die so weak references in this scenario make sense. It's generally better to consider the relationship and ownership model you want and then decide how to achieve that.

Swift: keeping a strong reference to a weak variable

While I wholeheartedly agree with Rob Napier’s analysis, for the sake of completeness, I should note that you can also make the lifetime of the object explicit:

let delegate = InterimDelegate()

withExtendedLifetime(delegate) {
let document = MyDocument()
document.delegate = delegate
document.save()
}

Weak reference in a closure

These should behave identically. Which you use would be a matter of style. I wouldn't consider either approach particularly better.

It's worth noting that this use of weak may be unnecessary in either case. If getProducts is correctly written, this code should only create a temporary retain loop rather than a permanent one. After the completion handler is called, it should release the closure, releasing self and breaking the loop. So the question is whether it is reasonable and desirable to have self be destroyed go away before this completes, and so whether you really want weak here at all. I often use a strong pointer for these cases. (This is also a matter of style and opinion. There are arguments for the habitual use of weak, I just find it an unnecessary hassle in many cases.)

If class A contains a strong reference to class B and class B has a weak reference to class A, why does A always get deinit before B?

Not sure I understood the question, but I see this as quite straight forward application of ARC rules. After the line

setup(&alpha, &bravo)

you have

  • 2 strong references to the object bravo (the bravo itself, and its reference alpha.b)
  • 1 strong (alpha itself), and 1 weak (bravo.a) reference to the object alpha

Now you set bravo = nil, removing 1 strong reference, but the other strong reference remains, so deinit is not called, based on rule:

ARC will not deallocate an instance as long as at least one active reference to that instance still exists.

Next you set alpha = nil. That's deleting its only strong reference, hence based on rule

A weak reference is a reference that doesn’t keep a strong hold on the instance it refers to, and so doesn’t stop ARC from disposing of the referenced instance.

A can be deallocated immediately. Also important to remember that

ARC automatically sets a weak reference to nil when the instance that it refers to is deallocated

In other words, the order of operations is:

  1. String reference is deleted with alpha = nil
  2. Since there are no other strong references, all weak references are set to nil
  3. deinit is called

So now, that alpha is deleted, no references of any kind are left for bravo, and hence its deinit can be called.

Disadvantages of using weak variables even when not needed?

Im afraid you just dont understand ARC. ARC does the counting of references for you, depending on whether something is defined as strong or weak (in effect, strong increases the reference count, while weak does not). If a reference count becomes 0, it is removed from memory. So if everything was weak, properties would be removed from memory immediately, and you could not use them. You need a strong somewhere, in effect.

As a simple way to plan how to structure your strong / weak definitions, think of one particular class as the owner of a property, and give that one the strong. This means the property will stick around for that owner to use it. If another class also has a reference to that property, but does not require that the property always sticks around for it - make that weak. As long as the main owner class, say the View Controller, still exists - then so will the property. If both were set weak, then even though the property still appears, it will be empty, because at runtime, it was decided that no-one really needed it, and it was removed.

ios confused about strong/weak references

You're understanding is backwards. Weak references are more often used for implementing child-to-parent relationships. They would seldom make sense for a parent-to-child relationship. Generally the parent owns the child; that means strong.

The vast majority of the time you want a strong reference. That's why it's the default. The most common reason not to have a strong reference is if it would cause a retain loop. For instance, if A has a strong reference to B, then if B had a strong reference to A you'd have a loop and neither object would ever be deallocated. So you pick one of the objects to be the owner, and it has the strong reference. The other object has a weak reference.

The most common case of this is delegation. A delegate almost always owns the thing it is delegate for. So the delegating object should have a weak reference to the delegate. As a convention in Objective-C, a property called delegate is expected to be weak. (If this feels backwards, think about how you use UITableView and UITableViewDelegate in practice, and which one you'd want to consider the "owner.")

Weak delegate pointers are not a hard-and-fast rule. There are exceptions such as NSURLConnection. If the delegating object has a shorter lifetime than the delegate, then it is ok (and generally preferable) for it to maintain a strong reference.

"Received Memory Warning" does not necessarily have anything to do with memory management. It just means you're using too much memory. If you have retain loops, then you may be leaking memory, and that would cause this warning. But it could also be because you're simply using too much memory. The "Allocations" tool in Instruments is the best way to investigate this.

While the implementation of "strong" and "weak" are very recent additions to Objective-C, they just formalize and provide better language support for what properly written code has been doing for many years with manual retains. The ownership patterns are identical today to what they were before ARC.

For what variables should you use weak var in Swift? How do I figure out the leaks?

The basic concept behind reference counting in Swift is one of ownership. Objects should hold strong references to any other objects that they "own", in the sense that they're responsible for the lifecycle of the other object, either alone or in conjunction with other objects.

A lot of object reference graphs in a typical application are hierarchical - one object owns a bunch of other objects, which each have their own children, etc. For example, a ViewController owns its window, the window owns its views, each view owns its subviews, and each subview owns the images, strings, or other content it displays. These are all strong references.

Weak references will typically be used for references that don't imply ownership. The delegate example is a good one - in most cases, a view does not own the delegate. The delegate object has a lifecycle independent of the view. In many cases, the delegate will be the same object that created/owns the view in the first place, for example a ViewController.

You do not want a strong reference that goes from a "child" to its "parent". That creates a circular reference, and both the child and the parent will hang around in memory until the application exits.

In addition to delegates and other "backwards-pointing" references, you will also see weak references used in caches, where you want to quickly return an object if it's requested a second time, but the cache shouldn't keep the object in memory if nobody's currently using it.

Do we need to explicitly use capture list for weak variables in swift closure?

Sort of, in this specific example, but you need to be very careful about how you think about what's happening.

First, yes, this is identical. We can tell that by generating the SIL (swiftc -emit-sil main.swift). Except for the difference in the name of self vs weakSelf, these generate exactly the same unoptimized SIL. In order to make it even clearer, I'll change the name of the variable in the capture list (this is just a renaming, it doesn't change the behavior):

weakSelf

    weak var weakSelf = self
callback = {
weakSelf?.perform()
}

weak_self

    callback = { [weak weakSelf = self] in
weakSelf?.perform()
}

Compare them

$ swiftc -emit-sil weakSelf.swift > weakSelf.sil
$ swiftc -emit-sil weak_self.swift > weak_self.sil
$ diff -c weakSelf.sil weak_self.sil

*** weakSelf.sil 2022-03-27 10:58:13.000000000 -0400
--- weak_self.sil 2022-03-27 11:01:22.000000000 -0400
***************
*** 102,108 ****

// Foo.init()
sil hidden @$s4main3FooCACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
! // %0 "self" // users: %15, %8, %7, %2, %22, %1
bb0(%0 : $Foo):
debug_value %0 : $Foo, let, name "self", argno 1, implicit // id: %1
%2 = ref_element_addr %0 : $Foo, #Foo.callback // user: %4
--- 102,108 ----

// Foo.init()
sil hidden @$s4main3FooCACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
! // %0 "self" // users: %8, %7, %15, %2, %22, %1
bb0(%0 : $Foo):
debug_value %0 : $Foo, let, name "self", argno 1, implicit // id: %1
%2 = ref_element_addr %0 : $Foo, #Foo.callback // user: %4

Except for the order of the users comment for self, they're identical.

But be very, very careful with what you do with this knowledge. This happens to be true because there exists a strong reference to self elsewhere. Going down this road too far can lead to confusion. For example, consider these two approaches:

// Version 1
weak var weakObject = Object()
let callback = {
weakObject?.run()
}
callback()

// Version 2
var weakObject = Object()
let callback = { [weak weakObject] in
weakObject?.run()
}
callback()

These do not behave the same at all. In the first version, weakObject is already released by the time callback is created, so callback() does nothing. The compiler will generate a warning about this, so in most cases this is an unlikely bug to create, but as a rule you should generally do weak captures in the capture list so that it occurs as close to the closure creation as possible, and won't accidentally be released unexpectedly.

Weak reference to closure in Swift

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.



Related Topics



Leave a reply



Submit