{"id":3038,"url":"https://github.com/eBardX/XestiMonitors","last_synced_at":"2025-08-06T16:32:33.208Z","repository":{"id":56928774,"uuid":"75018970","full_name":"eBardX/XestiMonitors","owner":"eBardX","description":"An extensible monitoring framework written in Swift","archived":false,"fork":false,"pushed_at":"2022-07-06T20:09:52.000Z","size":19840,"stargazers_count":272,"open_issues_count":2,"forks_count":16,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-11-10T15:52:24.305Z","etag":null,"topics":["cocoapod","extensible","framework","ios","macos","monitoring","swift","tvos","watchos"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eBardX.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-28T22:14:38.000Z","updated_at":"2024-05-31T08:16:35.000Z","dependencies_parsed_at":"2022-08-20T23:20:10.295Z","dependency_job_id":null,"html_url":"https://github.com/eBardX/XestiMonitors","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eBardX%2FXestiMonitors","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eBardX%2FXestiMonitors/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eBardX%2FXestiMonitors/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eBardX%2FXestiMonitors/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eBardX","download_url":"https://codeload.github.com/eBardX/XestiMonitors/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228923764,"owners_count":17992574,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cocoapod","extensible","framework","ios","macos","monitoring","swift","tvos","watchos"],"created_at":"2024-01-05T20:16:29.644Z","updated_at":"2024-12-09T16:31:22.629Z","avatar_url":"https://github.com/eBardX.png","language":"Swift","funding_links":[],"categories":["Utility","Libs","Swift","Utilities and Extensions","Utility [🔝](#readme)"],"sub_categories":["Web View","Utility","Other free courses"],"readme":"# XestiMonitors\n\n[![Swift 4.x](https://img.shields.io/badge/Swift-4.x-orange.svg)](https://developer.apple.com/swift/)\n[![License](https://img.shields.io/cocoapods/l/XestiMonitors.svg)](http://cocoapods.org/pods/XestiMonitors)\n[![Platform](https://img.shields.io/cocoapods/p/XestiMonitors.svg)](http://cocoapods.org/pods/XestiMonitors)\n\n[![Build Status](https://img.shields.io/travis/eBardX/XestiMonitors/master.svg?colorB=4BC51D)](https://travis-ci.org/eBardX/XestiMonitors)\n[![Code Coverage](https://img.shields.io/codecov/c/github/eBardX/XestiMonitors/master.svg?colorB=4BC51D)](https://codecov.io/github/eBardX/XestiMonitors)\n[![Documented](https://img.shields.io/cocoapods/metrics/doc-percent/XestiMonitors.svg?colorB=4BC51D)](http://ebardx.github.io/XestiMonitors/)\n\n[![CocoaPods](https://img.shields.io/cocoapods/v/XestiMonitors.svg?colorB=4BC51D)](http://cocoapods.org/pods/XestiMonitors)\n[![Carthage](https://img.shields.io/badge/carthage-compatible-brightgreen.svg)](https://github.com/Carthage/Carthage)\n[![Swift Package Manager](https://img.shields.io/badge/spm-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)\n\n* [Overview](#overview)\n* [Reference Documentation](#reference_documentation)\n* [Requirements](#requirements)\n* [Installation](#installation)\n    * [CocoaPods](#cocoapods_installation)\n    * [Carthage](#carthage_installation)\n    * [Swift Package Manager](#spm_installation)\n* [Usage](#usage)\n    * [Core Location Monitors](#core_location_monitors)\n    * [Core Motion Monitors](#core_motion_monitors)\n    * [Foundation Monitors](#foundation_monitors)\n    * [UIKit Monitors](#uikit_monitors)\n        * [Accessibility Monitors](#accessibility_monitors)\n        * [Application Monitors](#application_monitors)\n        * [Device Monitors](#device_monitors)\n        * [Screen Monitors](#screen_monitors)\n        * [Text Monitors](#text_monitors)\n        * [Other UIKit Monitors](#other_uikit_monitors)\n    * [Other Monitors](#other_monitors)\n    * [Custom Monitors](#custom_monitors)\n* [Credits](#credits)\n* [License](#license)\n\n## \u003ca name=\"overview\"\u003eOverview\u003c/a\u003e\n\nThe XestiMonitors framework provides more than *sixty* fully-functional monitor\nclasses right out of the box that make it easy for your app to detect and\nrespond to many common system-generated events.\n\nAmong other things, you can think of XestiMonitors as a better way to manage\nthe most common notifications (primarily on iOS and tvOS). At present,\nXestiMonitors provides “wrappers” around nearly all `UIKit` notifications (see\n[UIKit Monitors](#uikit_monitors)) and many `Foundation` notifications (see\n[Foundation Monitors](#foundation_monitors)).\n\nXestiMonitors also provides convenient “wrappers” around several frameworks and\nprogramming interfaces to make them easier for your app to use:\n\n* It wraps the Core Location framework to make it easier for your app to make\n  easier for your app to determine the device’s geographic location, altitude,\n  or orientation; or its position relative to a nearby iBeacon. See\n  [Core Location Monitors](#core_location_monitors) for details.\n* It wraps the Core Motion framework to make it easier for your app to obtain\n  both raw and processed motion measurements from the device. See\n  [Core Motion Monitors](#core_motion_monitors) for details.\n* It wraps the `SCNetworkReachability` programming interface to make it super\n  easy for your app to determine the reachability of a target host. See\n  [Other Monitors](#other_monitors) for details.\n\nAdditional monitors targeting more parts of all four platforms will be rolled\nout in future releases of XestiMonitors!\n\nFinally, XestiMonitors is *extensible*—you can easily create your own *custom*\nmonitors. See [Custom Monitors](#custom_monitors) for details.\n\n## \u003ca name=\"reference_documentation\"\u003eReference Documentation\u003c/a\u003e\n\nFull [reference documentation][refdoc] is available courtesy of [Jazzy][jazzy].\n\n## \u003ca name=\"requirements\"\u003eRequirements\u003c/a\u003e\n\n* iOS 9.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+\n* Xcode 9.0+\n* Swift 4.0+\n\n## \u003ca name=\"installation\"\u003eInstallation\u003c/a\u003e\n\n### \u003ca name=\"cocoapods_installation\"\u003eCocoaPods\u003c/a\u003e\n\n[CocoaPods][cocoapods] is a dependency manager for Cocoa projects. You can\ninstall it with the following command:\n\n```\n$ gem install cocoapods\n```\n\nTo integrate XestiMonitors into your Xcode project using CocoaPods, specify it\nin your `Podfile`:\n\n```\nsource 'https://github.com/CocoaPods/Specs.git'\nplatform :ios, '9.0'\nuse_frameworks!\n\ntarget '\u003cYour Target Name\u003e' do\n    pod 'XestiMonitors'\nend\n```\n\nThen, run the following command:\n\n```\n$ pod install\n```\n\n### \u003ca name=\"carthage_installation\"\u003eCarthage\u003c/a\u003e\n\n[Carthage][carthage] is a decentralized dependency manager that builds your\ndependencies and provides you with binary frameworks.\n\nYou can install Carthage with [Homebrew][homebrew] using the following commands:\n\n```\n$ brew update\n$ brew install carthage\n```\n\nTo integrate XestiMonitors into your Xcode project using Carthage, specify it\nin your `Cartfile`:\n\n```\ngithub \"eBardX/XestiMonitors\"\n```\n\nThen, run the following command:\n\n```\n$ carthage update\n```\n\nFinally, drag the built `XestiMonitors.framework` into your Xcode project.\n\n### \u003ca name=\"spm_installation\"\u003eSwift Package Manager\u003c/a\u003e\n\nThe [Swift Package Manager][spm] is a tool for automating the distribution of\nSwift code and is integrated into the swift compiler. It is in early\ndevelopment, but XestiMonitors does support its use on supported platforms.\n\nOnce you have your Swift package set up, adding XestiMonitors as a dependency\nis as easy as adding it to the `dependencies` value of your `Package.swift`.\n\n```\ndependencies: [\n    .Package(url: \"https://github.com/eBardX/XestiMonitors.git\")\n]\n```\n\n## \u003ca name=\"usage\"\u003eUsage\u003c/a\u003e\n\nAll monitor classes conform to the [Monitor][p_monitor] protocol, thus\nenabling you to create arrays of monitors that can be started or\nstopped uniformly—fewer lines of code!\n\nFor example, in a view controller, you can lazily instantiate several\nmonitors and, in addition, lazily instantiate an array variable containing\nthese monitors:\n\n```\nimport XestiMonitors\n\nlazy var keyboardMonitor = KeyboardMonitor { [unowned self] in\n    // do something…\n}\nlazy var memoryMonitor = MemoryMonitor { [unowned self] in\n    // do something…\n}\nlazy var orientationMonitor = OrientationMonitor { [unowned self] in\n    // do something…\n}\nlazy var monitors: [Monitor] = [keyboardMonitor,\n                                memoryMonitor,\n                                orientationMonitor]\n```\n\nThen, in the `viewWillAppear(_:)` and `viewWillDisappear(_:)` methods, you can\nsimply start or stop all these monitors with a single line of code:\n\n```\noverride func viewWillAppear(_ animated: Bool) {\n    super.viewWillAppear(animated)\n    monitors.forEach { $0.startMonitoring() }\n}\n\noverride func viewWillDisappear(_ animated: Bool) {\n    monitors.forEach { $0.stopMonitoring() }\n    super.viewWillDisappear(animated)\n}\n```\n\nEasy peasy!\n\n### \u003ca name=\"core_location_monitors\"\u003eCore Location Monitors\u003c/a\u003e\n\nXestiMonitors provides seven monitor classes wrapping the Core Location\nframework that you can use to determine the device’s geographic location,\naltitude, or orientation; or its position relative to a nearby iBeacon:\n\n* [BeaconRangingMonitor][beacon_ranging_monitor] to monitor a region for\n  changes to the ranges (*i.e.,* the relative proximity) to the Bluetooth\n  low-energy beacons within. *(iOS)*\n* [HeadingMonitor][heading_monitor] to monitor the device for changes to its\n  current heading. *(iOS)*\n* [LocationAuthorizationMonitor][location_authorization_monitor] to monitor the\n  app for updates to its authorization to use location services. *(iOS, macOS,\n  tvOS, watchOS)*\n* [RegionMonitor][region_monitor] to monitor a region for changes to its state\n  (which indicate boundary transitions). *(iOS, macOS)*\n* [SignificantLocationMonitor][significant_location_monitor] to monitor the\n  device for *significant* changes to its current location. *(iOS, macOS)*\n* [StandardLocationMonitor][standard_location_monitor] to monitor the device\n  for changes to its current location. *(iOS, macOS, tvOS, watchOS)*\n* [VisitMonitor][visit_monitor] to monitor for locations that the user stops at\n  for a “noteworthy” amount of time. *(iOS)*\n\n### \u003ca name=\"core_motion_monitors\"\u003eCore Motion Monitors\u003c/a\u003e\n\nXestiMonitors provides seven monitor classes wrapping the Core Motion framework\nthat you can use to obtain raw and processed motion measurements from the\ndevice:\n\n* [AccelerometerMonitor][accelerometer_monitor] to monitor the device’s\n  accelerometer for periodic raw measurements of the acceleration along the\n  three spatial axes. *(iOS, watchOS)*\n* [AltimeterMonitor][altimeter_monitor] to monitor the device for changes in\n  relative altitude. *(iOS, watchOS)*\n* [DeviceMotionMonitor][device_motion_monitor] to monitor the device’s\n  accelerometer, gyroscope, and magnetometer for periodic raw measurements\n  which are processed into device motion measurements. *(iOS, watchOS)*\n* [GyroscopeMonitor][gyroscope_monitor] to monitor the device’s gyroscope for\n  periodic raw measurements of the rotation rate around the three spatial axes.\n  *(iOS, watchOS)*\n* [MagnetometerMonitor][magnetometer_monitor] to monitor the device’s\n  magnetometer for periodic raw measurements of the magnetic field around the\n  three spatial axes. *(iOS, watchOS)*\n* [MotionActivityMonitor][motion_activity_monitor] to monitor the device for\n  live and historic motion data. *(iOS, watchOS)*\n* [PedometerMonitor][pedometer_monitor] to monitor the device for live and\n  historic walking data. *(iOS, watchOS)*\n\n### \u003ca name=\"foundation_monitors\"\u003eFoundation Monitors\u003c/a\u003e\n\nXestiMonitors provides seventeen monitors wrapping\n[`Foundation` notifications][wrapped_foundation_notifications]:\n\n* [BundleClassLoadMonitor][bundle_class_load_monitor] to monitor a bundle for\n  dynamic loads of classes. *(iOS, macOS, tvOS, watchOS)*\n* [BundleResourceRequestMonitor][bundle_resource_request_monitor] to monitor\n  the system to detect if the amount of available disk space for on-demand\n  resources is getting low. *(iOS, tvOS, watchOS)*\n* [CalendarDayMonitor][calendar_day_monitor] to monitor the system for changes\n  to the calendar day. *(iOS, macOS, tvOS, watchOS)*\n* [CurrentLocaleMonitor][current_locale_monitor] to monitor the system for\n  changes to the user’s locale. *(iOS, macOS, tvOS, watchOS)*\n* [ExtensionHostMonitor][extension_host_monitor] to monitor an extension\n  context for changes to the runtime state of the extension’s host app.\n  *(iOS, tvOS, watchOS)*\n* [HTTPCookiesStorageMonitor][http_cookies_storage_monitor] instance to monitor\n  an HTTP cookie storage object for changes to its acceptance policy or to its\n  cookies. *(iOS, macOS, tvOS, watchOS)*\n* [MetadataQueryMonitor][metadata_query_monitor] to monitor a metadata query\n  for changes to its results. *(iOS, macOS, tvOS, watchOS)*\n* [PortMonitor][port_monitor] to monitor a port for changes to its validity.\n  *(iOS, macOS, tvOS, watchOS)*\n* [ProcessInfoPowerStateMonitor][process_info_power_state_monitor] to monitor\n  the device for changes to its power state (Low Power Mode is enabled or\n  disabled). *(iOS, tvOS, watchOS)*\n* [ProcessInfoThermalStateMonitor][process_info_thermal_state_monitor] to\n  monitor the system for changes to the thermal state.\n  *(iOS, macOS, tvOS, watchOS)*\n* [SystemClockMonitor][system_clock_monitor] to monitor the system for changes\n  to the clock. *(iOS, macOS, tvOS, watchOS)*\n* [SystemTimeZoneMonitor][system_time_zone_monitor] to monitor the system for\n  changes to the currently used time zone. *(iOS, macOS, tvOS, watchOS)*\n* [UbiquitousKeyValueStoreMonitor][ubiquitous_key_value_store_monitor] to\n  monitor the iCloud (“ubiquitous”) key-value store for changes due to incoming\n  data pushed from iCloud. *(iOS, macOS, tvOS)*\n* [UbiquityIdentityMonitor][ubiquity_identity_monitor] to monitor the system\n  for changes to the iCloud (”ubiquity”) identity. *(iOS, macOS, tvOS, watchOS)*\n* [UndoManagerMonitor][undo_manager_monitor] to monitor an undo manager for\n  changes to its recording of operations. *(iOS, macOS, tvOS, watchOS)*\n* [URLCredentialStorageMonitor][url_credential_storage_monitor] to monitor the\n  shared URL credential storage object for changes to its stored credentials.\n  *(iOS, macOS, tvOS, watchOS)*\n* [UserDefaultsMonitor][user_defaults_monitor] to monitor a user defaults\n  object for changes to its data. *(iOS, macOS, tvOS, watchOS)*\n\n### \u003ca name=\"uikit_monitors\"\u003eUIKit Monitors\u003c/a\u003e\n\nXestiMonitors provides numerous monitors wrapping\n[`UIKit` notifications][wrapped_uikit_notifications].\n\n#### \u003ca name=\"accessibility_monitors\"\u003eAccessibility Monitors\u003c/a\u003e\n\nXestiMonitors provides three monitor classes that you can use to observe\naccessibility events generated by the system:\n\n* [AccessibilityAnnouncementMonitor][accessibility_announcement_monitor] to\n  monitor the system for accessibility announcements that VoiceOver has\n  finished outputting. *(iOS, tvOS)*\n* [AccessibilityElementMonitor][accessibility_element_monitor] to monitor the\n  system for changes to element focus by an assistive technology. *(iOS, tvOS)*\n* [AccessibilityStatusMonitor][accessibility_status_monitor] to monitor the\n  system for changes to the status of various accessibility settings.\n  *(iOS, tvOS)*\n\n#### \u003ca name=\"application_monitors\"\u003eApplication Monitors \u003c/a\u003e\n\nXestiMonitors provides seven monitor classes that you can use to observe common\nevents generated by the system about the app:\n\n* [ApplicationStateMonitor][application_state_monitor] to monitor the app for\n  changes to its runtime state. *(iOS, tvOS)*\n* [BackgroundRefreshMonitor][background_refresh_monitor] to monitor the app for\n  changes to its status for downloading content in the background. *(iOS)*\n* [MemoryMonitor][memory_monitor] to monitor the app for memory warnings from\n  the operating system. *(iOS, tvOS)*\n* [ProtectedDataMonitor][protected_data_monitor] to monitor the app for changes\n  to the accessibility of protected files. *(iOS, tvOS)*\n* [ScreenshotMonitor][screenshot_monitor] to monitor the app for screenshots.\n  *(iOS, tvOS)*\n* [StatusBarMonitor][status_bar_monitor] to monitor the app for changes to the\n  orientation of its user interface or to the frame of the status bar. *(iOS)*\n* [TimeMonitor][time_monitor] to monitor the app for significant changes in\n  time. *(iOS, tvOS)*\n\n#### \u003ca name=\"device_monitors\"\u003eDevice Monitors\u003c/a\u003e\n\nXestiMonitors provides three monitor classes that you can use to detect changes\nin the characteristics of the device:\n\n* [BatteryMonitor][battery_monitor] to monitor the device for changes to the\n  charge state and charge level of its battery. *(iOS)*\n* [OrientationMonitor][orientation_monitor] to monitor the device for changes\n  to its physical orientation. *(iOS)*\n* [ProximityMonitor][proximity_monitor] to monitor the device for changes to\n  the state of its proximity sensor. *(iOS)*\n\n#### \u003ca name=\"screen_monitors\"\u003eScreen Monitors\u003c/a\u003e\n\nXestiMonitors provides four monitor classes that you can use to detect changes\nin the properties associated with a screen:\n\n* [ScreenBrightnessMonitor][screen_brightness_monitor] to monitor a screen for\n  changes to its brightness level. *(iOS, tvOS)*\n* [ScreenCapturedMonitor][screen_captured_monitor] to monitor a screen for\n  changes to its captured status. *(iOS, tvOS)*\n* [ScreenConnectionMonitor][screen_connection_Monitor] to monitor the device\n  for screen connections and disconnections. *(iOS, tvOS)*\n* [ScreenModeMonitor][screen_mode_monitor] to monitor a screen for changes to\n  its current mode. *(iOS, tvOS)*\n\n#### \u003ca name=\"text_monitors\"\u003eText Monitors\u003c/a\u003e\n\nXestiMonitors provides four monitor classes that you can use to detect changes\nin text input mode and content:\n\n* [TextFieldTextMonitor][text_field_text_monitor] to monitor a text field for\n  changes to its text. *(iOS, tvOS)*\n* [TextInputModeMonitor][text_input_mode_monitor] to monitor the responder\n  chain for changes to the current input mode. *(iOS, tvOS)*\n* [TextStorageMonitor][text_storage_monitor] to monitor a text storage for the\n  processing of edits to its contents. *(iOS, tvOS)*\n* [TextViewTextMonitor][text_view_text_monitor] to monitor a text view for\n  changes to its text. *(iOS, tvOS)*\n\n#### \u003ca name=\"other_uikit_monitors\"\u003eOther UIKit Monitors\u003c/a\u003e\n\nIn addition, XestiMonitors provides nine other `UIKit` monitors:\n\n* [ContentSizeCategoryMonitor][content_size_category_monitor] to monitor the\n  app for changes to its preferred content size category. *(iOS, tvOS)*\n* [DocumentStateMonitor][document_state_monitor] to monitor a document for\n  changes to its state. *(iOS)*\n* [FocusMonitor][focus_monitor] to monitor the app for changes to the current\n  focus in the view hierarchy. *(iOS, tvOS)*\n* [KeyboardMonitor][keyboard_monitor] to monitor the keyboard for changes to\n  its visibility or to its frame. *(iOS)*\n* [MenuControllerMonitor][menu_controller_monitor] to monitor the menu\n  controller for changes to the visibility of the editing menu or to the frame\n  of the editing menu. *(iOS)*\n* [PasteboardMonitor][pasteboard_monitor] to monitor a pasteboard for changes\n  to its contents or for its removal from the app. *(iOS)*\n* [TableViewSelectionMonitor][table_view_selection_monitor] to monitor a table\n  view for changes to its selected row. *(iOS, tvOS)*\n* [ViewControllerShowDetailTargetMonitor][view_controller_show_detail_target_monitor]\n  to monitor the app for changes to a split view controller’s display mode in\n  the view hierarchy. *(iOS, tvOS)*\n* [WindowMonitor][window_monitor] to monitor a window for changes to its\n  visibility or key status. *(iOS, tvOS)*\n\n[KeyboardMonitor][keyboard_monitor] is especially handy in removing lots of\nboilerplate code from your app. This is how keyboard monitoring is typically\nhandled in a custom view controller:\n\n```\nfunc keyboardWillHide(_ notification: Notification) {\n    let userInfo = notification.userInfo\n    var animationDuration: TimeInterval = 0\n    if let value = (userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue {\n        animationDuration = value\n    }\n    constraint.constant = 0\n    UIView.animate(withDuration: animationDuration) {\n        self.view.layoutIfNeeded()\n    }\n}\n\nfunc keyboardWillShow(_ notification: Notification) {\n    let userInfo = notification.userInfo\n    var animationDuration: TimeInterval = 0\n    if let value = (userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue {\n        animationDuration = value\n    }\n    var frameEnd = CGRect.zero\n    if let value = (userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {\n        frameEnd = value\n    }\n    constraint.constant = frameEnd.height\n    UIView.animate(withDuration: animationDuration) {\n        self.view.layoutIfNeeded()\n    }\n}\n\noverride func viewWillAppear(_ animated: Bool) {\n    super.viewWillAppear(animated)\n    let nc = NotificationCenter.`default`\n    nc.addObserver(self, selector: #selector(keyboardWillHide(_:)),\n                   name: .UIKeyboardWillHide, object: nil)\n    nc.addObserver(self, selector: #selector(keyboardWillShow(_:)),\n                   name: .UIKeyboardWillShow, object: nil)\n}\n\noverride func viewWillDisappear(_ animated: Bool) {\n    NotificationCenter.`default`.removeObserver(self)\n    super.viewWillDisappear(animated)\n}\n```\n\nAnd this is the XestiMonitors way using [KeyboardMonitor][keyboard_monitor]:\n\n```\nimport XestiMonitors\n\nlazy var keyboardMonitor = KeyboardMonitor { [unowned self] event in\n    guard let constraint = self?.constraint,\n          let view = self?.view else { return }\n    switch event {\n    case let .willHide(info):\n        constraint.constant = 0\n        UIView.animate(withDuration: info.animationDuration) {\n            view.layoutIfNeeded()\n        }\n    case let .willShow(info):\n        constraint.constant = info.frameEnd.height\n        UIView.animate(withDuration: info.animationDuration) {\n            view.layoutIfNeeded()\n        }\n    default:\n        break\n    }\n}\n\noverride func viewWillAppear(_ animated: Bool) {\n    super.viewWillAppear(animated)\n    keyboardMonitor.startMonitoring()\n}\n\noverride func viewWillDisappear(_ animated: Bool) {\n    keyboardMonitor.stopMonitoring()\n    super.viewWillDisappear(animated)\n}\n```\n\nWhat’s in *your* wallet?\n\n### \u003ca name=\"other_monitors\"\u003eOther Monitors\u003c/a\u003e\n\nIn addition, XestiMonitors provides two other monitors:\n\n* [FileSystemObjectMonitor][file_system_object_monitor] to monitor a\n  file-system object for changes. *(iOS, macOS, tvOS, watchOS)*\n* [NetworkReachabilityMonitor][network_reachability_monitor] to monitor a\n  network node name or address for changes to its reachability.\n  *(iOS, macOS, tvOS)*\n\n### \u003ca name=\"custom_monitors\"\u003eCustom Monitors\u003c/a\u003e\n\nBest of all, the XestiMonitors framework provides several ways to create your\nown custom monitors quite easily.\n\n#### Implementing the Monitor Protocol\n\nYou can create a new class, or extend an existing class, that conforms to the\n[Monitor][p_monitor] protocol. You need only implement the\n[startMonitoring()][m_start_monitoring] and\n[stopMonitoring()][m_stop_monitoring] methods, as well as the\n[isMonitoring][m_is_monitoring] property:\n\n```\nimport XestiMonitors\n\nextension MegaHoobieWatcher: Monitor {\n    var isMonitoring: Bool { return watchingForHoobiesCount() \u003e 0 }\n\n    func startMonitoring() -\u003e Bool {\n        guard !isMonitoring else { return }\n        beginWatchingForHoobies()\n    }\n\n    func stopMonitoring() -\u003e Bool {\n        guard isMonitoring else { return }\n        endWatchingForHoobies()\n    }\n}\n```\n\n**Note:** The guard statements in both [startMonitoring()][m_start_monitoring]\nand [stopMonitoring()][m_stop_monitoring] protect against starting or stopping\nthe monitor if it is in the incorrect state. This is considered good coding\npractice.\n\n#### Subclassing the BaseMonitor Class\n\nTypically, you will want to create a subclass of [BaseMonitor][base_monitor].\nThe advantage of using this abstract base class is that the basic guard logic\nis taken care of for you. Specifically, the\n[startMonitoring()][bm_start_monitoring] method does not attempt to start the\nmonitor if it is already active, and the [stopMonitoring()][bm_stop_monitoring]\nmethod does not attempt to stop the monitor if it is *not* active. Instead of\ndirectly implementing the required protocol methods and properties, you need\nonly override the [configureMonitor()][bm_configureMonitor] and\n[cleanupMonitor()][bm_cleanupMonitor] methods of this base class. In fact, you\nwill *not* be able to override the [startMonitoring()][bm_start_monitoring] and\n[stopMonitoring()][bm_stop_monitoring] methods or the\n[isMonitoring][bm_is_monitoring] property—they are declared `final` in\n[BaseMonitor][base_monitor].\n\n```\nimport XestiMonitors\n\nclass GigaHoobieMonitor: BaseMonitor {\n    let handler: (Float) -\u003e Void\n    @objc let hoobie: GigaHoobie\n    private var observation: NSKeyValueObservation?\n\n    init(_ hoobie: GigaHoobie, handler: @escaping (Float) -\u003e Void) {\n        self.handler = handler\n        self.hoobie = hoobie\n    }\n\n    override func configureMonitor() -\u003e Bool {\n        super.configureMonitor()\n        observation = hoobie.observe(\\.nefariousActivityLevel) { [unowned self] hoobie, _ in\n            self.handler(hoobie.nefariousActivityLevel) }\n    }\n\n    override func cleanupMonitor() -\u003e Bool {\n        observation?.invalidate()\n        observation = nil\n        super.cleanupMonitor()\n    }\n}\n```\n\n**Note:** Be sure to invoke the superclass implementations of both\n[configureMonitor()][bm_configureMonitor] and\n[cleanupMonitor()][bm_cleanupMonitor].\n\n#### Subclassing the BaseNotificationMonitor Class\n\nIf your custom monitor determines events by observing notifications, you should\nconsider creating a subclass of\n[BaseNotificationMonitor][base_notification_monitor] instead. In most cases you\nneed only override the\n[addNotificationObservers(_:)][bnm_addNotificationObservers] method. You can\nalso override the\n[removeNotificationObservers(_:)][bnm_removeNotificationObservers] method if\nyou require extra cleanup when the notification observers are removed upon\nstopping the monitor. Although this base class inherits from\n[BaseMonitor][base_monitor], you will *not* be able to override the\n[configureMonitor()][bnm_configureMonitor] and\n[cleanupMonitor()][bnm_cleanupMonitor] methods—they are declared `final` in\n[BaseNotificationMonitor][base_notification_monitor].\n\n```\nimport XestiMonitors\n\nclass TeraHoobieMonitor: BaseNotificationMonitor {\n    let handler: (Bool) -\u003e Void\n    let hoobie: TeraHoobie\n\n    init(hoobie: TeraHoobie, queue: OperationQueue = .main,\n         handler: @escaping (Bool) -\u003e Void) {\n        self.handler = handler\n        self.hoobie = hoobie\n        super.init(queue: queue)\n    }\n\n    override func addNotificationObservers() -\u003e Bool {\n        super.addNotificationObservers()\n        observe(.teraHoobieDidChange) { [unowned self] _ in\n            self.handler(self.hoobie.value) }\n    }\n}\n```\n\n**Note:** Be sure to invoke the superclass implementations of both\n[addNotificationObservers(_:)][bnm_addNotificationObservers] and\n[removeNotificationObservers(_:)][bnm_removeNotificationObservers] in your\noverrides.\n\n## \u003ca name=\"credits\"\u003eCredits\u003c/a\u003e\n\nJ. G. Pusey (ebardx@gmail.com)\n\n## \u003ca name=\"license\"\u003eLicense\u003c/a\u003e\n\nXestiMonitors is available under [the MIT license][license].\n\n[carthage]:     https://github.com/Carthage/Carthage\n[cocoapods]:    http://cocoapods.org\n[homebrew]:     http://brew.sh/\n[jazzy]:        https://github.com/realm/jazzy\n[license]:      https://github.com/eBardX/XestiMonitors/blob/master/LICENSE.md\n[refdoc]:       https://eBardX.github.io/XestiMonitors/\n[spm]:          https://swift.org/package-manager/\n\n[wrapped_foundation_notifications]: https://github.com/eBardX/XestiMonitors/blob/master/Documents/wrapped-foundation-notifications.md\n[wrapped_uikit_notifications]:      https://github.com/eBardX/XestiMonitors/blob/master/Documents/wrapped-uikit-notifications.md\n\n[accelerometer_monitor]:                        https://eBardX.github.io/XestiMonitors/Classes/AccelerometerMonitor.html\n[accessibility_announcement_monitor]:           https://eBardX.github.io/XestiMonitors/Classes/AccessibilityAnnouncementMonitor.html\n[accessibility_element_monitor]:                https://eBardX.github.io/XestiMonitors/Classes/AccessibilityElementMonitor.html\n[accessibility_status_monitor]:                 https://eBardX.github.io/XestiMonitors/Classes/AccessibilityStatusMonitor.html\n[altimeter_monitor]:                            https://eBardX.github.io/XestiMonitors/Classes/AltimeterMonitor.html\n[application_state_monitor]:                    https://eBardX.github.io/XestiMonitors/Classes/ApplicationStateMonitor.html\n[background_refresh_monitor]:                   https://eBardX.github.io/XestiMonitors/Classes/BackgroundRefreshMonitor.html\n[base_monitor]:                                 https://eBardX.github.io/XestiMonitors/Classes/BaseMonitor.html\n[base_notification_monitor]:                    https://eBardX.github.io/XestiMonitors/Classes/BaseNotificationMonitor.html\n[battery_monitor]:                              https://eBardX.github.io/XestiMonitors/Classes/BatteryMonitor.html\n[beacon_ranging_monitor]:                       https://eBardX.github.io/XestiMonitors/Classes/BeaconRangingMonitor.html\n[bundle_class_load_monitor]:                    https://eBardX.github.io/XestiMonitors/Classes/BundleClassLoadMonitor.html\n[bundle_resource_request_monitor]:              https://eBardX.github.io/XestiMonitors/Classes/BundleResourceRequestMonitor.html\n[calendar_day_monitor]:                         https://eBardX.github.io/XestiMonitors/Classes/CalendarDayMonitor.html\n[content_size_category_monitor]:                https://eBardX.github.io/XestiMonitors/Classes/ContentSizeCategoryMonitor.html\n[current_locale_monitor]:                       https://eBardX.github.io/XestiMonitors/Classes/CurrentLocaleMonitor.html\n[device_motion_monitor]:                        https://eBardX.github.io/XestiMonitors/Classes/DeviceMotionMonitor.html\n[document_state_monitor]:                       https://eBardX.github.io/XestiMonitors/Classes/DocumentStateMonitor.html\n[extension_host_monitor]:                       https://eBardX.github.io/XestiMonitors/Classes/ExtensionHostMonitor.html\n[file_system_object_monitor]:                   https://eBardX.github.io/XestiMonitors/Classes/FileSystemObjectMonitor.html\n[focus_monitor]:                                https://eBardX.github.io/XestiMonitors/Classes/FocusMonitor.html\n[gyroscope_monitor]:                            https://eBardX.github.io/XestiMonitors/Classes/GyroscopeMonitor.html\n[heading_monitor]:                              https://eBardX.github.io/XestiMonitors/Classes/HeadingMonitor.html\n[http_cookie_storage_monitor]:                  https://eBardX.github.io/XestiMonitors/Classes/HTTPCookieStorageMonitor.html\n[keyboard_monitor]:                             https://eBardX.github.io/XestiMonitors/Classes/KeyboardMonitor.html\n[location_authorization_monitor]:               https://eBardX.github.io/XestiMonitors/Classes/LocationAuthorizationMonitor.html\n[magnetometer_monitor]:                         https://eBardX.github.io/XestiMonitors/Classes/MagnetometerMonitor.html\n[memory_monitor]:                               https://eBardX.github.io/XestiMonitors/Classes/MemoryMonitor.html\n[menu_controller_monitor]:                      https://eBardX.github.io/XestiMonitors/Classes/MenuControllerMonitor.html\n[metadata_query_monitor]:                       https://eBardX.github.io/XestiMonitors/Classes/MetadataQueryMonitor.html\n[motion_activity_monitor]:                      https://eBardX.github.io/XestiMonitors/Classes/MotionActivityMonitor.html\n[network_reachability_monitor]:                 https://eBardX.github.io/XestiMonitors/Classes/NetworkReachabilityMonitor.html\n[orientation_monitor]:                          https://eBardX.github.io/XestiMonitors/Classes/OrientationMonitor.html\n[pasteboard_monitor]:                           https://eBardX.github.io/XestiMonitors/Classes/PasteboardMonitor.html\n[pedometer_monitor]:                            https://eBardX.github.io/XestiMonitors/Classes/PedometerMonitor.html\n[port_monitor]:                                 https://eBardX.github.io/XestiMonitors/Classes/PortMonitor.html\n[process_info_power_state_monitor]:             https://eBardX.github.io/XestiMonitors/Classes/ProcessInfoPowerStateMonitor.html\n[process_info_thermal_state_monitor]:           https://eBardX.github.io/XestiMonitors/Classes/ProcessInfoThermalStateMonitor.html\n[protected_data_monitor]:                       https://eBardX.github.io/XestiMonitors/Classes/ProtectedDataMonitor.html\n[proximity_monitor]:                            https://eBardX.github.io/XestiMonitors/Classes/ProximityMonitor.html\n[region_monitor]:                               https://eBardX.github.io/XestiMonitors/Classes/RegionMonitor.html\n[screen_brightness_monitor]:                    https://eBardX.github.io/XestiMonitors/Classes/ScreenBrightnessMonitor.html\n[screen_captured_monitor]:                      https://eBardX.github.io/XestiMonitors/Classes/ScreenCapturedMonitor.html\n[screen_connection_monitor]:                    https://eBardX.github.io/XestiMonitors/Classes/ScreenConnectionMonitor.html\n[screen_mode_monitor]:                          https://eBardX.github.io/XestiMonitors/Classes/ScreenModeMonitor.html\n[screenshot_monitor]:                           https://eBardX.github.io/XestiMonitors/Classes/ScreenshotMonitor.html\n[significant_location_monitor]:                 https://eBardX.github.io/XestiMonitors/Classes/SignificantLocationMonitor.html\n[standard_location_monitor]:                    https://eBardX.github.io/XestiMonitors/Classes/StandardLocationMonitor.html\n[status_bar_monitor]:                           https://eBardX.github.io/XestiMonitors/Classes/StatusBarMonitor.html\n[system_clock_monitor]:                         https://eBardX.github.io/XestiMonitors/Classes/SystemClockMonitor.html\n[system_time_zone_monitor]:                     https://eBardX.github.io/XestiMonitors/Classes/SystemTimeZoneMonitor.html\n[table_view_selection_monitor]:                 https://eBardX.github.io/XestiMonitors/Classes/TableViewSelectionMonitor.html\n[text_field_text_monitor]:                      https://eBardX.github.io/XestiMonitors/Classes/TextFieldTextMonitor.html\n[text_input_mode_monitor]:                      https://eBardX.github.io/XestiMonitors/Classes/TextInputModeMonitor.html\n[text_storage_monitor]:                         https://eBardX.github.io/XestiMonitors/Classes/TextStorageMonitor.html\n[text_view_text_monitor]:                       https://eBardX.github.io/XestiMonitors/Classes/TextViewTextMonitor.html\n[time_monitor]:                                 https://eBardX.github.io/XestiMonitors/Classes/TimeMonitor.html\n[ubiquitous_key_value_store_monitor]:           https://eBardX.github.io/XestiMonitors/Classes/UbiquitousKeyValueStoreMonitor.html\n[ubiquity_identity_monitor]:                    https://eBardX.github.io/XestiMonitors/Classes/UbiquityIdentityMonitor.html\n[undo_manager_monitor]:                         https://eBardX.github.io/XestiMonitors/Classes/UndoManagerMonitor.html\n[url_credential_storage_monitor]:               https://eBardX.github.io/XestiMonitors/Classes/URLCredentialStorageMonitor.html\n[user_defaults_monitor]:                        https://eBardX.github.io/XestiMonitors/Classes/UserDefaultsMonitor.html\n[view_controller_show_detail_target_monitor]:   https://eBardX.github.io/XestiMonitors/Classes/ViewControllerShowDetailTargetMonitor.html\n[visit_monitor]:                                https://eBardX.github.io/XestiMonitors/Classes/VisitMonitor.html\n[window_monitor]:                               https://eBardX.github.io/XestiMonitors/Classes/WindowMonitor.html\n\n[p_monitor]:    https://eBardX.github.io/XestiMonitors/Protocols/Monitor.html\n\n[m_is_monitoring]:      https://ebardx.github.io/XestiMonitors/Protocols/Monitor.html#/s:vP13XestiMonitors7Monitor12isMonitoringSb\n[m_start_monitoring]:   https://ebardx.github.io/XestiMonitors/Protocols/Monitor.html#/s:FP13XestiMonitors7Monitor15startMonitoringFT_Sb\n[m_stop_monitoring]:    https://ebardx.github.io/XestiMonitors/Protocols/Monitor.html#/s:FP13XestiMonitors7Monitor14stopMonitoringFT_Sb\n\n[bm_cleanupMonitor]:    https://eBardX.github.io/XestiMonitors/Classes/BaseMonitor.html#/s:FC13XestiMonitors11BaseMonitor14cleanupMonitorFT_Sb\n[bm_configureMonitor]:  https://eBardX.github.io/XestiMonitors/Classes/BaseMonitor.html#/s:FC13XestiMonitors11BaseMonitor16configureMonitorFT_Sb\n[bm_is_monitoring]:     https://eBardX.github.io/XestiMonitors/Classes/BaseMonitor.html#/s:vC13XestiMonitors11BaseMonitor12isMonitoringSb\n[bm_start_monitoring]:  https://eBardX.github.io/XestiMonitors/Classes/BaseMonitor.html#/s:FC13XestiMonitors11BaseMonitor15startMonitoringFT_Sb\n[bm_stop_monitoring]:   https://eBardX.github.io/XestiMonitors/Classes/BaseMonitor.html#/s:FC13XestiMonitors11BaseMonitor14stopMonitoringFT_Sb\n\n[bnm_addNotificationObservers]:     https://eBardX.github.io/XestiMonitors/Classes/BaseNotificationMonitor.html#/s:FC13XestiMonitors23BaseNotificationMonitor24addNotificationObserversFCSo18NotificationCenterSb\n[bnm_cleanupMonitor]:               https://eBardX.github.io/XestiMonitors/Classes/BaseNotificationMonitor.html#/s:FC13XestiMonitors23BaseNotificationMonitor14cleanupMonitorFT_Sb\n[bnm_configureMonitor]:             https://eBardX.github.io/XestiMonitors/Classes/BaseNotificationMonitor.html#/s:FC13XestiMonitors23BaseNotificationMonitor16configureMonitorFT_Sb\n[bnm_removeNotificationObservers]:  https://eBardX.github.io/XestiMonitors/Classes/BaseNotificationMonitor.html#/s:FC13XestiMonitors23BaseNotificationMonitor27removeNotificationObserversFCSo18NotificationCenterSb\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FeBardX%2FXestiMonitors","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FeBardX%2FXestiMonitors","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FeBardX%2FXestiMonitors/lists"}