NSAsynchronousFetchRequest possible memory leak - swift

PROBLEM: Analyzing an iOS app with xcode instruments it appears to be a small but crucial (the snippet is indirectly executed all through the project) memory leak.
DESRCIPTION: We don't make any use of Entities references and follow the typical apple suggested core data object context stack
Here is a screenshot of instruments showing an apparent leak due to NSAsynchronousFetchRequest maintaining a mutual indirect reference to a NSFetchResult
Here is the code snippet triggering the leak (removeing all the non-neccessary code, even the [weak self] still doesn't change it) according to Instruments
let anEntityFetch = NSFetchRequest<NSFetchRequestResult>(entityName: AnEntity.entityName)
let asyncFetchRequest = NSAsynchronousFetchRequest(fetchRequest: rangeQuantityFetch) { (asynchronousFetchResult) -> Void in
//
}
do {
// commenting out the execute there is no leak anymore
_ = try managedObjectContext.execute(asyncFetchRequest)
} catch {
}
The same thing happens enabling compile optimization flags.
QUESTION: Is there a possibility that it is only an Instruments or xcode bug? Or that it is a known core data issue? Or any useful hint to address me to the problem source would be really appreciated.

It appears to be an issue with the core data object contexts stack. In the configuration we have the a main context having as parent a write context that has the actual persistence coordinator.
According to memory-leak-on-nspredicate-that-used-in-fetch-request-to-fetch-nsmanagedobject the problem is with the main context haveing a parent.
To solve this either
change the core data stack as pointed in the answer
or (seems to
work but is not a clean solution) extend the NSAsynchronousFetchRequest to set to nil the request property
after the completion block is called (this way the reference cycle is
broken and resources can be deallocated by ARC).

Related

Memory continuously increasing on swift application

I'm coding a generic Swift application (not for iOS, it will later run on raspbian) and i noticed a constant increase of memory. I checked for memory leaks also with the inspector, and there are none.
To dig deeper, I created a blank application for macOS, and I just wrote those lines of code, which are only for testing:
var array = [Decimal]()
while(true) {
array = [Decimal]()
for i in 0..<10000
{
array.append(Decimal(string: i.description)!)
}
sleep(1)
}
As I know, at beginning of every cycle of the while loop the entire array that was filled in the previous cycle should be deleted from memory. But seems that this is not happening, with those lines of code the process memory rises indefinitely.
I also tried the same code on an iOS project putting it on the application function (the one that is called at the beginning in the app delegate) and I noticed that in this case, the memory remains constant and do not rises up.
Am I missing something on the non iOS project?
The Decimal(string:) is creating autorelease objects. Use an autoreleasepool to drain the pool periodically:
var array = [Decimal]()
while true {
autoreleasepool {
for i in 0..<10_000 {
array.append(Decimal(string: i.description)!)
}
sleep(1)
array = []
}
}
Normally the autorelease pool is drained when you yield back to the runloop. But in this case, this while loop never yields back to the OS, and therefore the pool is not getting drained. The use of your own autoreleasepool, like above, solves that problem.
FWIW, Apple has been slowly excising the use of autorelease objects in the Foundation/Cocoa classes. (We used to experience this problem with far more Foundation objects/APIs than we do now.) Clearly Decimal(string:) still is creating autorelease objects behind the scenes. In most practical cases, this isn't a problem, but in your example, you will need to introduce your own autoreleasepool to mitigate this behavior in this while loop.

how to fix memory leaks with xcode (Swift 3)

i've made a game in Swift and it has a single and a multiplayer modes, and it seems that i have a problem with the memory management, because the app occupies 150 MB and i have no idea why.
the memory debugger of xcode shows that there are 15 issues when i choose a multiplayer game, but in the single player mode it semmes that there are no leaks and still it got 150 MB usage.
here are a screenshot of the debugger in action and i'll appreciate any help with all these triangles, circles and rombs.
thanks in advance!
This looks like a strong reference cycle.
Usually this happens when you don't declare objects that you use in closures as weak. In order to understand what a strong reference cycle is, check the following resources out:
Blog post about strong reference cycles
WWDC videos available (e.g. here and here)
Although the WWDC videos are a little bit older, the main idea is still the same. At least two objects are (transitively) holding a strong reference to each other. When both get released (e.g. when a GameScene is deallocated) they still point to one another, so the system is unable to deallocate them.
Usually, you get a strong reference cycles in the context of closures:
myMethod(...) { (param1, param2) in
self.myVariable = ...
}
If you have a structure like this in your code, try to make self weak. i.e.
myMethod(...) { [unowned self] (param1, param2) in
self.myVariable = ...
}
Since I don't see the code, I can't exactly see where the problem is but it seems that you have a strong reference cycle in your dictionaries. Then it might not be a closure problem.

EXC_BAD_ACCESS when calling new entity() method in iOS 10 / macOS Sierra Core Data

The new entity() method helps us avoid magic strings. Rather than saying something like managedObjectModel.entitiesByName["foo"], we can say Foo.entity().
The problem is that in my testing it always throws EXC_BAD_ACCESS. I've configured my NSPersistentStore and I've run a test query to make sure that everything is set up properly.
Any insight? What are the prerequisites to call this method?
Something is wrong with your setup.
To check, open Xcode, start a new project, choose "Master/Detail", check "Core Data". In the MasterViewController, insert this line anywhere:
print("The entity is ", Event.entity(), ".")
You will see that it works out of the box. Notice that in the model editor, when inspecting the Event entity, the option "Codegen" is set to "Class Definition".
The problem turned out to be that merely initializing NSPersistentStore and calling loadPersistentStores isn't enough. You have to explicitly or implicitly use its managedObjectModel property at least once, most likely due to lazy loading.
I tentatively regard this as a bug. The entity() method should probably do this itself under the hood, though there may be other considerations.

Restkit + Coredata - NSFetchedResultsControllerDelegate callbacks not triggered for UPDATE operations alone

I have a strange problem here. I am not getting the callbacks for "Update" operations on my NSManagedObject, but where as any objects inserted into or removed from the collection of that entity type would trigger the delegate callbacks.
Before I proceed with the question further, I would like to inform about my setup:
NSFetchedResultsController is properly configured. Made sure that
the property which is being modified externally is not any of the
sort keys for the fetchedResultsController as required by this Apple
documentation:
An update is reported when an object’s state changes, but the changed
attributes aren’t part of the sort keys.
There is only single managed object context in which these modifications are happening.
Since insert and delete operations are being reported to the
delegate, I presume there is something fishy about the Update
operations
I was drilling down the Restkit code with help of RKLogs to see where exactly the mapping happens and where the coredata object is being updated to find out the reason why am not getting the update delegate callbacks.
In the class RKManagedObjectMappingOperation -performMapping method, Mr. Blake Watters has documented the reason why MOC callbacks are not triggered upon updates:
- (BOOL)performMapping:(NSError **)error
{
BOOL success = [super performMapping:error];
if ([self.objectMapping isKindOfClass:[RKManagedObjectMapping class]]) {
/**
NOTE: Processing the pending changes here ensures that the managed object context generates observable
callbacks that are important for maintaining any sort of cache that is consistent within a single
object mapping operation. As the MOC is only saved when the aggregate operation is processed, we must
manually invoke processPendingChanges to prevent recreating objects with the same primary key.
See https://github.com/RestKit/RestKit/issues/661
*/
[self connectRelationships];
}
return success;
}
But I cannot for the life of myself figure out how to fix this? Coz it was done purposefully?
Has anyone faced same problem? How do I fix it?
Thanks,
Raj Pawan
There was 1 mistake from my part and 1 other thing (Ignorance) which I was not aware of and due to which I faced this problem:
Mistake:
Despite many discussion all over the forums, I was wrong to state my second listed item:
There is only single managed object context in which these
modifications are happening.
I had wrongly logged and found out that I was in the same context! So dumb of me!
Ignorance:
I did some digging through the RK code thinking something fishy is going on there, checked Blake Watters' comments and his commit 4b394f8c1e1f to see if the earlier code there (call to -processPendingChanges) which is now removed was causing any issue and not letting the delegate to be informed about updates.
Found out that this was indeed on a separate thread and yes it had its own MOC which I had missed out. Next thing to do was simple, I implemented the mechanism to merge changes of a MOC from different thread into main MOC. But this did not work either!
The reason turns out that I am in a very initial stages of the development of application. I am just mapping the json response with coredata objects using RestKit and I am nowhere utilising it! I was just logging the coredata objects in GDB and they remained in their fault state always! I was relying upon the -objectLoader callbacks and the NSNotification object to see that there was indeed an Update available. At some point while testing I happened to log a property of the managed object which is changed in the Notification callback before it was merged back to the main MOC. This faulted the managed object and loaded all properties of the managed object. Now when the secondary thread MOC changes were merged with the main thread MOC, my NSFetchedResultsControllerDelegate callbacks started triggering.

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.