NSNotificationCenter and Low-Memory Warnings

When the system is running low on RAM, it issues a low memory warning to the running application. The application responds by freeing up any resources that it does not need at the moment and can easily recreate. View controllers, during a low memory warning, are sent the message didReceiveMemoryWarning.

Objects other than view controllers may have data that they are not using and can recreate later. The BNRImageStore is such an object – when a low-memory warning occurs, it can release its ownership of the images by emptying its dictionary. Then if another object ever asks for a specific image again, that image can be loaded into memory from the filesystem.

In order to have objects that are not view controllers respond to low memory warnings, you must use the notification center. Every application has an instance of NSNotificationCenter, which works like a smart bulletin board. An object can register as an observer (Send me lost dog notifications). When another object posts a notification (I lost my dog), the notification center forwards the notification to the registered observers.

Whenever a low-memory warning occurs, UIApplicationDidReceiveMemoryWarningNotification is posted to the notification center. Objects that want to implement their own low-memory warning handlers can register for this notification.

In BNRImageStore.m, edit the initPrivate method to register the image store as an observer of this notification.

-​ ​(​i​n​s​t​a​n​c​e​t​y​p​e​)​i​n​i​t​P​r​i​v​a​t​e​
{​
 ​ ​ ​ ​s​e​l​f​ ​=​ ​[​s​u​p​e​r​ ​i​n​i​t​]​;​
 ​ ​ ​ ​i​f​ ​(​s​e​l​f​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​_​d​i​c​t​i​o​n​a​r​y​ ​=​ ​[​[​N​S​M​u​t​a​b​l​e​D​i​c​t​i​o​n​a​r​y​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​N​o​t​i​f​i​c​a​t​i​o​n​C​e​n​t​e​r​ ​*​n​c​ ​=​ ​[​N​S​N​o​t​i​f​i​c​a​t​i​o​n​C​e​n​t​e​r​ ​d​e​f​a​u​l​t​C​e​n​t​e​r​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​[​n​c​ ​a​d​d​O​b​s​e​r​v​e​r​:​s​e​l​f​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​s​e​l​e​c​t​o​r​:​@​s​e​l​e​c​t​o​r​(​c​l​e​a​r​C​a​c​h​e​:​)​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​n​a​m​e​:​U​I​A​p​p​l​i​c​a​t​i​o​n​D​i​d​R​e​c​e​i​v​e​M​e​m​o​r​y​W​a​r​n​i​n​g​N​o​t​i​f​i​c​a​t​i​o​n​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​o​b​j​e​c​t​:​n​i​l​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​
 ​ ​ ​ ​}​

 ​ ​ ​ ​r​e​t​u​r​n​ ​s​e​l​f​;​
}​

Now your image store is registered as an observer with the notification center (Figure 18.8).

Figure 18.8  Registered as an observer with notification center

Registered as an observer with notification center

Now, when a low-memory warning is posted, the notification center will send the message clearCache: to the BNRImageStore instance (Figure 18.9).

Figure 18.9  Receiving the notification

Receiving the notification

In BNRImageStore.m, implement clearCache: to remove all the instances of UIImage from the BNRImageStore’s dictionary.

-​ ​(​v​o​i​d​)​c​l​e​a​r​C​a​c​h​e​:​(​N​S​N​o​t​i​f​i​c​a​t​i​o​n​ ​*​)​n​o​t​e​
{​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​f​l​u​s​h​i​n​g​ ​%​d​ ​i​m​a​g​e​s​ ​o​u​t​ ​o​f​ ​t​h​e​ ​c​a​c​h​e​"​,​ ​[​s​e​l​f​.​d​i​c​t​i​o​n​a​r​y​ ​c​o​u​n​t​]​)​;​
 ​ ​ ​ ​[​s​e​l​f​.​d​i​c​t​i​o​n​a​r​y​ ​r​e​m​o​v​e​A​l​l​O​b​j​e​c​t​s​]​;​
}​

Removing an object from a dictionary relinquishes ownership of the object, so flushing the cache causes all of the images to lose an owner. Images that are not being used by other objects are destroyed, and when they are needed again, they will be reloaded from the filesystem. If an image is currently displayed in the BNRDetailViewController’s imageView, then it will not be destroyed since it is owned by the imageView. When the BNRDetailViewController’s imageView loses ownership of that image (either because the BNRDetailViewController was popped off the stack or a new image was chosen), then it is destroyed. It will be reloaded later if needed.

Build and run the app in the simulator. Create or load in some images. Then select Simulate Memory Warning in the Hardware menu. You should see a log statement indicating that the cache has been flushed out.

More on NSNotificationCenter

Notifications are another form of callbacks, like delegation and target-action pairs. However, unlike delegation and target-action pairs, which require that the object responsible for an event send a message directly to its delegate or targets, notifications use a middle-man: the NSNotificationCenter.

Notifications in Objective-C are represented by instances of NSNotification. Each NSNotification has a name (used by the notification center to find observers), an object (the object that is responsible for posting the notification), and an optional user info dictionary that contains additional information that the poster wants observers to know about. For example, if for some reason the status bar’s frame changes, UIApplication posts a UIApplicationDidChangeStatusBarFrameNotification with a user info dictionary. In the dictionary is the new frame of the status bar. If you received the notification, you could get the frame like this:

-​ ​(​v​o​i​d​)​s​t​a​t​u​s​B​a​r​M​o​v​e​d​O​r​R​e​s​i​z​e​d​:​(​N​S​N​o​t​i​f​i​c​a​t​i​o​n​ ​*​)​n​o​t​e​
{​
 ​ ​ ​ ​N​S​D​i​c​t​i​o​n​a​r​y​ ​*​u​s​e​r​I​n​f​o​ ​=​ ​[​n​o​t​e​ ​u​s​e​r​I​n​f​o​]​;​
 ​ ​ ​ ​N​S​V​a​l​u​e​ ​*​w​r​a​p​p​e​d​R​e​c​t​ ​=​ ​u​s​e​r​I​n​f​o​[​U​I​A​p​p​l​i​c​a​t​i​o​n​S​t​a​t​u​s​B​a​r​F​r​a​m​e​U​s​e​r​I​n​f​o​K​e​y​]​;​
 ​ ​ ​ ​C​G​R​e​c​t​ ​n​e​w​F​r​a​m​e​ ​=​ ​[​w​r​a​p​p​e​d​R​e​c​t​ ​C​G​R​e​c​t​V​a​l​u​e​]​;​

 ​ ​ ​ ​.​.​.​u​s​e​ ​f​r​a​m​e​ ​h​e​r​e​.​.​.​

}​

Notice that the CGRect had to be wrapped in an NSValue because only objects can go into dictionaries.

How can you know what is in the userInfo dictionary? Each notification is documented in the class reference. Most say This notification does not contain a userInfo dictionary. For notifications with userInfo dictionaries, all the keys and what they map to will be listed.

The last argument of addObserver:selector:name:object: is typically nil – which means, no matter what object posted a Fire! notification, the observer will get sent its message. You can specify a pointer to an object for this argument and the observer will only get notified if that object posts the notification it has registered for, while ignoring any other object that posts the same notification.

One purpose of the notification center is to allow multiple objects to register a callback for the same event. Any number of objects can register as an observer for the same notification name. When the notification occurs, all of those objects are sent the message they registered with (in no particular order). Thus, notifications are a good solution when more than one object is interested in an event. For example, many objects might want to know about a rotation event, so Apple used notifications for that.

One final point: the NSNotificationCenter has nothing to do with inter-app communication, push notifications, or local notifications. It is simply for communication between objects in a single application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset