Is it possible to implement NSFastEnumeration when using weak references? - ios

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.

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.

Manual reference counting and AutoRelease

In manual memory management on what scenarios you will go for Auto Release
I'd like to be well prepared as I am about to do a project using without ARC
You typically use autorelease when you need to return an object from a method, and relinquish ownership at the same time: upon returning the calling side (not the creating method) should own the object.
If you just relinquish ownership before returning the object (with release), it gets immediately deallocated and the calling side can not use it. If you don't call release, the object has a reference count of +1 from the called function (that instantiated it), which also has no further chance to release after the calling side has claimed ownership.
So, autorelease is like a "deferred release": the object gets sent one release method at a later time (but not before the function that is returning it returns).
Addendum:
The alternative approach is to return objects with an agreed-upon reference count of 1, and rely on the calling side to release it when done.
This is made explicit by adopting a preestablished naming pattern for those methods: In cocoa, they typically contain the words "alloc", "new", "copy" or "mutalbeCopy".
Source: Apple's documentation.

When to use takeUnretainedValue() or takeRetainedValue() to retrieve Unmanaged Objects in Swift?

According to Using Swift with Cocoa and Objective-C you can use takeUnretainedValue() and takeRetainedValue()to tell Swift how to manage the memory of an object for a function like this:
func StringByAddingTwoStrings(CFString!, CFString!) -> Unmanaged<CFString>!
When do I have to use takeUnretainedValue() or takeRetainedValue()?
When I use ARC is it then always takeUnretainedValue()?
You use takeRetainedValue when the unmanaged object has a +1 retain count and you want ARC to take care of releasing the object when you're done. For example, if you call a Core Foundation function with Create or Copy in the name (see Create Rule in the Memory Management Programming Guide for Core Foundation) which returns an unmanaged object for which you are responsible for releasing, you generally use takeRetainedValue so that it is released for you (or, if you don't do this, you have to manually release it yourself with CFRelease or similar function). You use takeUnretainedValue when ownership of the object has not been transferred to you and you therefore do not want ARC releasing the object for you when it falls out of scope.
So, as to when you call takeUnretainedValue vs takeRetainedValue, it simply depends upon what sort of object the called function returns. As a general rule of thumb, if the object was returned from a Core Foundation function with Create or Copy in the name, use takeRetainedValue. Otherwise use takeUnretainedValue.
In terms of what happens if you call the wrong method, if you call takeUnretainedValue when you're passed a +1 object (e.g. an object returned from Core Foundation function with Create or Copy in the name), your app will leak unless you explicitly CFRelease it. You may not immediately notice the occasional leak when running the app, but it can be observed by watching your app's memory usage (e.g. if you profile your app with Instruments). But if you leave these leaks unresolved, your app may eventually receive memory warnings.
On the other hand, if you call takeRetainedValue on an object which has not been retained for you (returned by a function that did not have Create or Copy in its name), the app will likely crash when the object is released. Sometimes this won't manifest itself immediately (not until the last strong reference is resolved), but it will generally result in a catastrophic failure of the app.
So judicious selection of takeUnretainedValue vs takeRetainedValue is very important.
Quoting from NSHipster:
https://nshipster.com/unmanaged/
An Unmanaged instance wraps a CoreFoundation type T, preserving a reference to the underlying object as long as the Unmanaged instance itself is in scope. There are two ways to get a Swift-managed value out of an Unmanaged instance:
takeRetainedValue() returns a Swift-managed reference to the wrapped instance, decrementing the reference count while doing so—use with the return value of a Create Rule function.
takeUnretainedValue() returns a Swift-managed reference to the wrapped instance without decrementing the reference count—use with the return value of a Get Rule function.

Why is an object not automatically set to nil when its reference count becomes 0?

In a non ARC Objective C environment, I understand why we have to release an object: to free the memory allocated for it; I understand why we have to set it to nil afterwards (if we are sure nothing else needs the instance / nothing else still has a hold on the object): to avoid dangling pointers.
However my question is, if all objects release their hold on an object, "carInstance" for example, resulting in its reference count going down to 0, why oh why does that Not automatically make it nil?
If reference count is now 0, is the object still usable in any way? Or is this just one of those things we have to do just because that's how not having garbage collection works (can't be, there must be a reason)
The simple answer is that the manual memory management model that was used pre-ARC is lightweight and simple. The behavior you are wishing for is the behavior you get with weak pointers under ARC; and it requires extra work by the OS, to track weak pointers and nil them out when the object is reclaimed. It's doable, clearly, but the cost of implementing it, as well as the computational overhead, wasn't deemed worthwhile until Apple was already rolling out the extra work of implementing ARC.
After an object is deallocated, the dangling pointer is worse than useless: it is downright dangerous. Referencing it while it points to unallocated memory produces an exception; referencing it after it is randomly reassigned to another object or some other memory allocation will typically produce an 'object does not respond to selector' error.

Does a TList<TProc>.Clear free all captured variables?

When I have a TList (so, a list of "reference to procedure"), and I Clear it, do all the captured variables used in the anonymous methods get freed, so no leaking occurs?
Ie. is reference counting in effect upon clearing the TList?
Delegate types are reference counted like interfaces (in fact they are implemented as interfaces). That means if they run out of scope the object behind the scenes (you might have seen that ArcRec$xxxx thing mentioned somewhere - that is the class name the compiler generates) gets destroyed. Captured variables are implemented as fields inside that class so they also run out of scope and are getting freed.
However you might pay attention to some circular referencing which might cause a memory leak with captured variables because of some important fact:
If you have multiple anonymous methods inside a single routine/method they all are implemented by one single class (that ArcRec$xxxx thing). So in this case the anonymous method with the longest lifetime might keep another one alive even if that already is out of scope.

Resources