Will an NSManagedObject ever turn into a fault while I have a strong reference to it? - ios

How can I know when to trust my NSManagedObject with stay around with its non managed variables. Surely a strong reference?

A managed object being a fault is unrelated to whether you have a strong reference to it. The comparison is sort of like saying, if I have a strong reference to an object, can its property values change? So yeah, it's possible for a managed object to re-fault regardless of what kind of reference(s) you have to it.
As a specific example, if you call refreshObject:mergeChanges: with your object as the first argument and with the second argument set to NO, you force the object to re-fault. But you can still have a strong reference to it.
But keep in mind that being a fault object has no relationship to whether it will "stay around", as you say. It still exists in memory. It hasn't been deallocated. You can even still use its property values.

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.

Does ARC set its reference type instance properties to nil before deallocation?

This question occured to me while reading this.
My question is in reference to the image below:
Once john is set to nil, Person instance no longer has any more strong reference and hence will be deallocated. But Apartment has two strong references and one of which is by the property on Person instance that would be soon deallocated. I believe, this strong reference continue to remain after deallocation and goes out of reach by the code.
So, setting unit14A to nil will remove only one strong reference to Apartment instance and it should not be deallocated as there would be one more strong reference due to the above case.
But, as the document says Apartment instance promptly got deallocated. To me, this can only happen if at the time of Person instance deallocation it sets its apartment property to nil, by that removing that strong reference on Apartment instance. But I couldn't find any documentation to verify this.
So, How does the Apartment instance get deallocated? What happened to the strong reference from the Person instance apartment property?
Can someone help me to understand this?
Objective-C objects are reference counted, meaning that for each object, the system keeps track of how many other objects hold a reference to it. This is object's reference count. Two special messages, retain and release, are used to maintain the reference count behind the scene. Once reference count goes down to zero, the system deallocates the object.
ARC provides "magic" to make reference counting work in a declarative way. The compiler knows every strong reference in your code, so when you do this
myStrongRef = nil;
the compiler quietly inserts a call to release in front of the assignment:
[myStrongRef release];
myStrongRef = nil;
To me [deallocation of Apartment] can only happen if at the time of Person instance deallocation it sets its apartment property to nil, by that removing that strong reference on Apartment instance.
Setting a strong reference to nil one way of breaking a strong reference. It is sufficient, but it isn't necessary. The important thing about setting a strong reference to nil is not the act of setting itself, but what happens immediately before it: the instance referred to by the strong reference gets a release message, instructing it to decrement its reference count. That is precisely what ARC does behind the scene for you: it sends the release message to Apartment, without setting Person's reference to nil.
How does the Apartment instance get deallocated? What happened to the strong reference from the Person instance apartment property?
Once strong reference from Person has sent its release message to Apartment, that strong reference disappears. The actual pointer may be set to Apartment's address, but nobody cares about it, because the Person itself is unreachable.
The life of an object depends on it's reference count, not any actual pointer to the object.
Strong reference is a way of speaking, there is no difference between a strong and weak reference, they are just pointers. The difference is that when a strong reference is created the reference count of the object pointed to in incremented and when deleted the reference count is decreased. When an object's reference count would become zero the object is deallocated.
Your intuition is correct. When an object is being deallocated under ARC all the strong references it holds are first relinquished - essentially they are set to nil, but in practice the implementation may differ.
This is also what happens when a method returns, or a block of code containing declarations exits, all the strong references held in local variables are relinquished.
All the details can be found in the Clang documentation.
HTH
Obviously not before deallocation, but during deallocation.
When an object's reference count goes to zero, the deallocation process starts. The object is marked as "being deallocated". At that point, the object will die (unlike Java, where it can be recovered). If an object is marked like this, it cannot be assigned to weak references (they stay nil), or to strong references.
Then dealloc is called, that is the dealloc methods that you have written. After that, strong references are set to nil, reducing their reference counts, then associated objects are removed, and finally the memory for the object is deleted.

Objective-C How to check which objects are referencing my object (retain cycle)

In a certain portion of code - I am expecting an object to be dellocated but it isn't.
Given that object - how can I check which objects are referencing it?
Also - Is it possible to know every time an objects reference count goes up? (and by which object)
You cant check it. Rather you should use instruments to check the same. They will show the retain count of the object. Perform the steps by running the app on instrument and check for retain count.
Even you should not use retainCount method to check. There is no way to identify that which objects are pointing to you object.

What are the disadvantages of setting every property to strong?

