retain cycle with core-data - ios

I think I have a problem, maybe linked to a retain cycle in Core-Data.
The code is a follow, where self.image is also a NSManagedObject:
- (void)setImage:(UIImage*)image1 andThumbnail:(UIImage*)image2
{
self.image.data = UIImageJPEGRepresentation(image1, 0.85); // This is autoreleased
self.thumbnail = UIImageJPEGRepresentation(image2, 0.85); // This is autoreleased
}
Apparently, the "self.image.date =" has one retain that is never released (and I think that it is between self.image and self). Because of that the self object will never be released and hence the leak.
EDIT: so basically I have the same problem as here: https://devforums.apple.com/message/246219#246219
I use exactly the same structure where the self in the previous code corresponds to the Bar in the given link. I also have the same view controller structure. However, the refreshObject doesn't help.
I tried to use the NSManagedObjectContext refreshObject method to break the retain cycle (as suggested in Apple documentation). It has no influence on the retainCount. I'm probably not using it the right way but I can't find much information about it. If I use NSManagedObjectContext:reset: I get a crash in the root view controller when I come back to it.
Thanks!

You should not interfere with the managed object context's management of the managed objects memory.
If self.image above is a managed object and you have not written custom accessors then you have no memory management concerns from it. Any attempt to manage the context's memory manually will almost always cause more problems than it solves.
Retain counts tell you nothing except in the simplest and smallest of command line apps. Once you use frameworks like Core Data, the behind the scenes retention is so complex that the retain count often bears no relationship to what happens in your own code.
Apparently, the "self.image.date ="
has one retain that is never released
(and I think that it is between
self.image and self). Because of that
the self object will never be released
and hence the leak.
This will not happen. You do not have to kill all objects in an instance's retained attributes before killing the instance itself. If that was true, you couldn't kill an instance that shared an attribute object with a 3rd object. If they were non-managedObject instances, the self.image object can exist long after the self object dies. Only the enforcement of the entity graph by the context makes them behave different and that has nothing to do with memory management.
If you see a mysterious retain count of 1 on a managed object, that is the retain put on the object by the managed object context. As long as the context believes the managed object must exist in the entity graph, it will never release the object.
If the leak is in the Core Data stack at all, your problem is most likely in the entity graph between the self entity and the self.image entity. The entity graph is preventing one or the other from being deleted most likely by a deny or a required relationship.

Related

Why is there a Weak References Between Managed Objects and the Context?

When i was learning how to use child contexts :
let childContext =
NSManagedObjectContext(
concurrencyType: .mainQueueConcurrencyType)
childContext.parent = coreDataStack.mainContext
let childEntry =
childContext.object(with: surfJournalEntry.objectID)
as? JournalEntry
// 3
detailViewController.journalEntry = childEntry
detailViewController.context = childContext
detailViewController.delegate = self
Author made some remark about passing both managed object and the managed object context to the detailViewController:
Note: You might be wondering why you need to pass both the managed
object and the managed object context to the detailViewController,
since managed objects already have a context variable. This is because
managed objects only have a weak reference to the context. If you
don’t pass the context, ARC will remove the context from memory (since
nothing else is retaining it) and the app will not behave as you
expect.
Well, ok, so then a read some official doc:
This means that in general you cannot rely on a context to ensure the
longevity of a managed object instance, and you cannot rely on the
existence of a managed object to ensure the longevity of a context.
Put another way, just because you fetched an object doesn’t mean it
will stay around.
But yet, i don't get what is true intention of making weak references between managed objects and the context? What is the goal do they pursue?
Managed object contexts usually use weak references to fetched objects to avoid the potential for excessive memory use. If it used strong references, and you did one or more fetches that found a large number of results, all of them would remain in memory for as long as the context existed. In many apps that would mean they'd never go away, because the context exists until the app exits. That could cause the app to use a lot of memory for objects it wasn't using anymore. Weak references mean that the managed objects are deallocated as soon as the app stops using them.
But you might want strong references in some cases, so there's a boolean property called retainsRegisteredObjects that makes the context use strong references instead. Use it if you like, but be careful of memory use.
Managed objects don't keep strong references to their contexts to avoid reference cycles. If they were strong references and you set retainsRegisteredObjects to true, you'd get a reference cycle. Each object would hold a strong reference to the other, so neither could be released from memory unless you set one of the references to nil.
You can think of managedObject as small and stupid object. They have a pointer to their context and know their objectId. When they need to know something they query the context. This has a lot of really neat advantages. If an entity was already queried in the context, a second instance of it will hit the row cache in the context and not hit the store at all.
Generally there are two kinds of context (for most core data setups): long lived main queue context that are always in memory, and short lived background contexts. For the main queue context you generally don't need to worry about the contexts leaving memory. They stay in memory for the lifetime of the application. The short lived context have a problem of leaving memory and also have a problem that they are not thread-safe. So generally they should be created in a block that is on the correct thread - used and then discarded and not pass out of the block.
I hope that explains it.

