美文网首页高能
封装YYCategory的实践2018

封装YYCategory的实践2018

作者: 勇往直前888 | 来源:发表于2018-07-31 17:15 被阅读211次

背景简介

根据YY作者的自述文章最近一段时间的工作整理整个YYKit是由一系列文章组成。这个导入YYKit整体感觉有点乱,最后还是根据需要,分模块导入,分别封装一下后,自己再重新组织一下,换个名字,比如KJTKit之类的。经过几天的封装,已经差不多了,还剩下YYCategory,这是小工具,有些很有用,并且类别的使用方式是Object-C特有的,也很普遍。剩下几个工程中暂时还没有涉及,等以后用到了再说。

image.png

封装NSDate

网络来的日期,一般是毫秒数,通过这个创建NSDate对象,有现成API,只是不要忘记将毫秒转化成秒,要除以1000
+ (instancetype)dateWithTimeIntervalSince1970:(NSTimeInterval)secs;

  • NSDate要显示给用户看到,需要转化为NSString,这两者的互转用得比较多,需要借助NSDateFormatter实现,这里直接提供方便工具,比较实用。
// 字符串转日期
+ (nullable NSDate *)kjtDateWithString:(NSString *)dateString format:(NSString *)format {
    return [NSDate dateWithString:dateString format:format];
}

// 日期转字符串
- (nullable NSString *)kjtStringWithFormat:(NSString *)format {
    return [self stringWithFormat:format];
}
  • 临近几天用的比较多,至于临近的月数,年数之类的,等以后用到再封装。
// 相邻几天,昨天就给-1,明天给1
- (nullable NSDate *)kjtDateByAddingDays:(NSInteger)days {
    return [self kjtDateByAddingDays:days];
}

封装NSObject

  • 提供了KVO的封装,这个比较赞,系统方法实在难用。引入 KVOController又有点小题大做的感觉。
// 添加观察者
- (void)kjtAddBlockForKeyPath:(NSString*)keyPath
                        block:(void (^)(id _Nonnull obj, id _Nonnull oldVal, id _Nonnull newVal))block {
    [self addObserverBlockForKeyPath:keyPath block:block];
}

// 移除所有观察者,防止内存泄漏
- (void)kjtRemoveAllBlocks {
    [self removeObserverBlocks];
}

- (void)removeObserverBlocksForKeyPath:(NSString*)keyPath;是故意不提供的,防止内存泄漏

  • 方法交换,涉及runtime相关内容,自己写容易出错,用这个比较方便。
// 交换实例方法
+ (BOOL)kjtSwizzleInstanceMethod:(SEL)originalSel with:(SEL)newSel {
    return [[self class] swizzleInstanceMethod:originalSel with:newSel];
}

// 交换静态类方法
+ (BOOL)kjtSwizzleClassMethod:(SEL)originalSel with:(SEL)newSel {
    return [[self class] swizzleClassMethod:originalSel with:newSel];
}
  • 关联变量,涉及runtime相关内容,自己写容易出错,用这个比较方便。
// 设置指针型关联变量
- (void)kjtSetAssociateValue:(nullable id)value withKey:(void *)key {
    [self setAssociateValue:value withKey:key];
}

// 设置数值型关联变量
- (void)kjtSetAssociateWeakValue:(nullable id)value withKey:(void *)key {
    [self setAssociateWeakValue:value withKey:key];
}

// 读取关联变量
- (nullable id)kjtGetAssociatedValueForKey:(void *)key {
    return [self getAssociatedValueForKey:key];
}

// 移除所有的关联变量,防止内存泄漏
- (void)kjtRemoveAssociatedValues {
    [self removeAssociatedValues];
}

封装NSString

  • md5是经常用到的
// md5
- (nullable NSString *)kjtMd5String {
    return [self md5String];
}
  • base64编码
// base64
- (nullable NSString *)kjtBase64EncodedString {
    return [self base64EncodedString];
}
  • url编解码,这个要自己写的话很烦人,有很多需要注意的地方
