Some of you may have noticed that viewControllers no longer request viewWillUnload and viewDidUnload in iOS6. This is because the controllers no longer automatically upload their views.
Your first thought might be, “Okay, how can I manually unload my view with a low memory warning?” It looks like a step back. ”
Then you look for answers and write something like:
- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; if([self isViewLoaded] && ![[self view] window]) { [self setView:nil]; } }
However, this method should not be used, it is potentially harmful due to some changes in the basic support of UIView. Therefore, in practice, you rarely have to manually unload a controller view from memory when reporting a lack of memory. (And never in theory)
But why? If you carefully read programming books on iOS, then you know that UIView is a subclass of UIResponder (so that the presentation can interact with events) and has a pointer to an instance of its CALayer (so that the presentation can be drawn on the screen).
')
CALayer is a container for a
bitmap image. When a UIView is drawn in the drawInRect method: it creates a bitmap for its layer. The remaining variables of the layer (many are taken from the view, such as frame and backgroundColor) indicate how and where this image is on the screen.
But the main part of the layer (in terms of memory usage) is bitmap. The layer itself is 48 bytes, and the standard UIView is only 96 bytes, regardless of the screen size. In this case, the memory consumption for a layer depends on the size of the image bitmap on the screen. For example, for iPad Retina, a full-screen image can reach 12mb.
The approach used in iOS6 is that when there is a shortage of memory, the layer bitmap (layer) is unloaded from memory, and the UIView and CALayer objects are preserved intact. It is quite advisable, because the objects themselves, as mentioned above, occupy a fairly small amount of memory, and the bitmap can be created again using drawInRect.
So, what we get with this approach: the controller no longer has to fill out the view with data, after a warning about a lack of memory. For example, we have created a viewController with several text fields. When reporting a lack of memory, the controller would have to save the text in these fields and re-fill them when calling viewDidLoad or viewWillAppear :. This is no longer necessary, since the text fields will never be destroyed and will retain their text until the image is drawn again. This simplifies the part of the code in which many errors occur.
There are also some really cool pieces built into the layer drawing process. But first, let's check if we understand allocation (allocation) and deallocation of memory well. When memory is allocated (for an object, bitmap, it doesn't matter) the corresponding block size on the heap is marked as “used” and the pointer is returned to the beginning of this block. In the case of allocating memory for an object, we think of this pointer as an object, but in reality it’s just a pointer to a memory address.
When a memory block is “used” there is a protection mechanism preventing the use of this memory block not through the returned pointer. Therefore, with this memory is quite hard to screw up.
Deallocation simply removes this protection and marks the memory block as “not used.” This means that the next allocation of memory can be used all this block or part of it. When freeing the memory, the values ​​stored in this block do not change. While, it is still possible to access it despite the fact that it could be changed from another place. Therefore, it is never safe to access the memory through the pointer obtained during allocation.
Now about why it matters for views and their layers. Each layer has a contents property, which points to an object that stores a bitmap.
This is a private object, an instance of the CABackingStore class, which contains the actual bitmap, as well as some metadata (such as whether the image has an alpha channel and how many bytes per pixel are used). Thus, it is the CABackingStore that must be destroyed when the memory runs out.
However, the subtlety lies in the fact that when there is a shortage of memory, the CABackingStore (storage) is not destroyed. If the view is not active at the time of the warning about the lack of memory, then the storage of its layer is marked with the flag volatile. This flag, in this context, is just the same as freeing memory (deallocation) and giving access to its use for various purposes. The difference between the flag and the release of memory (deallocation) is that the "tagged" memory can actually be restored, it is not irretrievably lost.
Consider why this is a great optimization. If the view (more precisely, the layer) was destroyed storage (CABackingStore), the next time the view should recreate it, performing drawInRect :. This is a resource-intensive operation and should be avoided. Having the ability to restore your storage layer can avoid a new call to drawInRect :.
Of course, there is a possibility that between the moment when the repository was flagged and the moment when the presentation was required to show the memory was completely spent for other purposes. In this case, to create a bitmap call drawInRect: can not be avoided.