类别方法命名的最佳做法

每个人都有一个原因,那是我们所生活的世界中最糟糕的部分。

遗憾的是,我们在iOS 11上遇到了一个与键盘框架有关的怪异问题,仅在iOS11上才发生。 有时,当文本字段变得集中时,键盘会稍微向上移动一点,如下图所示。

在键盘相关通知的信息字典中,我们可以获得键盘的框架。 通过在通知UIKeyboardWillShowNotification的事件处理程序中检查此信息,我们可以发现键盘的高度不正确。

- (void)keyboardWillShow:(NSNotification *)notification { 
NSDictionary *info = [notification userInfo];
NSString *curveValue = [info objectForKey:UIKeyboardAnimationCurveUserInfoKey];
CGRect rect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSLog(@"keyboard frame: %@", NSStringFromCGRect(rect));
}

在iPhone 7上运行时,我们得到如下日志:

 keyboard frame {{0, 451}, {375, 216}} 
keyboard frame {{0, 292}, {375, 375}}
keyboard frame {{0, 451}, {375, 216}}
keyboard frame {{0, 292}, {375, 375}}
keyboard frame {{0, 292}, {375, 375}}

由于键盘的框架完全由iOS控制,并且仅发生在iOS11上,所以我认为一开始是iOS11的问题。 但是,通过谷歌搜索,似乎没有其他人以前曾遇到过此问题。 后来,我创建了一个单独的演示项目来验证键盘行为,但也没有发现此问题。 因此,我们可以合理地推断出,这一定是导致我们出现此问题的怪异家伙。 而且它必须在整个项目范围内,因为键盘上移问题发生在我们项目中的每个文本字段中。

因此,为了解决此问题,我们必须找到这个罪魁祸首,但除了在整个项目范围内之外,没有任何线索。 我首先列出了几件事:

  • 我们实现UIView动画的方式。
  • iPhone6 / iPhone6 +屏幕支持
  • 定向支持
  • 我们创建UIWindow对象的方式。

不幸的是,经过长时间的实验验证后,这些都不是原因。 很好,至少我排除了这些因素,并缩小了可能原因的范围。

我对此用尽了思绪,并在stackoverflow上发布了一个问题,只有一个人回答,但他的回答实际上与我的问题无关。

没有解决此问题的捷径。 基于在简单的演示项目中可以正常工作的事实,我决定一点一点地简化我们的项目,使其与简单的dmeo项目相同。 我知道这很愚蠢,但是没有其他办法。

首先,我简化了相关的视图控制器,使其仅具有两个文本字段一样简单,问题仍然存在。

然后我删除了所有其他数百个不相关的文件,然后魔术发生了,问题解决了。 尽管我仍然需要缩小数百个文件中的罪魁祸首文件,但这是解决此问题的重要一步。 注意,它是项目范围的,因此我锁定了一些实用程序类和类别,尤其是UITextField,UIResponder和UIView上的类别。

答对了! 最终发现它是UIView类别,其编写方式如下:

  #import  @interface UIView (Layout) - (CGFloat)xPos; 
- (CGFloat)yPos;
- (CGFloat)width;
- (CGFloat)height;
- (void)setWidth:(CGFloat)width;
- (void)setHeight:(CGFloat)height;
- (void)setSize:(CGFloat)size;
- (void)setXPos:(CGFloat)xPos;
- (void)setYPos:(CGFloat)yPos;
- (void)setXPos:(CGFloat)xPos yPos:(CGFloat)yPos;
- (CGFloat)xPos;
- (CGFloat)yPos;
- (CGFloat)width;
- (CGFloat)height;
- (void)setWidth:(CGFloat)width;
- (void)setHeight:(CGFloat)height;
- (void)setSize:(CGFloat)size;
- (void)setXPos:(CGFloat)xPos;
- (void)setYPos:(CGFloat)yPos;
- (void)setXPos:(CGFloat)xPos yPos:(CGFloat)yPos;
@end

那么这段代码有什么问题呢? 看来这些方法只是帮助更改视图框架的辅助方法,没什么特别的。 是的,可以使用这些方法,但是这些方法的命名并没有遵循良好的做法。 从iOS11开始,苹果开始以某种方式在sdk中使用这些方法名称,因此此处定义的类别方法将覆盖sdk方法,并导致此奇怪的键盘问题。

在类别的方法上遵循良好的命名约定,尤其是在Apple SDK中的类上创建类别时。 如果您在类别中定义的方法恰好在您不知情的情况下覆盖了这些SDK类的内部方法,那么您很有可能会遇到一些奇怪的问题,例如我在这里遇到的问题。

即使它可以在当前最新的iOS版本上正常运行,也不能保证在将来的iOS版本上也可以正常运行。 因此,请注意类别中的类别名称和方法名称。

命名的良好做法是这样的,在类别名称和类别方法之前加上您选择的项目前缀,例如“ AF”,“ SD”等。应该是这样的:

  #import  @interface UIView (VF_Layout) - (CGFloat)vf_xPos; 
- (CGFloat)vf_xPosyPos;
- (CGFloat)vf_xPoswidth;
- (CGFloat)vf_xPosheight;
- (void)vf_setWidth:(CGFloat)width;
- (void)vf_setHeight:(CGFloat)height;
- (void)vf_setSize:(CGFloat)size;
- (void)vf_setXPos:(CGFloat)xPos;
- (void)vf_setYPos:(CGFloat)yPos;
- (void)vf_setXPos:(CGFloat)xPos yPos:(CGFloat)yPos;
- (CGFloat)vf_xPos;
- (CGFloat)vf_xPosyPos;
- (CGFloat)vf_xPoswidth;
- (CGFloat)vf_xPosheight;
- (void)vf_setWidth:(CGFloat)width;
- (void)vf_setHeight:(CGFloat)height;
- (void)vf_setSize:(CGFloat)size;
- (void)vf_setXPos:(CGFloat)xPos;
- (void)vf_setYPos:(CGFloat)yPos;
- (void)vf_setXPos:(CGFloat)xPos yPos:(CGFloat)yPos;
@end

不良实践就像是科技债务,您以后必须以更高的成本偿还。 因此,绝对值得一开始就表示您对良好做法的尊重。