// url编码
- (NSString *)kjtUrlEncodeString {
    return [self stringByURLEncode];
}

// url解码
- (NSString *)kjtUrlDecodeString {
    return [self stringByURLDecode];
}
  • html关键字处理,就是加&
// 标签关键字替换为&字符
- (NSString *)kjtEscapingHTMLString {
    return [self stringByEscapingHTML];
}
  • 去掉空格,在用户录入的时候经常用到
// 去掉首尾空格
- (NSString *)kjtTrimString {
    return [self stringByTrim];
}
  • 字符串判空,nil是空,@“ ”也是空
// 判空
- (BOOL)kjtIsEmpty {
    return ![self isNotBlank];
}
  • 字符集判断包含;子串包含iOS8已经提供,这里不重复封装
// 判断是否包含字符集; - (BOOL)containsString:(NSString *)string; iOS8已经提供,这里不重复
- (BOOL)kjtContainsCharacterSet:(NSCharacterSet *)set {
    return [self containsCharacterSet:set];
}
  • json解码
// json解码
- (id)kjtDecodeJson {
    return [self jsonValueDecoded];
}
  • 读文件内容
// 从文件读内容
+ (NSString *)kjtFileStringNamed:(NSString *)name {
    return [self stringNamed:name];
}

封装UIApplication

属性类型的接口并不是很友好,全部改成函数形式的。
另外,实例方法要通过[UIApplication sharedApplication]访问,不是很方便,所以都改成类的静态方法。

  • document和cache的路径,包括NSURL, NSString两种格式
// 文档和cache的路径
+ (NSURL *)kjtDocumentsURL {
    return [UIApplication sharedApplication].documentsURL;
}

+ (NSString *)kjtDocumentsPath {
    return [UIApplication sharedApplication].documentsPath;
}

+ (NSURL *)kjtCachesURL {
    return [UIApplication sharedApplication].cachesURL;
}

+ (NSString *)kjtCachesPath {
    return [UIApplication sharedApplication].cachesPath;
}
  • 应用标识符
// 应用标识符
+ (NSString *)kjtAppBundleName {
    return [UIApplication sharedApplication].appBundleName;
}

+ (NSString *)kjtAppBundleID {
    return [UIApplication sharedApplication].appBundleID;
}
  • 应用版本号,系统接口要记忆字典的键值,并且命名很不友好,取个好名字,用起来就方便多了。
// 版本号
+ (NSString *)kjtAppVersion {
    return [UIApplication sharedApplication].appVersion;
}

+ (NSString *)kjtAppBuildVersion {
    return [UIApplication sharedApplication].appBuildVersion;
}
  • 检查是否盗版,是否从苹果市场安装。是的话,一般是用户的生产版本。要判断签名,实现起来还是蛮麻烦的。
// 是否盗版,这里改了下名字,是否从苹果市场安装
+ (BOOL)kjtIsFromAppstore {
    return ![UIApplication sharedApplication].isPirated;
}

NSData封装

这个和NSString有相似之处,比如加解密这一块。不过又有很大不同,NSData是机器码,01类型的数据流,而NSString是可以写进文档,打印出来看的可见字符。这两者的差异还是很大的,平时使用的时候要注意一下。NSData不可打印,打印出来,就成了description,是01组成的字符了。

  • md5,这个太流行了,给个方便方法
// md5
- (NSString *)kjtMd5String {
    return [self md5String];
}

- (NSData *)kjtMd5Data {
    return [self md5Data];
}
  • 转字符串
// 转字符串
- (nullable NSString *)kjtUtf8String {
    return [self utf8String];
}
  • 与16进制形式字符串互转
// 与16进制字符串互转
- (nullable NSString *)kjtHexString {
    return [self hexString];
}

+ (nullable NSData *)kjtDataWithHexString:(NSString *)hexString {
    return [NSData dataWithHexString:hexString];
}
  • 与base64 字符串互转
// base64 字符串糊状
- (nullable NSString *)kjtBase64EncodedString {
    return [self base64EncodedString];
}

+ (nullable NSData *)kjtDataWithBase64EncodedString:(NSString *)base64EncodedString {
    return [NSData dataWithBase64EncodedString:base64EncodedString];
}
  • json 解码
// json 解码
- (id)kjtDecodeJson {
    return [self jsonValueDecoded];
}
  • 从文件中读
// 从文件中读
+ (nullable NSData *)kjtFileDataNamed:(NSString *)name {
    return [NSData dataNamed:name];
}

封装UIColor

主要是和16进制字符串的互转

// 与16进制字符串互转
+ (nullable UIColor *)kjtColorWithHexString:(NSString *)hexStr {
    return [UIColor colorWithHexString:hexStr];
}

- (nullable NSString *)kjtHexString {
    return [self hexString];
}

- (nullable NSString *)kjtHexStringWithAlpha {
    return [self hexStringWithAlpha];
}

封装UIDevice

这些主要是硬件信息,是属性形式的接口,访问需要[UIDevice currentDevice],不是很方便,改成类静态接口。

  • 系统版本号
// 系统版本号
+ (double)kjtSystemVersion {
    return [UIDevice systemVersion];
}
  • 硬件信息
+ (BOOL)kjtIsPad {
    return [UIDevice currentDevice].isPad;
}

+ (BOOL)kjtIsSimulator {
    return [UIDevice currentDevice].isSimulator;
}

+ (BOOL)kjtIsJailbroken {
    return [UIDevice currentDevice].isJailbroken;
}

+ (BOOL)kjtCanMakePhoneCalls {
    return [UIDevice currentDevice].canMakePhoneCalls;
}

+ (NSString *)kjtMachineModel {
    return [UIDevice currentDevice].machineModel;
}

+ (NSString *)kjtMachineModelName {
    return [UIDevice currentDevice].machineModelName;
}
  • IP地址,有两个,手机的和WiFi的,目前项目中用WiFi IP地址
// ip 地址
+ (NSString *)kjtIpAddressWIFI {
    return [UIDevice currentDevice].ipAddressWIFI;
}

+ (NSString *)kjtIpAddressCell {
    return [UIDevice currentDevice].ipAddressCell;
}
  • 唯一标识符,现在流行用这个。详情可以参考下面这篇文章:
    UUID 浅析
// 唯一标识符
+ (NSString *)kjtIdfvUuidString {
    return [[UIDevice currentDevice].identifierForVendor UUIDString];
}

封装NSNotificationCenter

  • 这是一种订阅模式,有一个中心,应为有一个中心NSNotificationCenter

  • NSNotification是一个对象,包括name,object,userInfo三部分。这个从系统定义可以看出来

@interface NSNotification : NSObject <NSCopying, NSCoding>

@property (readonly, copy) NSNotificationName name;
@property (nullable, readonly, retain) id object;
@property (nullable, readonly, copy) NSDictionary *userInfo;

- (instancetype)initWithName:(NSNotificationName)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;

@end
  • NSNotificationName可以当做普通的NSString来理解
    typedef NSString *NSNotificationName NS_EXTENSIBLE_STRING_ENUM;

  • 一般使用的时候,不会涉及NSNotification对象,使用NSNotificationCenter的单例,比如

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(test) name:@"test" object:nil];
  • 添加观察者一般在主程序,问题也不大。但是发送消息,有可能不在主线程,导致消息丢失。所以有必要封装一个函数,保证发送消息在主线程。
+ (void)kjtPostNotificationOnMainThreadWithName:(NSString *)name
                                      object:(nullable id)object
                                    userInfo:(nullable NSDictionary *)userInfo {
    [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:name object:object userInfo:userInfo];
}

参考文章

YYCategories

文档地址

相关文章

网友评论

    本文标题:封装YYCategory的实践2018

    本文链接:https://www.haomeiwen.com/subject/mcdcvftx.html