ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

UIViewController-KeyboardAnimation使用6大常见坑清单:忘记取消订阅、Block循环引用如何避免

UIViewController-KeyboardAnimation使用6大常见坑清单:忘记取消订阅、Block循环引用如何避免 UIViewController-KeyboardAnimation使用6大常见坑清单忘记取消订阅、Block循环引用如何避免【免费下载链接】UIViewController-KeyboardAnimationShowing/dismissing keyboard animation in UIViewController category.项目地址: https://gitcode.com/gh_mirrors/ui/UIViewController-KeyboardAnimationUIViewController-KeyboardAnimation是一款轻量的 iOS 键盘动画开源组件它通过 UIViewController 分类Category提供订阅式 API键盘出现、消失或尺寸变化时你的动画 Block 会自动以键盘原生动画的时长与曲线被执行无需手写通知监听代码。本清单针对新手最常踩的 6 个坑——尤其是忘记取消订阅和Block 循环引用——给出症状、原因和正确做法。1 分钟了解这个组件解决了什么 在 iOS 中处理键盘通常需要监听UIKeyboardWillShowNotification、UIKeyboardWillHideNotification等通知手动取出键盘高度和动画时长再包一层UIView动画——每个页面都要复制一遍这套代码。本组件把这些重复劳动封装成了 4 个订阅 API定义在 UIViewControllerKeyboardAnimation.h 中an_subscribeKeyboardWithAnimations:completion:—— 键盘出现/消失动画 完成回调an_subscribeKeyboardWithBeforeAnimations:animations:completion:—— 额外提供动画开始前的执行时机an_subscribeKeyboardFrameChangesWithAnimations:—— 响应键盘尺寸变化如旋转屏幕时键盘高度改变an_unsubscribeKeyboard/an_unsubscribeKeyboardFrameChanges—— 取消订阅官方示例聊天输入框跟随键盘上移可直接参考演示工程 ViewController.m核心逻辑只有十几行。快速上手安装与最小订阅步骤在 Podfile 中添加依赖后安装pod UIViewControllerKeyboardAnimation, ~ 1.3也可以直接复制头文件与实现文件UIViewControllerKeyboardAnimation.h、UIViewControllerKeyboardAnimation.m进工程或使用 git submodule 方式引入仓库仓库地址https://gitcode.com/gh_mirrors/ui/UIViewController-KeyboardAnimation。最小订阅写法// viewWillAppear 中订阅 __weak typeof(self) weakSelf self; [self an_subscribeKeyboardWithAnimations:^(CGRect keyboardRect, NSTimeInterval duration, BOOL isShowing) { __strong typeof(weakSelf) self weakSelf; self.inputBottomSpace.constant isShowing ? CGRectGetHeight(keyboardRect) : 0; [self.view layoutIfNeeded]; } completion:nil];到这里就能跑起来但以下 6 个坑不避开轻则 UI 不跟随重则内存泄漏。6 大常见坑清单 ⚠️坑 1忘记调用 an_unsubscribeKeyboard —— 别页面上幽灵动画这是使用率最高的 Bug。头文件中的官方警告原文大意是如果当前视图消失时不取消订阅已订阅的视图控制器会在其他页面上继续响应键盘事件。原因在实现里很直白订阅时通过objc_setAssociatedObject把 Block 挂在视图控制器上见 UIViewControllerKeyboardAnimation.m并注册了键盘通知观察者只要视图控制器对象还活着比如它还在导航栈或 Tab 里通知照常派发动画照常执行——哪怕页面早已不可见。✅ 正确做法在viewWillDisappear中取消订阅与订阅成对出现- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self an_unsubscribeKeyboard]; }⚠️ 额外注意an_unsubscribeKeyboard只清理出现/消失通道的 Block 与观察者不会清理键盘尺寸变化通道。如果你同时订阅了an_subscribeKeyboardFrameChangesWithAnimations:必须再调用一次an_unsubscribeKeyboardFrameChanges两条通道互不代替。坑 2Block 内强引用 self —— 键盘动画最常见的循环引用这个坑的头文件里已经写明了warning These blocks will be holding inside UIViewController which calls it, so as with any block-style API avoid a retain cycle。循环链路是这样的视图控制器通过关联对象持有你传入的动画 BlockOBJC_ASSOCIATION_COPY_NONATOMIC会拷贝并强持有 Block 内容Block 里又强引用了self视图控制器本身结果控制器 → Block → 控制器谁也不放手视图控制器永远无法释放。✅ 正确做法Block 内使用弱引用官方 README 示例采用 ReactiveCocoa 的weakify/strongify不用该库时标准__weak写法完全等价__weak typeof(self) weakSelf self; [self an_subscribeKeyboardWithAnimations:^(CGRect keyboardRect, NSTimeInterval duration, BOOL isShowing) { __strong typeof(weakSelf) self weakSelf; if (!self) return; // 修改布局…… } completion:nil];同样的规则适用于beforeAnimations、animations、completion三个 Block 参数——任何一个强捕获self都会形成循环引用。坑 3在 viewDidLoad 里订阅 —— 订阅时机不对很多新手默认初始化就该放viewDidLoad但组件文档对每个订阅 API 都标注了官方建议viewWillAppear是订阅的最佳时机tip viewWillAppear is the best place to subscribe to keyboard events。在viewDidLoad订阅的问题视图控制器可能已被创建但尚未显示例如被 push 前的准备阶段此时键盘状态可能已变化而WillShow/WillHide通知只在状态切换瞬间发一次错过就补不回来导致页面出现时 UI 与键盘位置错乱页面每次重新出现都会重走订阅逻辑与坑 5 叠加会反复添加观察者。✅ 正确做法订阅放viewWillAppear取消订阅放viewWillDisappear让订阅的生命周期与页面可见性严格对齐官方 Demo 正是这样做的见 ViewController.m。坑 4Auto Layout 改了约束却不调用 layoutIfNeeded —— 动画跳变不丝滑动画 Block 是在UIView animate动画事务内部被调用的这是本组件最大的卖点你在 Block 里做的修改会自动享受键盘原生的时长和曲线。但有一个前提条件被新手频繁忽略——文档原话If using auto layout dont forget to call layoutIfNeeded。如果你只修改了约束常量self.inputBottomSpace.constant isShowing ? CGRectGetHeight(keyboardRect) : 0; // 漏了 [self.view layoutIfNeeded];那么约束值虽然变了但视图并没有在动画事务内真正布局表现就是输入框瞬移到目标位置失去了与键盘同步滑动的效果。✅ 正确做法在动画 Block 的最后一行加上[self.view layoutIfNeeded]让约束变更进入当前动画事务。坑 5重复订阅 subscribe —— 按一次键盘动画执行 N 次an_subscribeKeyboardWithAnimations:completion:不是幂等的每调用一次都会执行一次addObserver注册新的通知观察者见 UIViewControllerKeyboardAnimation.m 中an_subscribeKeyboardWithAnimations:completion:的实现。Block 本身会被新值覆盖但观察者会叠加。典型事故场景把订阅写进了viewWillAppear之外的地方如viewDidAppear里根据条件反复触发或页面复用组件时重复初始化订阅 3 次后键盘每弹起一次动画 Block 就被派发执行 3 次——布局被连续改写动画卡顿甚至错乱。✅ 正确做法订阅只做一次或确保先an_unsubscribeKeyboard再重新订阅分清两个通道WillShow/WillHide出现/消失与WillChangeFrame尺寸变化如转屏后键盘高度变化是两条独立的通知通道按需选择避免同一个页面同时订阅两套后又各自忘记清理参考坑 1。坑 6误读 isShowing 与 keyboardRect —— 键盘收起了UI 却回不去动画 Block 的第三个参数isShowing表示这次是出现还是消失而keyboardRect是键盘最终frame屏幕坐标系。两个高频误用不区分 isShowing 就写布局。键盘消失时 Block 同样会被调用isShowing为NO如果只写上移逻辑、没有对应的复位分支输入框就会永远悬在键盘收起后的位置。正确写法是对两个分支各写一套状态if (isShowing) { self.inputBottomSpace.constant CGRectGetHeight(keyboardRect); } else { self.inputBottomSpace.constant 0; }直接拿 keyboardRect 当视图坐标用。keyboardRect来自UIKeyboardFrameEndUserInfoKey是窗口屏幕坐标系下的完整 frame不要直接赋给视图的frame.origin对跟随键盘高度类需求取CGRectGetHeight(keyboardRect)即可Demo 工程也是这么做的。顺带一提completion回调的参数finished为NO时表示动画在中途被打断例如用户快速连点输入框依赖动画完成的逻辑如置回状态标志位要判断这个值官方复杂示例就是用它重置isKeaboardAnimation标记的。6 大坑速查表 #坑典型症状正确做法1忘记取消订阅别的页面弹键盘本页 UI 跟着动viewWillDisappear调an_unsubscribeKeyboard帧变化通道单独取消2Block 强引用 self页面销毁后内存不回落Block 内__weak/weakify弱引用3viewDidLoad订阅页面出现时 UI 与键盘错位订阅放viewWillAppear与取消订阅成对4忘记layoutIfNeeded布局瞬移、失去动画同步感Auto Layout 场景在动画 Block 末尾补上5重复订阅 / 混用双通道一次键盘事件触发多次动画订阅只做一次两条通道分别管理6误读 isShowing / keyboardRect键盘收起后输入框不回落分支处理复位用CGRectGetHeight取高度小结UIViewController-KeyboardAnimation 的价值在于用极小的 API 面换掉了重复的键盘通知样板代码而它把订阅、取消订阅、Block 持有这三件事的生命周期管理交还给了使用者。记住本文的 6 大坑尤其是取消订阅成对调用与Block 弱引用 self这两条核心纪律基本可以覆盖新手阶段全部的高频事故。组件本体仅头文件和实现文件两个源文件UIViewControllerKeyboardAnimation.h、UIViewControllerKeyboardAnimation.m配合 Demo 工程Demo/KeyboardAnimationDemo/通读一遍你对它的所有行为都能建立确定性预期。【免费下载链接】UIViewController-KeyboardAnimationShowing/dismissing keyboard animation in UIViewController category.项目地址: https://gitcode.com/gh_mirrors/ui/UIViewController-KeyboardAnimation创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表