In Swift 4, how do I remove a block-based KVO observer? - swift

If I store an observer like this:
let observer: NSKeyValueObservation = foo.observe(\.value, options: [.new]) { (foo, change) in
print(change.newValue)
}
How do I remove/disable/cleanup observer once I no longer need it?
My foo instance does not have any remove-like method that receives an NSKeyValueObservation instance, the observer itself doesn't have any remove-like either.

In iOS 11, you don't have to. Just let the observer go out of scope. There is no penalty any longer for letting an observer die before the observed or for letting the observed die before the observer, so you have no actual work to do.
On the other hand, if you really want to unregister the observer, remove it from whatever is retaining it, or tell it to invalidate. (Something must be retaining it, because if you don't persist the observer, it will die and your observer function will never be called.)
(You say "if I store an observer like this", but the way you are storing it, with let, is a somewhat silly way to store the observer. It would be better to put it in a Set from which you can remove it later, or at least store it in a Optional var that you can later set to nil.)

With Swift 5, I began using .observe(\.propertyName, ...) on core data objects as the tokens automatically unregister at deinit or an invalidate() call on the token.
This works remarkably well until I recently noticed that I was leaking objects. I was seeing leaked NSKeyValueObservance, NSKeyValueObservationInfo, and NSArray objects. After verifying that I was managing the tokens properly, I finally tracked down the problem.
If you perform an .observe() on a Core Data object, you must keep the object as well as the token. If the object turns into a fault before you invalidate/release the token, you will leak memory. You do not crash but once it turns into a fault you will leak memory even if you free the token.

Related

How do I manually retain in Swift with ARC?

I'm using Swift 3 with ARC in an iOS app, and I want to manually retain an object.
I tried object.retain() but Xcode says that it's unavailable in ARC mode. Is there an alternative way to do this, to tell Xcode I know what I'm doing?
Long Version:
I have a LocationTracker class that registers itself as the delegate of a CLLocationManager. When the user's location changes, it updates a static variable named location. Other parts of my code that need the location access this static variable, without having or needing a reference to the LocationTracker instance.
The problem with this design is that delegates aren't retained, so the LocationTracker is deallocated by the time the CLLocationManager sends a message to it, causing a crash.
I would like to manually increment the refcount of the LocationTracker before setting it as a delegate. The object will never be deallocated anyway, since the location should be monitored as long as the app is running.
I found a workaround, which is to have a static variable 'instance' that keeps a reference to the LocationTracker. I consider this design inelegant, since I'm never going to use the 'instance' variable. Can I get rid of it and explicitly increment the refcount?
This question is not a duplicate, as was claimed, since the other question is about Objective-C, while this one is about Swift.
The solution turned out to be to re-enable retain() and release():
extension NSObjectProtocol {
/// Same as retain(), which the compiler no longer lets us call:
#discardableResult
func retainMe() -> Self {
_ = Unmanaged.passRetained(self)
return self
}
/// Same as autorelease(), which the compiler no longer lets us call.
///
/// This function does an autorelease() rather than release() to give you more flexibility.
#discardableResult
func releaseMe() -> Self {
_ = Unmanaged.passUnretained(self).autorelease()
return self
}
}
This is easily done with withExtendedLifetime(_:_:) function. From the documentation:
Evaluates a closure while ensuring that the given instance is not destroyed before the closure returns.
Cheers!

Using weak reference to check if object is deallocated, in Objective-C

I'm using ARC.
Sometimes I wrote the following code to assert a object should be deallocated:
__weak weakVariableOrProperty = someObject;
....
someObject = nil;
// or someObject = anotherObject;
....
if (weakVariableOrProperty) {
#throw [NSException exceptionWithName:NSInternalInconsistencyException reason:#"Object not deallocated" userInfo:nil];
}
For example, I use this code to check if a view controller is deallocated before creating a new view controller.
I believe that weak variable or weak property is set to nil immediately after last strong variable or property was set to nil or another object.
And this code is working as I expected until now.
Using weak variable or property to check if object is deallocated is a technique commonly used?
Is it possible that this code will cause problem in the future?
I believe that weak variable or weak property is set to nil immediately after last strong variable or property was set to nil or another object.
This is not exactly true, because an object could be autoreleased. In this case, the last strong reference may be gone, but the reference count of the instance would remain positive. In cases like that, the __weak reference would not be nil-ed out until the autorelease process takes place.
Is using weak variable or property to check if object is deallocated a technique commonly used?
I seriously doubt that this technique has gained much popularity, because ARC is a relatively new thing to Objective C. However, the technique appears valid.
Is it possible that this code will cause problem in the future?
This is very hard to guess, because the ARC Specification does not make any specific guarantees about the timing of nil-ing out the references, and because the spec allows compilers to optimize sequences of retain and release messages that they send to ARC objects.
Your explanation code will be prone to a race condition.
The object in weakVariableOrProperty could be released (since it's only referenced by a weak reference) after the if condition has been evaluated. To avoid this, introduce an ordinary variable, set it to weakVariableOrProperty and check it for nil instead.
That said, as #dasblinkenlight says, betting on exactly when an object will be gone is tough. In a reference-counted system you don't know what else is holding onto it. It may go away just after you've checked. You should be able to constrain your environment enough that you know the system's not squirreling things away, but both autorelease and weak references complicate things.
The best way to solve this is simply to have well-defined object lifetimes: view controllers that don't live forever, that you explicitly tell to go away and so on.
So I've tried using this technique to ensure that objects are always deallocated on a background thread. The [dealloc] for some of my classes was moderately heavy weight and could take a long time (10s of ms) which would freeze the main thread ever so slightly.
I decided to add all of these heavy objects to an array before they'd be released on the main thread, and then go through that array later on a backgroundd thread to remove them from the array. The thought was that the array would keep the retainCount alive until it could be removed from the array on the background thread, and then i could guarantee the cost of the [dealloc] wouldn't happen on the main thread.
To do this, i had the code below:
while([objectsToDealloc count] && /* other conditions to prevent infinite loop */){
__weak id ref = [objectsToDealloc lastObject];
[objectsToDealloc removeLastObject];
#synchronized(ref){
// synchronising on ref will retain it if possible.
// so if its still around,that means we didn't dealloc it
// like we were asked to.
// so insert it back into our array. once the object is deallocd
// it won't be able to be synchronized, because the weak ref will
// be nil
if(ref){
[objectsToDealloc insertObject:ref atIndex:0];
}
}
}
The idea was that if the array didn't contain the last reference (or if there were pending autoreleases on the object, etc), then the weak ref wouldn't nil out. I'd then #synchronize on the object - the synchronized block will retain + release whatever object is being synchronized - which would ensure the ref would stay alive during that block. if it was nil, then it'd been dealloced. if it wasn't nil, then i should add it back to the array and check back again later.
After testing with this code over the past few weeks, I cannot recommend this strategy to check for deallocated objects. I haven't tracked down exactly why yet, but very rarely the object will dealloc but the ref won't be nil yet, so i'll be adding an invalid object back into the array.
i've only caught this in the debugger one time, though i have crash logs of it happening a few times. You can see below that "nil" ends up in my array, even though the code above should protect against it.
Again, I suggest not using this technique for detecting when/if objects deallocate, and instead focus efforts on clarifying your object graph and relationships.

My way of creating events is creating a cycle reference where nothings gets released

I have a bunch of objects and I try and simulate events with them.
id completedSelectorTarget;
SEL nextTripSelector;
Then I call perform selector on the selector target.
Well I created a double reference where the listener of the event completedSelectorTarget retains my object and completedSelectorTarget is retained by the object as well.
How do I avoid this? Is there a better way to do events? I thought to remove the retain on completedSelectorTarget, but then what will happen when I call perform selector? The whole thing will crash wont it? Is there a way to check if completedSelectorTarget has been released before I call perform selector? Or perhaps I'm just doing this wrong?
Yes you are correct, you should avoid circular retains.
The way to do this is to decide on an ownership model for these objects. This means deciding which object should have the final say over the life and death of these objects, and a good way to choose this is to pick the object that creates these objects as the owner and main retainer of them. It's not the only way it can be done, but that should be a good start in the right direction. All other relationships should be weak and use assign for the property. In this way you can be sure that when the owner of the objects decides that they should go away, that they will. The owner could also cause these weak links to be cleaned perhaps by calling a method that separates the weak connection by setting the target properties to nil. This is done in case any other object is hanging onto either of the objects and causing the selectors to fire on the targets that have been deallocated.
So you can remove the retain from the completedSelectorTarget properties and make weak connections between the objects.
#property (assign) __weak id completedSelectorTarget;
Once that is done, decide which object is the owner of these objects and make it retain them, either directly using #propery (retain) ..., or perhaps by storing them in a container such as an array or dictionary. When this retain, or container, is released, your object(s) should deallocate or at the very least wind up on an autorelease pool. And you now have a single owner that you can go to to make sure your objects get deallocated.
For now I'm using NSNotification Center. I notice that it crashes as well if you don't remove the observer when it is released. Still it should save me time from writing my own code.

iPhone - Is there a way to know if a reference is (still) valid?

Let's say I assign an instance var with an object given in parameter. I don't know what this object is, so I don't want to retain it. But, that reference I have to that object can be invalid at some time, for example if the object is released, or is about to be released (autorelease pool). So, inside my class instance, can I know if the reference I have kept into an instance variable can be used without any risk of crash?
You should retain it and release it when you no longer need it. That is exactly what retain is for.
Kris Van Bael is right, no matter if you know what the object is, if you want to have ownership of it (if it's up to you to ensure that the object is alive), you must retain it. Release it when you don't need it, and set the reference to NIL (for security).
But their is an exception !
Sometimes you don't want to have ownership, the most common example is the delegate.
You don't want to retain your delegate, because it probably already retains you, and if both objects release each other in the dealloc method, your app will leak.
But in this case, you shouldn't care about the delegate being deallocated : the delegate should set your "delegate" property to nil in it's dealloc method.
So
if you have ownership on the object : retain, no choice !
if the object has ownership on you : assign, and don't worry !
This approach is really dangerous. If your app is not able to track object life cycle, then you must change the code in order to have control of this.
Anyway answering to your question: you can protect your instance variable by extra retaining it in your class and then releasing it when it is no more needed. So you don't need to do the check you are asking for.
You should set any released reference to NIL and check for NIL.

Core Data - How to check if a managed object's properties have been deallocated?

I've created a program that uses core data and it works beautifully.
I've since attempted to move all my core data methods calls and fetch routines into a class that is self contained. My main program then instantiates that class and makes some basic method calls into that class, and the class then does all the core data stuff behind the scenes. What I'm running into, is that sometimes I'll find that when I grab a managed object from the context, I'll have a valid object, but its properties have been deallocated, and I'll cause a crash. I've played with the zombies and looked for memory leaks, and what I have gathered is it seems that the run loop is probably responsible for deallocating the memory, but I'm not sure.
Is there a way to determine if that memory has been deallocated and force the core data to get it back if I need to access it? My managedObjectContext never gets deallocated, and the fetchedResultsController never does, either.
I thought maybe I needed to use the [managedObjectContext refreshObject:mergeData:] method, or the [managedObjectContext setRetainsRegisteredObjects:] method. Although, I'm under the impression that last one may not be the best bet since it will be more memory intensive (from what I understand).
These errors only popped up when I moved the core data calls into another class file, and they are random when they show up.
Any insight would be appreciated.
-Ryan
Sounds to me like you are not retaining objects you want to keep hanging around. If you are doing something like this:
NSArray *array = [moc executeFetchRequest:request error:&error];
you do not own the returned array and it will most likely disappear when the current autorelease pool is drained. This will occur when the run loop finishes processing the current event.
All this is speculation. If you want a proper answer, you need to post your code.
It's hard to know what the problem is based on your description, but you might want to look at the Core Data memory management guide. You shouldn't have to worry about memory management for managed objects and their entities (they're fetched and faulted automatically). When you talk about "properties," do you mean custom properties backed by ivars? If so, these should be released in didTurnIntoFault and allocd as needed (probably in the accessor).
I was struggling with a similar issue. I'm using a managed object class and want to set its properties dependent on user input. But the sometimes the properties and sometimes the whole managed object were deallocated.
After reading the Apple documentation http://developer.apple.com/library/IOs/#documentation/Cocoa/Conceptual/CoreData/Articles/cdMemory.html the chapter "The Role of the Managed Object Context" I learned that managed objects are released each run loop completes.
And there is the golden advice to set
[myMangedObjectContext setRetainsRegisteredObjects:YES];
(I had to set it in the init method (initWithNibName for me) of my view controller.)
You should also regard to retain only the objects you need to as explained in the documentation. But read it yourself.
If I'm not right please correct me.
I also made a class that handles all my CoreData fetching and stuff. I ran into a couple of gotcha's, so here are some tips. (If I am making any memory management errors in these examples, please let me know.)
Two things:
1) Made a "fetchFiredObject" method in the CoreData handler class. So when I want to get a managedObject that has all its variables and is a "fully feathered bird" so to speak, instead of doing:
aManagedObject *myManagedObject = [myCoreDataHandler.managedObjectStorageArray objectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
instead I do:
aManagedObject *myManagedObject = [myCoreDataHandler fetchFiredObjectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
And in myCoreDataHandler's fetchFiredObjectAtIndex:i method, we're going into the array, finding the object key at index i, then doing a fetchRequest for that object key, and returning the freshly-fetched managedObject so that it won't have been faulted or deallocated, etc. :D
2) When I create a new child viewController, I populate its "myCoreDataHandler" value from the parent upon creation. However, this happens on a subsequent line of code after the line of code that creates the new viewController. Therefore, any code in the child's viewDidLoad that tries to use myCoreDataHandler's methods will return empty objects because viewDidLoad completes before the parent's next line of code where it sets the values of globals in the child object. So make sure you are not accessing your "Core Data handling object" from within viewDidLoad or anything local methods called by viewDidLoad! Instead call them from the parent after creating the new viewController.