As a new iOS programmer, I've had a slew of bugs to fix today, a few of them have been related to me using weak properties instead of strong.
I realise that a good programmer wouldn't have this problem and would only set the properties to strong that need to be, but nonetheless, in my newbie eyes, I can't see why I should use weak, it only adds the risk of problems.
In general, you should decide between weak, strong, assign, and copy by looking at the relationship between the class holding the property and the value of that property, and also the kind of the property being passed.
If the property being set is primitive, use assign (or do not use ownership qualifier at all)
If the property being set is a scalar, immutable object, use strong
If the property being set is a scalar, mutable object implementing NSCopying protocol, use copy
If the property being set is mutable, and the ownership is transferred to your object, use strong
If the property being set is a mutable object implementing NSCopying protocol, but the ownership remains with the caller, use copy
If the property being set is a back reference (i.e. a "to parent" property in a "child" object), use weak.
The concept of ownership is very important in reference counted memory models. This is the primary driving factor behind your decision. You need to decide where is the primary owner of an object, and give that owner a strong reference. If an ownership is shared among a group of objects, give them all a strong reference.
The most difficult situation is when objects could own each other, directly or indirectly. In this case you would be better off replacing "ownership" with "knows about", give all objects a common "top" owner who "owns" everybody, and model the "knows about" relationships with weak references.
weak and strong are very important to get right for memory management purposes.
strong will increase the reference counter for the pointer, and you effectively say that you own the object.
weak does not increase the reference counter, and the object can potentially disappear at any time. If you have a cyclic dependency, you should use weak to avoid a memory leak (two objects both having a strong reference to each other is a cyclic dependency and those objects will never be released).
You should always think about your memory management, but a good rule of thumb is that the property should always be strong, unless you positively know that it is retained elsewhere. Multiple objects can have a strong reference to the same object with no problems, as long as no cyclic references occur.
Some super basic rules of thumb:
If you want the object to stick around at least until you are finished with it, go with strong
If you can handle the object disappearing without it hurting you too bad (i.e it is the parent that created you that might be nice to know about but not super important) then use weak
if it is not an NSObject (so is an int, bool float or other primitive type) use assign.
A rule of thumb that I use is: if the object is retained somewhere else, use weak. The biggest thing for me is when using interface builder. If you have an IBOutlet, you can make it weak, because that object is taken care of in interface builder and in the XIB file

ARC in iOS questions

~ Will ARC always release an object the line after the last strong pointer is removed? Or is it undetermined and at some unspecified point in the future it will be released? Similarly, assuming that you don't change anything with your program, will ARC always be the same each time you run and compile your program?
~ How do you deal with handing an object off to other classes? For example, suppose we are creating a Cake object in a Bakery class. This process would probably take a long time and involve many different methods, so it may be reasonable for us to put the cake in a strong property. Now suppose we want to hand this cake object off to a customer. The customer would also probably want to have a strong pointer to it. Is this ok? Having two classes with strong pointers to the same object? Or should we nil out the Bakery's pointer as soon as we hand off?
Your code should be structured so the answer to this doesn't matter - if you want to use an object, keep a pointer to it, don't rely on ARC side effects to keep it around :) And these side effects might change with different compilers.
Two strong pointers is absolutely fine. ARC will only release the object when both pointers are pointing to something else (or nothing!)
ARC will implement the proper retains and releases at compile time. It will not behave any different than if you put them in there yourself so it will always do the same compilation and to answer your question should always behave the same. But that said it does not mean that your object will always be released immediately after the pointer is removed. Because you never call dealloc directly in any form of objective C you are only telling it that there is no reference count and that it is safe to release. This usually means that it will be released right away though.
If you pass an object from one class to another and the receiving class has a strong property associated with it and the class that passes it off eventually nils its pointer it will still have a reference count of at least 1 and will be fine.
Ok, first this answer might helpt you also a little bit: ARC equivalent of autorelease?
Generally after the last strong variable is nilled, the object is released immediately. If you store it in a property, you can nil the property, assign it to something like __strong Foo *temp = self.bar; before you nil, and return that local __strong variable (although arc normally detects the return, and inferes the __strong byitself).
Some more details on that: Handling Pointer-to-Pointer Ownership Issues in ARC
DeanWombourne's answer is correct; but to add to (1).
In particular, the compiler may significantly re-order statements as a part of optimization. While method calls will always occur in the order written in code (because any method call may have side effects), any atomic expression may be re-ordered by the compiler as long as that re-order doesn't impact behavior. Same thing goes for local variable re-use, etc...
Thus, the ARC compiler will guarantee that a pointer is valid for as long as it is needed, no more. But there is no guarantee when the pointed to object might be released other than that it isn't going to happen beyond the scope of declaration. There is also no guarantee that object A is released before B simply because A is declared and last used before B.
IN other words, as long as you write your code without relying on side effects and race conditions, it should all just work.
Please keep you code proper as it has diffrent behaviour on diffrent complier.

Resources