WLUnitField 密码/验证码输入框——阅读笔记

这是我参与更文挑战的第3天,活动详情查看: 更文挑战

为了让用户在输入密码、验证码时辨识度更高,一般都会自定义输入框。WLUnitField 实现了一个类似 UITextField 的输入框。

XIB 的支持

WLUnitField 支持了 XIB 实时渲染,可以在 XIB 上直接设置属性,然后查看效果,大大降低了学习使用的难道。

为了用来处理 IB 中不支持(自定义枚举)的类型,和修饰符不统一的问题(是否为 readonly 属性),作者使用了预处理宏 TARGET_INTERFACE_BUILDER

#if TARGET_INTERFACE_BUILDER
// 只在 IB 中执行的代码
#else
// App 运行过程中的代码
#endif
复制代码

部分代码如下:

IB_DESIGNABLE
@interface WLUnitField : UIControl <UITextInput>

#if TARGET_INTERFACE_BUILDER
@property (nonatomic, assign) IBInspectable NSUInteger inputUnitCount;
@property (nonatomic, assign) IBInspectable NSUInteger style;
#else
@property (nonatomic, assign, readonly) NSUInteger inputUnitCount;
@property (nonatomic, assign, readonly) WLUnitFieldStyle style;
#endif

@end
复制代码

其中 style 在代码中使用的是 WLUnitFieldStyle 类型,IB 中只能使用基础类型。

NSNotificationName

以前定义通知时一直都使用的 NSString *,但是有更合理的类型 NSNotificationName

#ifdef NSFoundationVersionNumber_iOS_9_x_Max
    NSNotificationName const WLUnitFieldDidBecomeFirstResponderNotification = @"WLUnitFieldDidBecomeFirstResponderNotification";
    NSNotificationName const WLUnitFieldDidResignFirstResponderNotification = @"WLUnitFieldDidResignFirstResponderNotification";
#else
    NSString *const WLUnitFieldDidBecomeFirstResponderNotification = @"WLUnitFieldDidBecomeFirstResponderNotification";
    NSString *const WLUnitFieldDidResignFirstResponderNotification = @"WLUnitFieldDidResignFirstResponderNotification";
#endif
复制代码

其实 NSNotificationName 就是 NSString * 的别名:

typedef NSString *NSNotificationName NS_EXTENSIBLE_STRING_ENUM;
复制代码

NSString 的编码、循环

WLUnitField 的作者在对一个字符串进行循环时,使用了 enumerateSubstringsInRange:options:usingBlock 方法:

[text enumerateSubstringsInRange:NSMakeRange(0, text.length)
                         options:NSStringEnumerationByComposedCharacterSequences
                      usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
    if (self.characterArray.count < self.inputUnitCount)
        [self.characterArray addObject:substring];
    else
        *stop = YES;
}];
复制代码

通过搜索看到了这篇文章:NSString 与 Unicode。里面详细的介绍了 Unicode 的发展历程,标准等价(canonically equivalent)和 相容等价(compatibility equivalence)等定义,以及 NSString 的编码方式,我们在处理字符串长度、循环字符串时的注意事项和技巧。

以前总是调用 lengthcharacterAtIndex:,在处理 emoji 时就会出错。有些代码在写错了几百遍、几千遍之后,才知道什么是正确的方式。

想起之前有个需求:一个汉字为两个字符长度。实现方式如下:

extension String {
    /// 获取 GB 编码下的字符长度。一个汉字 = 两个字符长度。
    /// - Returns: 字符长度
    func GBCharacterCount() -> Int {
        let GBEncoding = CFStringConvertEncodingToNSStringEncoding(UInt32(CFStringEncodings.GB_18030_2000.rawValue))
        return self.data(using: String.Encoding(rawValue: GBEncoding))?.count ?? 0
    }
}
复制代码

参考

NSString 与 Unicode

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享