So I'm trying to use the CoreAudio method AUGraphAddRenderNotify(...) but I need a reference to the class that created this notification within the notification block. Because this is a C function, I can't simply add a [weak self] in closure capture. Looking at the Documentation, the last parameter of this method is allowed to be an UnsafeMutableRawPointer that will be passed in during the execution of the block as the first parameter. Following this suggestion, here is the code that I have:
let selfPointer = Unmanaged.passUnretained(self).toOpaque()
AUGraphAddRenderNotify(graph, { (audioPlayerPointer, _, _, _, _, _) -> OSStatus in
let audioPlayer = Unmanaged<AudioPlayer>.fromOpaque(audioPlayerPointer).takeUnretainedValue()
...
return noErr
}, selfPointer)
Here is my question:
I need to figure out how I can safely get the value behind this pointer (accounting for nil). More specifically, I want to safely access the audioPlayer and make sure that it hasn't been deallocated by the time I use it. Currently, everything works just fine until the audioPlayer gets deallocated and then my app crashes. I know that I can use AUGraphRemoveRenderNotify(...) to stop the notification before the object gets deallocated but unfortunately this method is not what I'm looking for. How can I check if the object that the pointer is pointing to has already been deallocated?
Thanks in advance!
Weak references don't really work like that
Interestingly, weak references don't actually point to the target object that they model. They point to side tables, whose lifetime is different from the target object.
A side-table entry is allocated when the first weak reference to an object is made.
The creation of every weak reference increments the ref count of the side-table entry, and every destruction of a weak reference decrements it.
Once the target object is deallocated, the side-table entry remains in place. That way, all the weak references don't become dangling pointers.
After eventual deallocation of the target object, all attempts to access a weak ref to the (now-dead) cause the weak-ref to be nil-ed out (which is what you observe as a user), but also deincrements the side-table entry
Thus, every weak reference either needs to be destroyed (e.g. goes out of scope) or attempted to be accessed before the side table entry expires.
Since these side table entries aren't exposed to "user land" Swift code, you can't make a raw pointer to them, and so you can't really deal with weak references in this way.
Alternate ideas
I have a few ideas of what you can do instead, though I haven't tried them.
You can exploit UnsafeMutableRawPointer pointer to pass in a Weak<T> wrapper, like:
struct Weak<T: AnyObject> {
wear var object: T?
}
Though I think it'll have to be a class, in this case.
or for some other mechanism, such as passing in a closure (which weakly captures the object)
Related
I have a strongly referenced model in my view controller that has a function listenToQueue which "listens" to my Firebase database for real time updates. Whenever an update occurs, it passes back an object to my view controller, which then calls a function. Here is my code:
eventModel.listenToQueue { [weak self] queuer in
self?.queuerDidChange(queuer: queuer)
}
This works. However, originally my code looked like this:
eventModel.listenToQueue(updateHandler: queuerDidChange)
This caused a retain cycle between the model and the view controller. However, that code looks cleaner, so I'm wondering if there's a way to pass the queuerDidChange function via a weak reference to self? I tried this already, but the retain cycle is still there:
weak var weakSelf = self
eventModel.listenToQueue(updateHandler: weakSelf?.queuerDidChange)
Is it possible to do what I want, or shall I just stick to the code I've got?
weak var weakSelf = self
eventModel.listenToQueue(updateHandler: weakSelf?.queuerDidChange)
Above code is the same code as:
eventModel.listenToQueue(updateHandler: queuerDidChange)
Because you declare weakSelf and use it immediately. weakSelf?.queuerDidChange has no relation to weakSelf, instead it already contains reference to self itself. I assume queuerDidChange member function. So the only way to avoid retain cycle is what you call the dirty way.
eventModel.listenToQueue { [weak self] queuer in
self?.queuerDidChange(queuer: queuer)
}
I noticed this in one of my apps. I like the look of passing in the method itself, but I also had to use the weak reference technique you mentioned.
This makes sense, I think, because method implementations are held on the class itself, and self is bound to that implementation when classes are instantiated. Therefore a method will always have a strong reference to self.
And in Swift, function parameters are strongly referenced. I don’t think there’s a way to pass any parameter using a weak reference.
I'm aware of the fact that closure can create retain cycles if it is assigned to a property of a class and instance properties of the class are used inside of the closure. But
1) what about the closure is not assigned to the class property but passed as parameter to a singleton's class method ?
2) How the memory is managed in this case ?
In a method of my controller (UIViewController) I have something like:
MySingleton.classMethod(parameters ..., completion: { () -> Void in
/**
doing stuff here
*/
})
If You are not assigning the closure to a property, but just passing it to a function You need to consider if the closure will be escaping or noescape. In Swift 3 by default all closures passed to functions are non-escaping.
Here is a little bit more info on the matter:
"noescape" - the passed closure is invoked before the return of the function
"escaping" - If a closure is passed as an argument to a function and it is invoked after the function returns, the closure is escaping.
Simple explanation : We need to mark closure as escaping when we pass it to a function and the closure will be called after this function returns.
General rule is when the closure is escaping You need to use capture list to prevent retain cycles.
Example
let closure = { [weak someVariable] (name: Type) -> Void in
....
// code
}
Additional info:
One weird thing is that optional closures are treated as escaping. And when we explicitly add escaping keyword, there is a compile error -escaping attribute only applies to function types.
See the below links for more info.
https://bugs.swift.org/browse/SR-2053
https://stackoverflow.com/a/39619298/5388473
https://stackoverflow.com/a/39846519/5388473
Update
The idea of using weak or unowned in the capture lists of escaping closures is that essentially We don't know what will happen with the passed escaping closure, it may be called sometime later from another function or it may be stored in some object, which may lead to a strong retain cycle.
weak vs unowned vs strong capture
For more detailed information check Apple ARC docs.
From Apple docs:
Swift provides two ways to resolve strong reference cycles when you
work with properties of class type: weak references and unowned
references.
Weak and unowned references enable one instance in a reference cycle
to refer to the other instance without keeping a strong hold on it.
The instances can then refer to each other without creating a strong
reference cycle.
Use a weak reference when the other instance has a shorter
lifetime—that is, when the other instance can be deallocated first.
Use an unowned reference when the other instance has the same lifetime
or a longer lifetime.
Keep in mind that the weak approach will add a boiler plate to the code and will be a little bit more slow, because ARC will add code for setting the weak variables to nil on their deallocation. It is a good practice to follow the rules stated above, when choosing weak or unowned.
I just followed a tutorial on ARC and was provided with this code.
The following ViewController class and below it a Vehicle class.
What i got from it was that ARC essentially tracks down an instantiated class and allocates a piece of memory for it. As "strong" references for the instance are created, arc increases the increment for how many references there are to the instance. Once all of them are set to nil, ARC deallocates the instance from memory. The instructor also said something along the lines of, once all references are not being used, it deallocates from memory. I did not quite understand the part where they're not being "used", so I decided to add a button which presents another View Controller thats blank with no code. I figured that if I navigate to the next view controller, deinit will get called as the references in view controller 1, are now not being used and thus deallocated from memory. This was not the case, and the deinit did not get called. Therefore, I'm wondering, do references stay in memory unless you set them to nil, always?
Part 2 of question : Also, while you're answering that question, I also have another, I was also wondering if ARC only applied to class instances and references to it since every piece of documentation or tutorial that I have looked up seems to only mention class instances. For example, if I set var number = 2
var othernumber = number , is "number" also stored in memory, and only deallocated until all references to it are nil. If this is also the case, then the same question applies, is setting all references equal to nil the only way of deallocating from memory? Sorry for the lengthy question, but im quite new to the memory concept.
import UIKit
class ViewController: UIViewController {
var ref1: Vehicle?
var reference2: Vehicle?
var ref3: Vehicle?
var timer: NSTimer!
var count = 0
override func viewDidLoad() {
super.viewDidLoad()
ref1 = Vehicle(kind: "Car")
reference2 = ref1
ref3 = ref1
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(tick), userInfo: nil, repeats: true)
}
func tick() {
count++
if count >= 3 {
ref3 = nil
reference2 = nil
}
if count == 5 {
ref1 = nil
}
}
}
class Vehicle {
let type: String
init(kind: String){
self.type = kind
print("\(type) is being initialized")
//when the class is instantiated, we get an initialization message. When class is deallocated, we get a deinit message. As in, all strong references are gone, we can deinitialize.
}
deinit {
//class vehicle not in memory anymore as all strong references to it have been destroyed. This will be tested with segue as well.
print("\(type) is being deinitialized")
}}
The "used" terminology is confusing/misleading (or, at best, imprecise). With ARC, the object will not be released until there are no remaining strong references, plain and simple. If you nil all of those strong references, or those strong references fall out of scope, that's when the object is deallocated.
By the way, be aware that scheduledTimerWithTimeInterval establishes its own strong reference to its target. You have to invalidate the timer to resolve that strong reference.
ARC only applies to reference types (i.e. class instances). It simply does not apply to value types (such as numeric types or struct types).
Thus, consider
var number = 2
var othernumber = number
The othernumber does not reference the number. It makes a copy. It is a new object whose value happens to be the same value as number. For a discussion differentiating Swift value types from reference types, see WWDC 2015 Building Better Apps with Value Types. (By the way, the behind the scenes memory management of complex value types is actually more complicated than it is for simple value types, but it's not really relevant in this conversation. But it is discussed in some detail in the video if you're interested.)
This is a big question.
In order to understand ARC you really need to understand manual reference counting.
Reference counting is a way of keeping track of which objects are still in use, and which can be deallocated.
In manual reference counting, objects have a retain count.
You send a retain message to an object to increase it's retain count, and release to decrease it's retain count. If sending a release message to an object causes it's retain count to drop to 0, the object is deallocated/freed.
There is also an autorelease message which adds the object to an "autorelease pool". Each time your code returns and the event loop is visited, all the objects in the autorelease pool get sent a release message for each time they are in the autorelease pool. (You can send more than one autorelease message to an object, but ignore that.) Autorelease is useful for returning temporary objects that go away if you don't do anything special with them. An autoreleased object sticks around during the current call chain, but get freed when your code returns if nobody has retained it.
Objects are created and returned to the owner with a reference count of 1, and the owner is responsible for sending a release message to the object when it is done with it.
In manual reference counting you have to put retain, release, and autorelease calls in your code at the correct places in order to express your memory management intentions. Getting it wrong causes either memory leaks or crashes.
ARC uses all of the above mechanisms, but the compiler analyzes your code and inserts retain, release, and autorelease calls for you. It also strips out excess retain/release calls to the bare minimum required.
In ARC, you just need to declare your variables as strong or weak and the compiler does the rest. There are still a few gotchas, but for the most part you don't have to worry about memory management.
Storing an object in a strong variable causes the compiler to generate a retain call. Zeroing out the strong variable causes the compiler to send the object a release message.
Unlike garbage collection, the system doesn't have to stop and do time-consuming cleanup passes on memory. Objects get freed as soon as there are no longer any strong references to them.
I just read the ARC section in the Swift book and a few other related posts concerning weak and unowned references.
After my readings, I do have a clear understanding on what they are and in what situations each of them are to be used (see also this SO post which gives a great explanation of this).
However, I fail to understand why Apple even came up with these two solutions? Essentially, from a MM perspective, both come down to not creating a strong reference to the referred object (i.e. not increasing its retainCount). So, why even bother and provide two MM primitives here?
Now, developers need to understand when to use which of the two, and Apple did a great job in explaining the different scenarios, but they didn't say why. Wouldn't it have been simpler to e.g. only provide weak so that developers don't need to dig into the docs and understand the different use cases?
I guess, another way to phrase the question is, why at all should we use unowned, except for Apple telling us so? At least from a MM standpoint, this wouldn't make a difference and using weak where according to the docs we should use unowned wouldn't create a memory leak?!
The difference is in the optionality of variables. Like Apple says in the Unowned References section of the link you provided:
Unlike a weak reference, however, an unowned reference is assumed to
always have a value. Because of this, an unowned reference is always
defined as a nonoptional type.
The usage of this is more visible in a closure block. Here you do not have to use ? operator or get a reference on the object if you use it inside the closure.
Instead of writing this:
UIView.animateWithDuration(0.2) {
[weak self]
() -> Void in
self?.view.layoutIfNeeded()
}
However, if you can be sure that the reference to self will not be released before the animation and you can simply write unowned and do not have to use the ? operator or unwrap it with an if let statement:
UIView.animateWithDuration(0.2) {
[unowned self]
() -> Void in
self.view.layoutIfNeeded()
}
#Kádi's answer about weak variables being optional is correct, but incomplete.
Weak and unowned have a difference in meaning outside of Swift's Optional semantics. A weak reference is more accurately named an auto-zeroing weak reference. The system knows about an object stored in a weak variable, and when the object is deallocated, goes to the extra work to zero out the value. As a consequence of that, weak variables are optionals in Swift.
Unowned pointers are not memory managed at all. They are a raw memory pointer that can take any value. (They can still be typed to point to a particular type of structure, so they aren't always "raw" in the way a C void pointer is raw.) Unowned pointers are useful for pointing to malloc'ed memory, pointer arithmetic, and the like. Declaring a pointer type as unowned basically tells the compiler "Don't worry about it. I know what I'm doing." The burden is then on you to make sure the pointer is always valid, before you try to dereference it, and also manage the memory behind the pointer yourself.
I have a collection which maintains weak references to its objects. I'd like it to conform to NSFastEnumeration, but the buffer provided by countByEnumeratingWithState:objects:count: uses unsafe_unretained references. That creates a gap during which a returned reference could become invalid but not zeroed.
That's fine in the general case -- if the collection stuffs its (currently valid but weakly-referenced) object into the buffer and returns it, then the caller will presumably create its own strong reference if needed. But that leaves two problems:
(1) I don't see any guarantee that the for(){} iteration construct itself creates a temporary strong reference to the object, so if the contents of the {x} block changes something outside the collection in a way that causes the object to be released, then it'll have a dangling reference.
(2) There's still a small gap while returning from countByEnumeratingWithState: during which activity on another thread could invalidate the reference. My collection isn't meant to be thread-safe, but it would be nice if it could at least safely store references to objects which could be referenced on another thread, as there's really no way to prevent that in any multi-threaded application.
You can't return a strong reference directly to the caller. The caller won't release it, and the fast enumeration protocol does not guarantee that you will get a chance to release it yourself when the caller is done.
Instead you can retain+autorelease the objects before you store them into the buffer. That would guarantee the objects stay alive while the caller uses them. It may hurt the "fast" part of fast enumeration, but you would still get the "convenient syntax" part. If you add a nil check after you read the weak variable then you can avoid storing nil pointers into the buffer.