Observer model

The observer pattern is an object behavior pattern used to decouple communication between a series of classes that need to cooperate with each other. It defines a one-to-many dependency between objects. When an object’s state changes, all objects that depend on it are notified. The observer pattern is typically implemented in two steps: the consumer registers notification message listeners and the producer sends notification messages.

IOS provides several implementations of the observer mode: NSNotification and NSNotificationCenter are used to register and send notification messages in Cocoa Touch layer. In CoreFoundation layer, C functions of CFNotificationXXX series are provided to register and send notification messages. At the operating system level, libsystem_notify.dylib library provides a lower level notification message registration and sending mechanism based on C language.

This article focuses on the various interface functions provided in the libsystem_notify.dylib(hereafter referred to simply as the System notification library) library to implement notification message registration and notification message sending. Notification message registration and sending in system notification library is a kind of low-level notification mechanism which can be used to realize cross-process communication.

System notification library API

All functions in the notify.h library are declared in the notify.h file, so when you want to use the functions provided by the system notification library, you need to include #include

in your code. As with all other notification message-based implementations, each notification message is identified by a string, as is the notification message in the system notification library. In addition, each process registered to listen for a notification message also generates an in-process valid notification message identifier token. Tokens can be understood as a process’s unique representation of a listener’s notification message at run time. The system notification library provides four processing modes for notification messages: block-based processor, Message port based on Mach Port, signal-based processing and processor based on file operation.

Registration of notification messages

In order to support the above four message processing mechanisms, the system notification library provides four functions to register notification messages of various processing types:

