Cocoa Deep Copy Containers - objective-c

I am tying to understand the example in the apple docs for deep copying an array of dictionaries Here.
In Listing 3 A true deep copy
The example shows
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];
Notice there is no copy, mutable copy , or autorelease operators, so I am struggling to understand how this is a copy and how it gets released. In fact, if I release my implementation, it will crash. It does however work as expected, and there does not appear to be any abandoned memory using it as the example shows.
I looked the the NSUnarchiver class reference and it mentions that the unarchiveObjectWithData method creates a temporary copy of the object(s)?
Does this mean the proper implementation then is to allocate and init the new array rather than just assigning the pointer so it can be released?
Thanks in advance.

They are doing a deep copy by doing a full archival pass on the object graph. Using NSArchiver enables things like automatic cyclic reference management and the objects can choose not to encode things like their delegate or they can hook stuff back up on unarchival.
For all intents and purposes, it is archival by saving something to disk and then reading it back in as a new document. Only, instead of the disk, it is just stored in memory all the time.
It is slow, very expensive, and totally inappropriate for anything but when you very occasionally need to duplicate a complex object graph completely.
unarchiveObjectWithData: returns an auto-released object. If you using MRC, you need to retain it if you want to keep it. But, a better solution would be to move to ARC.

You are crashing on retain (or shortly after) because you did not respect Apple's stated memory management rules, which can be found here: https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
Did you get the object from a method that contains alloc, new, copy or deepCopy in its name? No, then it is not your responsibility to release it.
Do you want to hold on to this object? If so, it is your responsibility to retain it.
As to why this code snippet results in a deep copy, you should read again what the archiver classes do. They don't deal with your objects, they deal with "descriptions of the contents of your objects". You might just as easily have done a "json import of the result of a json export" or an "xml import of an xml export".

Related

Can I snapshot and restore memory of Objective-C object graph?

I'm designing a object persistent code.
IMO, memory snapshot is fastest, reliable and compact persistent method within a few limitation.
It's easy with C structs. I can layout all objects' memory layout manually. I can save all references as index of object collection. So reference is not a problem.
Anyway I want to try this with Objective-C objects. To do this, objects must be positioned in specific location of memory. So, if I can specify memory location of allocation, I can snapshot the memory. And when restoring, I can get an object at specific address.
Of course, all of these are machine-specific and needs many tricks, but it's fine to me.
The only problem is I don't know way to specify location of new Objective-C object. How can I do this?
Generally people use NSCoding and NSKeyedArchiver (or some custom subclass thereof). I think your C method would have worked before the 64-bit runtime, since the data part of objects was implemented using structs, but I think the new runtime's use of nonfragile instance variables would complicate matters. In any event, the program that loads the persistent objects still has to have the class definitions for them, either hard-coded or loaded via bundles.

What happens when an NSArray element gets deallocated?

