XestiMonitors 框架提供了超过六十个功能齐全的监视器类,开箱即用,使您的应用程序能够轻松检测和响应许多常见的系统生成的事件。
在其他方面,您可以将 XestiMonitors 视为管理最常见通知(主要在 iOS 和 tvOS 上)的更好方法。目前,XestiMonitors 提供了几乎所有UIKit
通知(请参阅 UIKit 监视器)和许多Foundation
通知(请参阅 Foundation 监视器)的“包装器”。
XestiMonitors 还围绕几个框架和编程接口提供了方便的“包装器”,使您的应用程序更容易使用
SCNetworkReachability
编程接口,使您的应用程序可以非常轻松地确定目标主机的可达性。 有关详细信息,请参阅其他监视器。针对所有四个平台的更多部分的附加监视器将在 XestiMonitors 的未来版本中推出!
最后,XestiMonitors 是可扩展的——您可以轻松创建自己的自定义监视器。 有关详细信息,请参阅自定义监视器。
CocoaPods 是 Cocoa 项目的依赖项管理器。 您可以使用以下命令安装它
$ gem install cocoapods
要使用 CocoaPods 将 XestiMonitors 集成到您的 Xcode 项目中,请在您的Podfile
中指定它
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!
target '<Your Target Name>' do
pod 'XestiMonitors'
end
然后,运行以下命令
$ pod install
Carthage 是一个分散式依赖项管理器,可以构建您的依赖项并为您提供二进制框架。
您可以使用Homebrew 使用以下命令安装 Carthage
$ brew update
$ brew install carthage
要使用 Carthage 将 XestiMonitors 集成到您的 Xcode 项目中,请在您的Cartfile
中指定它
github "eBardX/XestiMonitors"
然后,运行以下命令
$ carthage update
最后,将构建的XestiMonitors.framework
拖到您的 Xcode 项目中。
Swift Package Manager 是一种用于自动化 Swift 代码分发的工具,并已集成到 swift 编译器中。 它还处于早期开发阶段,但 XestiMonitors 确实支持其在受支持平台上的使用。
设置好 Swift 包后,将 XestiMonitors 添加为依赖项就像将其添加到Package.swift
的dependencies
值一样简单。
dependencies: [
.Package(url: "https://github.com/eBardX/XestiMonitors.git")
]
所有监视器类都符合 Monitor 协议,因此使您可以创建可以统一启动或停止的监视器数组——代码行数更少!
例如,在视图控制器中,您可以延迟实例化几个监视器,此外,还可以延迟实例化包含这些监视器的数组变量
import XestiMonitors
lazy var keyboardMonitor = KeyboardMonitor { [unowned self] in
// do something…
}
lazy var memoryMonitor = MemoryMonitor { [unowned self] in
// do something…
}
lazy var orientationMonitor = OrientationMonitor { [unowned self] in
// do something…
}
lazy var monitors: [Monitor] = [keyboardMonitor,
memoryMonitor,
orientationMonitor]
然后,在viewWillAppear(_:)
和viewWillDisappear(_:)
方法中,您只需一行代码即可启动或停止所有这些监视器
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
monitors.forEach { $0.startMonitoring() }
}
override func viewWillDisappear(_ animated: Bool) {
monitors.forEach { $0.stopMonitoring() }
super.viewWillDisappear(animated)
}
易如反掌!
XestiMonitors 提供了七个包装 Core Location 框架的监视器类,您可以使用它们来确定设备的地理位置、海拔或方向;或其相对于附近 iBeacon 的位置
XestiMonitors 提供了七个包装 Core Motion 框架的监视器类,您可以使用它们从设备获取原始和处理后的运动测量数据
XestiMonitors 提供了十七个包装 Foundation
通知的监视器
XestiMonitors 提供了许多包装 UIKit
通知的监视器。
XestiMonitors 提供了三个监视器类,您可以使用它们来观察系统生成的辅助功能事件
XestiMonitors 提供了七个监视器类,可用于观察系统生成的关于应用程序的常见事件
XestiMonitors 提供了三个监视器类,可用于检测设备特征的变化
XestiMonitors 提供了四个监视器类,可用于检测与屏幕关联的属性更改
XestiMonitors 提供了四个监视器类,可用于检测文本输入模式和内容的变化
此外,XestiMonitors 还提供了其他九个 UIKit
监视器
KeyboardMonitor 在删除应用程序中的大量样板代码方面尤其方便。这是自定义视图控制器中键盘监视的典型处理方式
func keyboardWillHide(_ notification: Notification) {
let userInfo = notification.userInfo
var animationDuration: TimeInterval = 0
if let value = (userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue {
animationDuration = value
}
constraint.constant = 0
UIView.animate(withDuration: animationDuration) {
self.view.layoutIfNeeded()
}
}
func keyboardWillShow(_ notification: Notification) {
let userInfo = notification.userInfo
var animationDuration: TimeInterval = 0
if let value = (userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue {
animationDuration = value
}
var frameEnd = CGRect.zero
if let value = (userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
frameEnd = value
}
constraint.constant = frameEnd.height
UIView.animate(withDuration: animationDuration) {
self.view.layoutIfNeeded()
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let nc = NotificationCenter.`default`
nc.addObserver(self, selector: #selector(keyboardWillHide(_:)),
name: .UIKeyboardWillHide, object: nil)
nc.addObserver(self, selector: #selector(keyboardWillShow(_:)),
name: .UIKeyboardWillShow, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.`default`.removeObserver(self)
super.viewWillDisappear(animated)
}
这是使用 KeyboardMonitor 的 XestiMonitors 方式
import XestiMonitors
lazy var keyboardMonitor = KeyboardMonitor { [unowned self] event in
guard let constraint = self?.constraint,
let view = self?.view else { return }
switch event {
case let .willHide(info):
constraint.constant = 0
UIView.animate(withDuration: info.animationDuration) {
view.layoutIfNeeded()
}
case let .willShow(info):
constraint.constant = info.frameEnd.height
UIView.animate(withDuration: info.animationDuration) {
view.layoutIfNeeded()
}
default:
break
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
keyboardMonitor.startMonitoring()
}
override func viewWillDisappear(_ animated: Bool) {
keyboardMonitor.stopMonitoring()
super.viewWillDisappear(animated)
}
你的钱包里有什么?
此外,XestiMonitors 还提供了另外两个监视器
最重要的是,XestiMonitors 框架提供了多种方法来轻松创建自己的自定义监视器。
您可以创建一个新类,或扩展一个现有类,使其符合 Monitor 协议。您只需实现 startMonitoring() 和 stopMonitoring() 方法,以及 isMonitoring 属性
import XestiMonitors
extension MegaHoobieWatcher: Monitor {
var isMonitoring: Bool { return watchingForHoobiesCount() > 0 }
func startMonitoring() -> Bool {
guard !isMonitoring else { return }
beginWatchingForHoobies()
}
func stopMonitoring() -> Bool {
guard isMonitoring else { return }
endWatchingForHoobies()
}
}
注意: startMonitoring() 和 stopMonitoring() 中的 guard 语句可以防止在监视器处于不正确状态时启动或停止监视器。这被认为是良好的编码实践。
通常,您需要创建一个 BaseMonitor 的子类。使用此抽象基类的优点是可以为您处理基本的 guard 逻辑。具体来说,如果 startMonitoring() 方法已激活,则不会尝试启动监视器;如果 stopMonitoring() 方法 *未* 激活,则不会尝试停止监视器。您只需重写此基类的 configureMonitor() 和 cleanupMonitor() 方法,而不是直接实现所需的协议方法和属性。实际上,您*不能*重写 startMonitoring() 和 stopMonitoring() 方法或 isMonitoring 属性——它们在 BaseMonitor 中声明为 final
。
import XestiMonitors
class GigaHoobieMonitor: BaseMonitor {
let handler: (Float) -> Void
@objc let hoobie: GigaHoobie
private var observation: NSKeyValueObservation?
init(_ hoobie: GigaHoobie, handler: @escaping (Float) -> Void) {
self.handler = handler
self.hoobie = hoobie
}
override func configureMonitor() -> Bool {
super.configureMonitor()
observation = hoobie.observe(\.nefariousActivityLevel) { [unowned self] hoobie, _ in
self.handler(hoobie.nefariousActivityLevel) }
}
override func cleanupMonitor() -> Bool {
observation?.invalidate()
observation = nil
super.cleanupMonitor()
}
}
注意: 务必调用 configureMonitor() 和 cleanupMonitor() 的超类实现。
如果您的自定义监视器通过观察通知来确定事件,则应考虑创建一个 BaseNotificationMonitor 的子类。在大多数情况下,您只需重写 addNotificationObservers(_:) 方法。如果当通知观察器在停止监视器时被删除时需要额外的清理,您还可以重写 removeNotificationObservers(_:) 方法。虽然这个基类继承自 BaseMonitor,但您*不能*重写 configureMonitor() 和 cleanupMonitor() 方法——它们在 BaseNotificationMonitor 中声明为 final
。
import XestiMonitors
class TeraHoobieMonitor: BaseNotificationMonitor {
let handler: (Bool) -> Void
let hoobie: TeraHoobie
init(hoobie: TeraHoobie, queue: OperationQueue = .main,
handler: @escaping (Bool) -> Void) {
self.handler = handler
self.hoobie = hoobie
super.init(queue: queue)
}
override func addNotificationObservers() -> Bool {
super.addNotificationObservers()
observe(.teraHoobieDidChange) { [unowned self] _ in
self.handler(self.hoobie.value) }
}
}
注意: 请务必在您的重写中调用父类的 addNotificationObservers(_:) 和 removeNotificationObservers(_:) 方法实现。
J. G. Pusey (ebardx@gmail.com)
XestiMonitors 基于 MIT 许可证 发布。