Uint32_t notify_register_dispatch(const char *name, int *out_token, dispatch_queue_t queue // Uint32_t notify_register_signal(const char *name, int sig, int *out_token); Uint32_t notify_register_mach_port(const char *name, mach_port_t *notify_port, int flags, int *out_token); // Notification registration based on file descriptors. uint32_t notify_register_file_descriptor(const char *name, int *notify_fd, int flags, int *out_token);Copy the code

As you can see from the four functions above, the first argument to each function is the name of the notification message that we want to listen for, and each function has an out_token output that identifies the notification message that the process registered at run time. For block handlers, the specified block function is always called in a specified queue every time a notification is triggered. For signal, a specified signal is always sent to the system each time a monitored notification is triggered. For a Mach port, an empty Mach MSG message is always sent to the specified Mach port every time a listening notification is triggered. For file descriptors, specific content is always written to the specified file each time a listening notification is triggered.

The system notification library supports both iOS and macOS, and is a cross-process notification message. Typically, iOS uses notify_register_dispatch to listen for notifications and process them in blocks, while macOS uses all of these methods.

2. Sending notification messages

When a notification message is generated, it needs to be sent to all listeners. Notification messages are sent using the function notify_POST:

 uint32_t notify_post(const char *name);

Copy the code

The signature of the function is simple, and the input parameter is the notification message name. Notifications in the system notification function do not take any additional parameters.

Notice the suspension, resumption and cancellation of message listener

When a notification message is registered, the system returns a token value to identify the notification message. At the same time, the system also provides the suspension, recovery and cancellation of the notification message monitoring process:

// This token will temporarily not accept notification of messages. Uint32_t notify_SUSPEND (int token) // restore notification, set this token to restore notification of receiving messages. Uint32_t notify_resume(int token) // The uint32_t notify_resume(int token) uint32_t notify_cancel(int token);Copy the code

4. Notification message sending detection

Sometimes we don’t want to register a notification handler to handle notifications, but rather to check if a notification has already been sent. Two functions are provided to do this:

// Register a token for notification message detection. uint32_t notify_register_check(const char *name, int *out_token); // Check whether the notification message corresponding to this token has been sent. Check returns 1 if the notification message was sent, 0 otherwise. uint32_t notify_check(int token, int *check);Copy the code

5. Status of notification messages

For listeners of notification messages, we can bind a 64-bit status data to the returned token. We can get it and set it. This status data is primarily used to implement extended processing of notification listeners.

 uint32_t notify_set_state(int token, uint64_t state64)
 uint32_t notify_get_state(int token, uint64_t *state64)
Copy the code

6. Preset notification messages

The operating system layer supports some preset notification messages declared in the notify_keys.h header file. These preset messages are for directory services, for disk space and volume suspension, for network configuration changes, for logging notifications, and for system time zone and time changes. For each type of notification, see the instructions in the file. For example, the following example implements listening handling for insufficient disk space, network state changes, and system time adjustments:

#include <notify.h>
#include <notify_keys.h>

void foo() { int token1, token2, token3; // Register to listen for notifications of network state changes. notify_register_dispatch(kNotifySCNetworkChange, & token1, dispatch_get_main_queue(), ^(int token) { //... }); / / register to monitor system disk space is insufficient to inform notify_register_dispatch (kNotifyVFSLowDiskSpaceRootFS, & token2, dispatch_get_main_queue (), ^(int token) { //.... }); // Register to listen for notifications of system time changes. notify_register_dispatch(kNotifyClockSet, &token3, dispatch_get_main_queue(), ^(int token) { //... }); }Copy the code

Besides notify_keys. H file public notification messages, and some are not public notification messages, we can get more by the information has not been publicly about the state of the system changes, the following list will list all the systems at the bottom of the notification message, particular meaning each notification is the reader to guess and validation.

"com.apple.asl.remote"
"com.apple.system.timezone"
"com.apple.MCX._managementStatusChangedForDomains"
"com.apple.CFPreferences._domainsChangedExternally"
"com.apple.system.clock_set"
"com.apple.system.timezone"
"AppleNumberPreferencesChangedNotification"
"AppleTimePreferencesChangedNotification"
"AppleDatePreferencesChangedNotification"
"AppleLanguagePreferencesChangedNotification"
"AppleTextBehaviorPreferencesChangedNotification"
"com.apple.librarian.account-token-changed"
"com.apple.system.batterysavermode"
"com.apple.accessibility.cache.forcetouch.sensitivity.changed"
"com.apple.networkd.started"
"com.apple.neconfigurationchanged"
"com.apple.networkd.settings"
"com.apple.system.config.network_change"
"com.apple.CoreAnimation.CAWindowServer.DisplayChanged"
"com.apple.networkd.proxy_count"
"com.apple.iohideventsystem.available"
"com.apple.backboardd.rawOrientation"
"com.apple.springboard.hasBlankedScreen"
"UIBacklightLevelChangedNotification"
"com.apple.accessibility.wob.status"
"com.apple.backboardd.videosettingschanged"
"com.apple.mobile.keybagd.user_changed"
"com.apple.LaunchServices.database"
"com.apple.accessibility.cache.enhance.text.legibility"
"com.apple.frontboard.systemappservices.serverNotifyToken"
"com.apple.frontboard.workspace.serverNotifyToken"
"com.apple.accessibility.cache.captioning"
"com.apple.accessibility.cache.vot"
"com.apple.accessibility.cache.ax"
"com.apple.accessibility.cache.app.ax"
"com.apple.accessibility.status"
"com.apple.language.changed"
"com.apple.springboard.showingAlertItem"
"com.apple.mobile.keybagd.lock_status"
"NameLayerTree"
"ApplePreferredContentSizeCategoryChangedNotification"
"kKeepAppsUpToDateEnabledChangedNotification"
"com.apple.accessibility.cache.reduce.motion"
"UIKeyboardSpringBoardKeyboardShow"
"UIKeyboardSpringBoardKeyboardHide"
"com.apple.locationd.registration"
"kCTDaemonReadyNotification"
"com.apple.system.config.network_change"
"com.apple.system.timezone./var/db/timezone/zoneinfo/UTC"
"com.apple.system.info:/etc/hosts"
"com.apple.MSVLoggingConfigurationDidChange"
"com.apple.managedconfiguration.defaultsdidchange"
"com.apple.AppSupport.loggingDefaultsChanged"
"com.apple.mobileipod.MPMusicPlayerController.launched"
"com.apple.networkd.nat64.ifstate"
"com.apple.ManagedConfiguration.profileListChanged"
"com.apple.backboardd.unambiguousOrientation"
"com.apple.accessibility.cache.button.shapes.enabled"
"com.apple.accessibility.cache.use.single.system.color.enabled"
"com.apple.accessibility.cache.darken.system.colors.enabled"
"com.apple.coreui.statistics"
"com.apple.UIKit.UIScreenEdgeGestureMode"
"com.apple.managedconfiguration.restrictionchanged"
"com.apple.managedconfiguration.passcodechanged"
"PINPolicyChangedNotification"
"com.apple.managedconfiguration.settingschanged"
"com.apple.managedconfiguration.effectivesettingschanged"
"com.apple.managedconfiguration.appwhitelistdidchange"
"com.apple.managedconfiguration.defaultsdidchange"
"com.apple.managedconfiguration.keyboardsettingschanged"
"com.apple.managedconfiguration.clientrestrictionschanged"
"com.apple.managedconfiguration.webFilterUIActiveDidChange"
"com.apple.ManagedConfiguration.managedAppsChanged"
"MCManagedBooksChanged"
"com.apple.managedconfiguration.allowpasscodemodificationchanged"
"com.apple.mediaserverd.up"
"com.apple.hangtracer.prefchangednotification"
"com.apple.accessibility.cache.enhance.background.contrast"
"com.apple.system.thermalpressurelevel"
"com.apple.backboardd.backlight.changed"
"com.apple.accessibility.QuickSpeakEnabled"
"com.apple.accessibility.cache.quick.speak"
"com.apple.powerlog.state_changed"
"com.apple.powerlog.clientPermissionState"

Copy the code

Welcome to ouyang Big Brother 2013Making the address