Let's suppose I create a few objects and I add them to an array.
House *myCrib = [House house];
House *johnHome = [House house];
House *lisaHome = [House house];
House *whiteHouse = [House house];
NSArray *houses = [NSArray arrayWithObjects: myCrib, johnHome, lisaHome, whiteHouse, nil];
Normally, all House objects have a retain count of two, but they're being autoreleased once. After a while, I decide to release myCrib, even if I'm not the owner — I never retained or initialized.
[myCrib release];
The retain count should drop to zero and my object should be deallocated. My question now is: will this illegal action cause my app to work erroneously or even crash, or will NSArray simply delete my object from its list with bad consequences.
I'm looking for a way to maintain a list of objects, but I want the list to maintain itself. When some object disappears, I want the reference to it to disappear from my array gracefully and automatically. I'm thinking of subclassing or wrapping NSArray.
Thank you.
My question now is: will this illegal
action cause my app to work
erroneously or even crash, or will
NSArray simply delete my object from
its list with bad consequences.
Your array now has an invalid object pointer. There's no way to tell that the pointer is invalid just by looking at it, and the array isn't notified that the object has been deallocated. The problem isn't with the array, after all, the problem is with the code that improperly releases the object. So yes, the application will likely crash or otherwise behave incorrectly due to that bad pointer, and no, NSArray won't detect and deal with the problem for you.
I'm looking for a way to maintain a
list of objects, but I want the list
to maintain itself. When some object
disappears, I want the reference to it
to disappear from my array gracefully
and automatically.
If the objects in the list are all instances of a common class, you could define your own memory management methods that both retain/release the object and add/remove it from the list, or broadcast appropriate notifications in case there can be multiple lists. I suppose you could even override -retain and -release for this purpose, but I'd think long and hard about that before doing it, and document it well if you do; it's not the sort of thing that other developers would expect.
Another option might be Core Data. If you delete a managed object from the object graph, it'll disappear from any relationships. Strictly speaking, a to-many relationship is a set, not a list, but the difference may not be a concern for your purposes.
Update: I just noticed that you didn't tag your question ios. If you're working under MacOS X, you should definitely take a look at NSPointerArray. If you use garbage collection, NSPointerArray can be configured to use weak references and to replace references to collected objects with null references. This is exactly what you seem to be looking for.
You should not release myCrib if you are not the owner. To do so is a violation of the memory management guidelines and will make your code extremely difficult to maintain. I cannot stress enough that you absolutely should never do this under any sort of circumstance. You're asking for crashes; the array has declared ownership of the object, and you must not subvert that ownership in any way.
So the answer here is: your code is absolutely wrong and you should fix it. If you can't fix it, you should trash it and start over and keep rewriting it until you've come up with another way to achieve the same effect without subverting object ownership. I guarantee that it's possible.
If what you want is a weak-referencing array, then there are a couple ways you can do this (this was just asked a couple of days ago):
NSPointerArray - weakly references its pointers. When you use garbage collection, they're autozeroing (ie, the pointers get removed when the object is deallocated). Unfortunately, this is not available on iOS.
CFMutableArrayRef - you can specify a custom retain and release callback, or just not specify one at all. If you leave them out, the array will simply not retain the objects it contains. However, this does not automatically remove the pointer when the object is deallocated.
DDAutozeroingArray - an NSMutableArray subclass I wrote the other day to provide a weakly-referencing and auto-zeroing array that works on both Mac OS and iOS. However, I strongly encourage you to use this only as a last resort; There are probably much better ways of doing what you're looking for. https://github.com/davedelong/Demos
I'm looking for a way to maintain a
list of objects, but I want the list
to maintain itself. When some object
disappears, I want the reference to it
to disappear from my array gracefully
and automatically. I'm thinking of
subclassing or wrapping NSArray.
If I have understood right, what you want is an array of weak references. Then, you might be interested in reading this post.
You're asking for a crash here. Your NSArray will still have a reference to the object that now no longer exists -- and who knows what it will be pointing to after a while?
Subclassing NSArray might not be the answer either. It's a class cluster which, in short, means that it's harder to subclass than you might hope.
Not entirely sure how you'd implement this. Something like the element sending a notification when they're about to be deallocated which the array would then pick up. You'd need to be careful that you didn't leak or over-release your objects.
I created a wrapper class — in my code it's called a controller — which maintains the (mutable) array for me. I initialize the controller class in my view controllers — the place where I need them — instead of using an array directly.
No invalid code for me. :-p

Objective-C Multithreading and Data Containers

I have sort of a simple question. I am writing an Objective-C program with some multithreading. I have a global NSArray, and I add objects into that NSArray from a method that is called in a new thread. If the objects I add into that NSArray are new objects created in that method (local), will that create memory access and/or other issues or will the garbage collector be smart enough to keep those objects around until they have no more references? Also, if I want to an object into that NSArray, will that object be passed by reference or by value?
Can you add objects in NSArray? I guess you mean NSMutableArray.
NSMutableArray is NOT thread safe. So you may need to acquire a lock before trying to modify it. Though this will mostly dependent on how your threads are working on shared data.
NSArray or NSMutableArray will retain the objects that they contains. So after adding you can release the local copy.
The array will store the reference.
Hope it helps. In general multithreading is much more difficult than a single thread app. Please check Threading Programming Guide for the details. It may save you from many hazards.
There should be no problems with the design you're describing. All of your threads share the same memory space, so everything will work just fine. The memory management system will do "the right thing", but I recommend learning the retain/release method - there's nothing better than actually understanding what your program is doing.
Objective-C is pass-by-value only, just like C. That said, objects are only ever passed around by pointers in Objective-C, so you can think of it as always pass-by-reference in that sense.

How should I memory manage objects returned by instance methods?

Plenty of Objective-C classes return objects. Statements like [[instanceOfNSWhatever objectForKey:aKey] stringValue], for instance, appear all over my (and hopefully everyone else's code).
How am I supposed to memory manage these "intermediate" objects?
Were they just created or did they always exist?
Can I retain them, and if I release the object that created them, will they be released as well?
Are they autoreleased?
What if I run [instanceOfNSWhatever stringValue] a million times in a loop? Can I dispose of all those NSStrings as needed?
I'm still learning ObjC, and while I've been good at balancing my retain counts overall, I'm definitely lacking some understanding about how these methods work. Can anyone fill me in?
You've probably already read this section of Apple's docs about memory management, but I'll point you to the section about the Object Ownership Policy just in case. You are only responsible for managing the memory of objects you "own". To quote the docs:
You own any object you create.
You "create" an object using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy).
If you own an object, you are responsible for relinquishing ownership when you have finished with it. [ie: release]
If you do not own an object, you must not release it.
The "Simple Examples" section of those docs provide good elaboration, but to put the points above in the context of your specific questions:
How am I supposed to memory manage these "intermediate" objects?
The good news is: you don't. Ignore the the memory management aspect of the "intermediate" objects in your example.
Were they just created or did they always exist?
They may have always existed, or they may have just been created. The beauty of objective-c is that you, as a consumer of those objects, don't have to care.
Can I retain them, and if I release the object that created them, will they be released as well?
You don't need to retain them if you're just passing them on to some other function, or using them as intermediate values yourself in your own calculations within the function. Say, for example, that you're returning the stringValue from your example function to someone else. There's no point in retaining it just to return it.
If you DO happen to retain it, then yes, you are responsible for issuing a corresponding release message as some point. You might, for example, retain the stringValue from your example if you want to hold on to that value as a property in your own instance. Objective-C uses reference counting. If you need that object to stick around for a long time, you must retain it so that someone else's release message doesn't cause it to vanish if the retain count falls to 0.
Are they autoreleased?
Depends. Let's say you ask for a string from instanceOfNSWhatever. If instanceOfNSWhatever has to create that string just special for you (in order to service your request), but doesn't otherwise care about that string, then yes... instanceOfNSWhatever probably put that string into the autorelease pool. If the string was already a property of instanceOfNSWhatever and it was just sending it to you in response to your request, then no, it probably wasn't autoreleased.
Again, the beauty is: you don't know and don't need to care. Since instanceOfNSWhatever created the string, it is responsible for managing it. You can ignore the memory management unless you add to the string by sending it a retain message.
What if I run [instanceOfNSWhatever stringValue] a million times in a loop? Can I dispose of all those NSStrings as needed?
No need. Again... stringValue isn't yours to manage because you didn't create it. As a technical note, if instanceOfNSWhatever really did have to create 1 million copies of stringValue to service your 1 million calls, it probably put them all in an autorelease pool, which would be drained at the end of the current cocoa event loop. Fortunately, unless you send each of those stringValue objects a retain message, you can gleefully ignore the memory management question here.
You basically manage all your memory according to the Memory Management Programming Guide for Cocoa. In short, however, you basically only need to worry about objects that you "own". You own an object if you create it (in Cocoa, you create an object by specifically allocating it using alloc or copying it using copy or one of their derivatives). If you own an object, you are responsible for releasing it when you are finished with it.
Any other object is, therefore, not owned by you. If you need to use such an object for any extended period (for example, outside the scope in which you received it), you need to specifically take ownership of the object by either sending it a retain message or copying it.
To answer your last question, if you are creating a lot of temporary objects in a loop or some other way, you can create your own autorelease pools. See the documentation for NSAutoreleasePool for more information about using them. Please note, however, that you should really only do this after you've profiled your application and found that it is using too much memory and would benefit from this kind of optimization.
Finally, if you are creating and releasing a lot of heavy objects and don't want to rely on autorelease pools, you can specifically allocate and initialize them and then make sure to release them on your own as soon as you're finished with them. Most objects that have convenience creators have similar initializers for creating the object specifically.
When working on the iPhone/iPod Touch, the autorelease objects are released when your application exits. This may be what you don't want. Especially when working with images or large chunks of data. To insure large pools of memory that are tagged autorelease get released sooner, create local autorelease pools. Like this:
NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];
-- do something that creates large autorelease memory blocks --
[localPool drain];
If you don't do this, you will find your application exiting unexpectedly.
I'll tell you a simple rules I wish I'd known when I first started Objective-C :)
If an method contains the words "alloc" or "copy" then you must [release] the object when finished.
If a method does not contain these words, you must [retain] it for it to remain valid outside of your function.
If you call [retain] you must later call [release] when finished.
This covers practically all you need to know about the basics of memory management.
ObjC makes heavy use of what are known as "auto release" pools. Objects returned from non alloc/copy functions are placed into these pools and automatically freed after your function exists.
That is why you do not need to release the results of something like [obj stringValue].