Are objects immediately released when a property is allocated a second time?

I am working on an app where I am presenting 100 sentences using AVAudioplayer. Rather than have 100 AVAudioplayer objects I wanted to just have one property and change the object associated with it on the fly. My code boils down to the following (though the lines arent immediately following each other in the actual code):
self.thePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url1 error:&error];
self.thePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url2 error:&error];
Does the object initialized with url1 get released when thePlayer is allocated and initialized a second time with url2, or are both objects only released when the view is dismissed? As I am dealing with 100 sound files I don't want them all hanging around in memory. I'm using ARC
Thanks in advance
In your specific case, guessing at what your code likely includes, the objects will probably be deallocated when you want them to be. That's a lot of "guessing," "likely," and "probably." You really need to understand how the memory management works in order to reason about it.
If the AVAudioPlayer is strongly referenced by anything else, then it won't be released until those strong references are gone. In other words, setting thePlayer won't deallocate the player if something else has a strong reference to it. (That "something" may be some part of the system frameworks, or even itself in some rare cases. It doesn't have to be your code.)
If the AVAudioPlayer has pending autorelease calls on it, then it won't be released until the autorelease pool drains (usually at the end of event loop, which basically means "when your method that UIKit called returns.") For example, if you create a large number of objects in a loop and immediately throw them away, they may or may not be deallocated until the autorelease pool drains. Again, autoreleases may be injected by system frameworks. In practice, this means that the object will usually be deallocated "soon" (in a small fraction of a second), but not necessarily immediately. You can clean up autoreleased objects sooner by using #autoreleasepool blocks, which is sometimes necessary if you create many temporary objects in a loop. This is not needed very often.
But to a first-order approximation, in many of the most common cases, yes, replacing the property will automatically and immediately deallocate the previous object.
It would be useful to show how you declared thePlayer. If they are synthesized properly the memory management would be handled automatically. It appears that you are using "self" to access thePlayer and if so you'd be setting the value through a setter/getter and that would handle the memory management for you. But I also notice that "Self" is capitalized and should not be in order to properly use the setter/getter. For more info on synthesized variables check out: What exactly does #synthesize do?. Note there are some places where you should NOT use self and this link discusses that: How does an underscore in front of a variable in a cocoa objective-c class work?.

Can we use deinitialized variables in code, or are they pretty much useless because they are deallocated right after?

Im a little confused on the topic of deallocation when comparing it to deinitaizlization. Doesn't deallocation happen the moment after a variable is deinitialized.....My main point here is, Could we use/manipulate deinitialized variables somehow? or they are pretty much useless because deallocation takes place right after...?
In Swift the deinit method is called as part of the deallocation process. Precisely when the memory allocated to an object is released you cannot know, but you can't access the object after it has been deinitalised.
Aside from it not making any sense to do so, it isn't possible to manipulate the object after deinit since the deallocation process is initiated by the removal of the last strong reference to the object. as there are no references how could you manipulate the object anyway. (I suppose you could use an unowned/unsafe reference to attempt to access the object but this would result in your app crashing)

CFBridgingRelease ussage when assigning to a property - is niling it out necessary ("Crossing the Bridge")

I am using a CFBridgingRelease when acquiring a network stream:
self.networkStream = CFBridgingRelease(
CFReadStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) url)
);
The property definition is:
#property (strong, readwrite) NSInputStream *networkStream;
In certain circumstances (when a proper streamEvent is received in the run loop) I finish the operation:
if (self.networkStream != nil) {
[self.networkStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.networkStream close];
self.networkStream.delegate = nil;
self.networkStream = nil;
}
This is made as an NSOperation (adding to a NSRunLoop for a thread like AFNetworking one).
It is based on the Apple example:
https://developer.apple.com/library/ios/samplecode/SimpleFTPSample/Introduction/Intro.html
Should i make the
self.networkStream = nil
or will it be managed by ARC and the nil is unnecessary or even bad?
Also when I use the CFBridgingRelease is the Release made on acquire or when niling the value or how does it exactly work (I've done some reading and I k'now it is "passing the memory management responsibility to ARC" for an object acquired from CoreFoundation using "Create/Copy" as the "Create Rule"). Perhaps some more insight or info on it?
Thx in advance.
EDIT:
Ok.. Went through your comments but I have one issue mentioned
NSStream error in specific configuraion
In a nutshell => It works ok (even when trying to download an non existent file) but when the FTP server has bad rights it crashes and only in RELEASE configuration. I added two pictures from instruments -> one when I do nil out the property and the other when I don't.
Again - this only happens in RELEASE and in that specific FTP configuration!
This is tightly related so please if you have any ideas anwser on that thread.
This line
self.networkStream = nil
is not necessary, but it's not bad either.
ARC releases a resource when it's no longer needed, in other words, when there are no strong references to it, this means that the resource is released when you set it to nil, or when the variable referencing it goes out of scope (this should answer both your first and second questions).
In your case, since this variable is a member of your class, if you set it to nil it will be released immediately (to be precise, at the end of the current run loop). If you don't set it to nil, it will be released when your class is destroyed.
CFBridgingRelease does just what you say it does, your insight is fine. If you have an owned CF object which is one of the toll-free bridged types then you can transfer your ownership to ARC to manage. Despite the name, CFBridgingRelease doesn't "release" the object in the retain-release sense, it releases you from having to manage the ownership.
When it is no longer required ARC will relinquish your ownership of the object automatically, and if there is no other ownership interest that will result in the object being freed (released).
Assigning nil to a variable/property of strong reference type cannot be "bad" in the sense it could break memory management. Such an assignment simply relinquishes an ownership interest in the referenced object. Assigning nil is often unnecessary as ARC will relinquish ownership in a timely fashion; but, for example, if you have a property on a long-lived object you may want to assign nil to the property to relinquish your interest sooner.
Of course assigning nil can be "bad" in a program-logic sense if you actually need the object and the assignment causes it to be released!
HTH
No need to set property to nil value. ARC will take care releasing that object.
CFBridgingRelease : It will transfer ownership to ARC, if passed object is Owned by you.(__bridge_transfer use this, while you are casting object)
CFBridgingRetain : It will transfer ownership to you from ARC(__bridge_retained).
If you don't want to transfer ownership, then you need to cast one objet to another object using "__bridge".
All object owned by you should be released after its Usage. It may be you received ownership by using CFBridgingRetain(), you should release that object.

Coredata | Child Context memory Management

I am creating some child context from the main context and I wanted to know do I need to release the child context?
I have a CoreData class which creates child context (this class is an arc enabled classes) but it can provide context to other classes which might not be arc classes.
- (NSManagedObjectContext *) createChildContext
{
NSManagedObjectContext *childManagedContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
childManagedContext.parentContext = [self parentContext];
return childManagedContext;
}
then some other class can get the child context
NSManagedObjectContext *context = [coredata createChildContext];
My question is do I need to release the context in this class or will it be auto managed by the arc class that created it since I am not retaining it.
This is actually a pretty interesting question, since you're mixing ARC and non-ARC. As always, though, the Memory Management Policy can help us decide what to do in this situation.
First off (as I think you already know), you don't have to release the context in the ARC class that creates it (inside -createChildContext). In fact, you can't explicitly release or autorelease it there, since the class is ARC - you can't do any manual memory management inside it.
Now let's look at the calling class. As you have it written, you do not have to release the context once you're done with it. Since you have not taken ownership of the context, you shouldn't tell the object that you're releasing it; it's not your place to give up ownership of an object you never owned in the first place.
Why haven't you taken ownership of the context? Well, as you have it written, you never:
Explicitly retained the object (e.g. [[coredata createChildContext] retain])
Assigned the object to a #property marked retain or strong
Got the object from a method starting with alloc, new, or copy
In this sense, you could think of the object being "managed by" the ARC class that created it, though that's a bit misleading; in reality, it doesn't matter who manages it, it just matters that you don't own it in the non-ARC calling class.
If you need to change that for some reason - say, you need the child context to stick around for a while, or you intend to use it throughout your class - you could consider one of the approaches listed above, where you do take ownership of the context. In that case, you would have to release it when you're done with it.
I highly recommend reading over the Advanced Memory Management Programming Guide; it has a lot of very useful things to say about dealing with object ownership, among other topics.

Resources