Instance caching in Objective C

I want to cache the instances of a certain class. The class keeps a dictionary of all its instances and when somebody requests a new instance, the class tries to satisfy the request from the cache first. There is a small problem with memory management though: The dictionary cache retains the inserted objects, so that they never get deallocated. I do want them to get deallocated, so that I had to overload the release method and when the retain count drops to one, I can remove the instance from cache and let it get deallocated.
This works, but I am not comfortable mucking around the release method and find the solution overly complicated. I thought I could use some hashing class that does not retain the objects it stores. Is there such? The idea is that when the last user of a certain instance releases it, the instance would automatically disappear from the cache.
NSHashTable seems to be what I am looking for, but the documentation talks about “supporting weak relationships in a garbage-collected environment.” Does it also work without garbage collection?
Clarification: I cannot afford to keep the instances in memory unless somebody really needs them, that is why I want to purge the instance from the cache when the last “real” user releases it.
Better solution: This was on the iPhone, I wanted to cache some textures and on the other hand I wanted to free them from memory as soon as the last real holder released them. The easier way to code this is through another class (let’s call it TextureManager). This class manages the texture instances and caches them, so that subsequent calls for texture with the same name are served from the cache. There is no need to purge the cache immediately as the last user releases the texture. We can simply keep the texture cached in memory and when the device gets short on memory, we receive the low memory warning and can purge the cache. This is a better solution, because the caching stuff does not pollute the Texture class, we do not have to mess with release and there is even a higher chance for cache hits. The TextureManager can be abstracted into a ResourceManager, so that it can cache other data, not only textures.
Yes, you can use an NSHashTable to build what is essentially a non-retaining dictionary. Alternatively, you can call CFDictionaryCreate with NULL for release and retain callbacks. You can then simply typecast the result to a NSDictionary thanks to tollfree bridging, and use it just like a normal NSDictionary except for not fiddling with retain counts.
If you do this the dictionary will not automatically zero the reference, you will need to make sure to remove it when you dealloc an instance.
What you want is a zeroing weak reference (it's not a "Graal of cache managing algorithms", it's a well known pattern). The problem is that Objective C provides you with zeroing weak references only when running with garbage collection, not in manual memory managed programs. And the iPhone does not provide garbage collection (yet).
All the answers so far seem to point you to half-solutions.
Using a non-reataining reference is not sufficient because you will need to zero it out (or remove the entry from the dictionary) when the referenced object is deallocated. However this must be done BEFORE the -dealloc method of that object is called otherwise the very existence of the cache expose you to the risk that the object is resurrected. The way to do this is to dynamically subclass the object when you create the weak reference and, in the dynamically created subclass, override -release to use a lock and -dealloc to zero out the weak reference(s).
This works in general but it fails miserably for toll-free bridged Core Foundation objects. Unfortunately the only solution, if you need to to extend the technique to toll-free bridged objects, requires some hacking and undocumented stuff (see here for code and explanations) and is therefore not usable for iOS or programs that you want to sell on the Mac App Store.
If you need to sell on the Apple stores and must therefore avoid undocumented stuff, your best alternative is to implement locked access to a retaining cache and then scavenge it for references with a current -retainCount value of 1 when you want to release memory. As long as all accesses to the cache are done with the lock held, if you observe a count of 1 while holding the lock you know that there's no-one that can resurrect the object if you remove it from the cache (and therefore release it) before relinquishing the lock.
For iOS you can use UIApplicationDidReceiveMemoryWarningNotification to trigger the scavenging. On the mac you need to implement your own logic: maybe just a periodical check or even simply a periodical scavenging (both solutions would also work on iOS).
I've just implemented this kind of thing by using an NSMutableDictionary and registering for UIApplicationDidReceiveMemoryWarningNotification. On a memory warning I remove anything from the dictionary with a retainCount of 1...
Use [NSValue valueWithNonretainedObject:] to wrap the instance in an NSValue and put that in the dictionary. In the instance dealloc method, remove the corresponding entry from the dictionary. No messing with retain.
My understanding is that you want to implement the Graal of cache managing algorithms: drop items that will no longer be used.
You may want to consider other criteria, such as dropping the least recently requested items.
I think the way I would approach this is to maintain a separate count or a flag somewhere to indicate if the object in the cache is being used or not. You could then check this when you're done with an object, or just run a check every n seconds to see if it needs to be released or not.
I would avoid any solution involving releasing the object before removing it from the dictionary (using NSValue's valueWithNonretainedObject: would be another way to accomplish this). It would just cause you problems in the long run.