Base

1.看到weakify和strongify这两个宏定义如下:

#ifndef weakify#if DEBUG#if __has_feature(objc_arc)#define weakify(object) autoreleasepool{} __weak __typeof(object) weak##_##object = object;#else#define weakify(object) autoreleasepool{} __block __typeof(object) weak##_##object = object;#endif#else#if __has_feature(objc_arc)#define weakify(object) try{} @finally{} {} __weak __typeof(object) weak##_##object = object;#else#define weakify(object) try{} @finally{} {} __block __typeof(object) weak##_##object = object;#endif#endif
#endif#ifndef strongify#if DEBUG#if __has_feature(objc_arc)#define strongify(object) autoreleasepool{} __typeof(object) object = weak##_##object;#else#define strongify(object) autoreleasepool{} __typeof(object) object = block##_##object;#endif#else#if __has_feature(objc_arc)#define strongify(object) try{} @finally{} {} __typeof(object) object = weak##_##object;#else#define strongify(object) try{} @finally{} {} __typeof(object) object = block##_##object;#endif#endif
#endif
复制代码

使用的时候:

 @weakify(self);void(^mylock)() = ^{@strongify(self);NSLog(@"Hello %p", self);};
复制代码

在代码定义的时候,不是很明白为什么要加上@autoreleasepool{} {}等这样的代码,并且也不知道使用的时候为啥要加上@。。

然后在YYKit的issue中找到了答案:

关于__block__weak的话,__weak是为了防止出现循环引用,在block内保持对外部变量的弱引用,而__block的话则是将在内部引用了变量的地址,方便在block内进行赋值修改。

2.CFAutorelease

static inline CFTypeRef YYCFAutorelease(CFTypeRef CF_RELEASES_ARGUMENT arg) {// 1if (((long)CFAutorelease + 1) != 1) {return CFAutorelease(arg);} else {// 2id __autoreleasing obj = CFBridgingRelease(arg);return (__bridge CFTypeRef)obj;}
}
复制代码

CFAutoRelease做的事情就是ARC对NSObject的计数操作。在ARC环境下,ARC并不会对Core Foundation对象进行计数,所以Core Foundation的操作需要我们自己完成。CFAutoRelease会将对象添加到自动释放池中,这就意味着在下一轮的loop中,该对象会接收到CFRelease的信息,或者在自动释放池已经满了的时候进行释放。

  1. 用于iOS 6以上,(long)CFAutorelease表示的是CFAutorelease这个函数的所在的内存地址。这里我的理解是当函数不存在的时候,其内存地址会为0,但是又不明白为什么要加1后去判断是否为1.(求解答)
  2. 为了适配iOS 6添加的代码,使用__autoreleasing修饰的话,会将对象强行添加到自动释放池中。

3.获取某段代码的运行时间

// <QuartzCore/QuartzCore.h>版本
// extern double CACurrentMediaTime(void);
double begin, end, ms;
begin = CACurrentMediaTime();
// do something
end = CACurrentMediaTime();
ms = (end - begin) * 1000; // 转化为毫秒// <sys/time.h>版本
struct timeval t0, t1;
gettimeofday(&t0, NULL);
// do something
gettimeofday(&t1, NULL);
double ms = (double)(t1.tv_sec - t0.tv_sec) * 1e3 + (double) (t1.tv_usec - t0.tv_usec) * 1e-3; // 结果是毫秒
复制代码

4.使用__DATE____TIME__获取当前日期和时间 5.dispatch_time在设备休眠的时候会停止计时,而dispatch_wall_time在设备休眠时还会继续计时 6.pthread_main_np()获取主线程,如果其值为不等于0的话,表明当前处于主线程 7.volatile表示的是系统每次都会从内存中访问该变量的数据,而不会在cache或者是寄存器的备份中读取,且会要求编译器不对该变量的访问进行优化。该变量随时可能会发生变化. 8.深拷贝一个对象:

深拷贝(Deep Copy)是指将整个对象的内存直接拷贝到另一块内存中,浅拷贝(Shallow Copy)仅仅拷贝指向对象的指针:

即浅拷贝是指针拷贝,深拷贝是内容拷贝

实现深拷贝的方法,可以将对象先归档后再进行读档,如下:

id obj = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:originalObj]];
复制代码

举个例子:

NSArray<NSMutableString *> *originalArray = @[[NSMutableString stringWithString:@"1"], [NSMutableString stringWithString:@"2"], [NSMutableString stringWithString:@"3"]];NSArray<NSMutableString *> *copyArray = [originalArray copy];NSMutableString *one = [originalArray objectAtIndex:0];[one setString:@"5"];
复制代码

上面的代码中,当你把两个Array都打印出来的话,你会发现copyArray的内容也跟着修改了,copy方法执行的指针复制。

NSArray<NSMutableString *> *originalArray = @[[NSMutableString stringWithString:@"1"], [NSMutableString stringWithString:@"2"], [NSMutableString stringWithString:@"3"]];NSArray<NSMutableString *> *deepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:originalArray]];NSMutableString *one = [originalArray objectAtIndex:0];[one setString:@"5"];
复制代码

而这段代码执行的就是深拷贝,通过归档后解档获取内容一致的集合,并且该集合又存在另一块内存上。互不影响。

9.递归锁的实现

static inline void pthread_mutex_init_recursive(pthread_mutex_t *mutex, bool recursive) {
#define YYMUTEX_ASSERT_ON_ERROR(x_) do { \
__unused volatile int res = (x_); \
assert(res == 0); \
} while(0)assert(mutex != NULL);if (!recursive) {YYMUTEX_ASSERT_ON_ERROR(pthread_mutex_init(mutex, NULL));} else {pthread_mutexattr_t attr;YYMUTEX_ASSERT_ON_ERROR(pthread_mutexattr_init(&attr));YYMUTEX_ASSERT_ON_ERROR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));YYMUTEX_ASSERT_ON_ERROR(pthread_mutex_init(mutex, &attr));YYMUTEX_ASSERT_ON_ERROR(pthread_mutexattr_destroy(&attr));}
#undef YYMUTEX_ASSERT_ON_ERROR
}
复制代码

volatile关键字用于告诉编译器其后面的变量随时可能发生变化,编译后的程序如果需要存储或者读取的时候都要从变量地址中直接读取。

Foundation

NSObject+YYAdd

在这个Category中,主要是添加了可变参数的方法,runtime的Method Swizzling, Associate value和深拷贝的方法。

  1. 在实现可变参数函数的过程中,我们需要用到:
  • va_list args - 指向可变参数列表的指针
  • va_start(args, firstArg) - 初始化va_list变量,这个宏的第二个参数为第一个可变参数的前一个参数
  • va_arg(args, type) - 获取返回的可变参数,第二个参数为对应参数的类型
  • va_end(args) - 清空参数列表,并置参数指针args无效

?:

- (void)test:(NSString *)firstArg, ... {va_list args;va_start(args, firstArg);if (firstArg) {NSString *parameter;while ((parameter = va_arg(args, id))) {NSLog(@"%@", parameter);}}va_end(args);
}- (void)viewDidLoad {[super viewDidLoad];[self test:@"first", @"Hello", @"World", nil];
}
复制代码

YYKit作者通过使用NSMethodSignatureNSInvocation实现了可变参数的方法实现。

2.在获取函数返回值类型的时候,是根据char型指针指向的编码来进行判断的:

编码 代表类型
r const
n in
N inout
o out
O bycopy
R byref
V oneway
v void
B bool
c char
C unsigned char
s short
S unsigned short
i int
I unsigned int
l int
L unsigned int
q long long
Q unsigned long long
f float
d double
D long double
@ id
# Class
如果是返回其他的类型,比方说struct / union / SEL / void * / unknown的话,可能通过NSValuevalueWithBytes:objCType:方法进行类型的转换

3.在交换两个方法的实现时,需要注意实例方法和类方法的区别:

// 实例方法
Method instanceMethod = class_getInstanceMethod(self, sel);// 类方法
Method classMethod = class_getInstanceMethod(objc_getClass(self), sel);
复制代码

4.设置关联对象时,strong的话使用OBJC_ASSOCIATION_RETAIN_NONATOMIC进行修饰,weak对象使用OBJC_ASSOCIATION_ASSIGN

5.实现真正的深复制的话,可以通过归档/解档来进行操作:

id obj = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:o]];
复制代码

NSObject+YYAddForARC

NSObject+YYAddForKVO

这个Category的作用是将KVO改写成block的调用。

将block声明为_YYNSObjectKVOBlockTarget的属性,通过Associated Object为NSObject添加一个字典属性,其中,键值对为keypath和一个存储了_YYNSObjectKVOBlockTarget实例的数组。用数组大概是因为可能会有多个object监听同一个属性?

NSString+YYAdd

1.提供了加密的方法,加密的方式有: md2, md4, md5, sha1, sha224, sha256, sha384, sha512, hmac***, crc32. 2.base64和utf-8的编解码 3.字符串的size 4.正则表达式匹配 5.将NSString转化为NSNumber 6.获取UUID 7.转化为UTF32(NSString是UTF16的) 8.其他工具类

在加密的时候,需要先将NSString转化为NSData类型之后再进行加密操作。在YYKit中,使用NSStringdataUsingEncoding:方法,将字符串通过UTF8编码为NSData。关于加密的函数,在NSData的Category中在进行解析。

2.获取UUID的话,可以通过Core Foundation的方法进行获取

CFUUIDRef uuid = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, uuid);
CFRelease(uuid);
NSString *uuidString = (__bridge_transfer NSString*)string;
复制代码

NSNumber+YYAdd

这个Category提供的,就是将一个能够转化为NSNumber类的字符串转化为NSNumber类型

1.将十六进制的字符串转为NSNumber, 使用NSScanner

// 比方说0xf0f0f0等等
NSScanner *scan = [NSScanner scannerWithString:str];
unisigned num = -1;
BOOL suc = [scan scanHexInt:&num];
if (suc) {NSNumber *num = [NSNumber numberWithLong:num];
}
复制代码

NSData+YYAdd

这里就是将数据加密的类

在iOS中,要将数据加密的话,可以使用`<CommomCrypto/CommonCrypto.h>这个框架提供的方法来将给定的数据进行加密。

1.将char类型输出为字符串的话,使用%x,一般用两位来代表char,也就是%02x

2.md2, md4, md5加密的方法为CC_MD?(const void *data, CC_LONG len, unsigned char *md)。其中问好?用2/4/5进行替代。第一个参数代表要加密的数据,第二个参数代表加密数据的长度,最后一个代表输出结果。另外要注意的是,输出结果的长度根据不同的加密方法在初始化时填入的参数有所不同。md2加密的长度是CC_MD2_DIGEST_LENGTH,md4和5的话就替换掉2就行了。

3.sha1, sha224, sha256, sha384, sha512加密的话,跟上面mdx的加密方式差不多,不过使用的是CC_SHA?(const void *data, CC_LONG len, unsigned char *md)方法(就是没明白为什么在输出为字符串的时候,字符串的初始化长度要*2 -- 答案:What is the length of a hashed string with SHA512?, 大概就是sha加密出来的字节数,比我们输出为hex字符串的字节数少了一半,所以要乘以2)

4.hmac加密的话,使用ccHmac(CCHmacAlgorithm algorithm, const void *key, size_t keyLength, const void *data, size_t dataLength, void *macOut)加密,从参数不难看出具体的含义,要注意的是,传入的加密的key为字符串时,要将其转为char类型。

5.AES256加密使用的是CCCrypt方法

6.在将NSData类型的数据输出为十六进制字符串的时候,一般会将字符串的长度设置为数据长度*2.原因就参照上面sha加密时的解释

7.将hex的字符串转为NSData的话

+ (NSData *)dataWithHexString:(NSString *)hexStr {hexStr = [hexStr stringByReplacingOccurrencesOfString:@" " withString:@""];hexStr = [hexStr lowercaseString];NSUInteger len = hexStr.length;if (!len) return nil;unichar *buf = malloc(sizeof(unichar) * len);if (!buf) return nil;[hexStr getCharacters:buf range:NSMakeRange(0, len)];NSMutableData *result = [NSMutableData data];unsigned char bytes;char str[3] = { '\0', '\0'. '\0' }; // 有3个的原因是。。以'\0'结尾。。第三个理解为做结束标志位int i;for (i = 0; i < len / 2; i++) {str[0] = buf[i * 2];str[1] = buf[i * 2 + 1];bytes = strtol(str, NULL, 16); // 将字符串转为16位进制[result appendBytes:&bytes length:1];}free(buf);return result;
}
复制代码

8.base64加密的太长了。。就不讲了,原理谷歌一下大概都能清楚。 9.gzipInflategzipDeflate的话用于字符串的加压和解压操作,要进行zip操作的话,需要导入<zlib.h>头文件.

NSArray+YYAdd

一些常用的数组方法,比方说从plist文件中生成数组等

1.使用NSPropertyListSerialization将Property list来进行NSObject对象的转化。

NSDictionary+YYAdd

一些常用的字典方法,比方说从plist文件中生成字典,字典的有序的key,有序的value数组等

NSDate+YYAdd

NSDate常用方法

1.对于时间的加减的话,通常都是使用NSCalendar来进行计算。

NSNotificationCenter+YYAdd

NSNotificationCenter+YYAdd这个类提供的方法主要是将消息在主线程post出来,因为NSNotificaitonCenter消息的发送取决于发送的线程,方法的执行也是在该线程中执行,所以有需要在主线程中进行执行话,得在主线程中发送notification

1.在上面说过,YYKit的主线程判断使用的是pthread的pthread_main_np方法

NSKeyedUnarchiver+YYAdd

主要是为解档时添加了try/catch方法来捕获错误

NSTimer+YYAdd

NSTimer的计时的selector转为了block执行

NSBundle+YYAdd

根据屏幕的scale来获取对应的文件的路径

NSThread+YYAdd

为当前线程的runloop添加自动释放池


UIKit

UIColor+YYAdd

提供了从hex转为了UIColor的方法,并且也提供了RGB, HSB, HSL和CMYK之间的转化方法

1.对于RGB颜色来说,有RGB, RGBA, RRGGBB, RRGGBBAA这几种表现形式,前缀可能会出现'#'或者'0x' 2.sscanf(string str, string fmt, mixed var1, mixed var2 ...)从指定的字符串中读入与指定格式相符的数据

3.获取两个颜色相加后的结果的话,可以使用Core Graphics.先创建位图,然后在位图当中进行颜色的填充,获取结果值

UIImage+YYAdd

使用Core Graphic和vImage来处理图片

1._yy_CGImageSourceGetGIFFrameDelayAtIndex(CGImageSourceRef source, size_t index)方法用于获取当前这帧图片的播放时长 2.根据NSData的类型的数据来判断图片是否是GIF的话,有两个条件:

  • data.bytes & 0xFFFFFF == '0FIG'
  • CGImageSourceGetCount() > 1 3.创建纯色图片
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size {if (!color || size.width <= 0 || size.height <= 0) {return nil;}CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);UIGraphicsBeginImageContextWithOptions(size, NO, 0);CGContextRef context = UIGraphicsGetCurrentContext();if (!context) {return nil;}CGContextSetFillColorWithColor(context, color.CGColor);CGContextFillRect(context, rect);UIImage *image = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return image;
}
复制代码

4.判断图片是否有alpha通道的话,使用CGImageGetAlphaInfo()方法,并与kCGBitmapAlphaInfoMask进行与运算,之后判断该值是否等于CGImageAlphaInfo中带alpha通道的枚举值

UIControl+YYAdd

UIBarButtonItem+YYAdd

UIGestureRecognizer+YYAdd

UIView +YYAdd

1.在生成屏幕截图时,在snapshotImage中,会先将layer绘制到当前的上下文中,而在snapshotImageAfterScreenUpdates:函数中,则是通过drawViewHierarchyInRect:afterScreenUpdates:来进行,两个方法的不同之处在于前者会忽略所有图形的处理效果,后者允许我们对截图进行图形处理

UIScrollView+YYAdd

1.在计算scrollview的内容位置的时候,需要考虑上contentInset的影响

UITableView+YYAdd

UITextField+YYAdd

UIScreen+YYAdd

UIDevice+YYAdd

1.判断设备是否为ipad:UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad; 2.(厉害了。。。还能判断越狱与否)判断越狱设备的话,根据'/Applications/Cydia.app', '/private/var/lib/apt/', '/private/var/lib/cydia/', '/private/var/stash'这几个路径来进行判断。或者试着在'/private/'下进行文件读写,能写入的表明是越狱设备。 3.获取设备已经使用了多长时间:

- (NSDate *)systemUptime {NSTimeInterval time = [[NSProcessInfo processInfo] systemUptime];return [[NSDate alloc] initWithTimeIntervalSinceNow:(0 - time)];
}
复制代码

UIApplication+YYAdd

1.通过[NSBundle mainBundle]objectForInfoDictionaryKey:获取bundle名称,id,app版本和build版本:'CFBundleName, CFBundleIdentifier, CFBundleShortVersionString, CFBundleVersion'

UIFont+YYAdd

1.使用UIFont实例的fontDescriptor.symbolicTraits可以获取到字体的一些属性,比方说是否粗体,斜体等

UIBezierPath+YYAdd

Quartz

CALayer+YYAdd

YYCGUtilities

转载于:https://juejin.im/post/5a30e259f265da43176a2202

YYKit(Base模块)学习笔记相关推荐

  1. python模块学习笔记

    python模块学习笔记 1.Python自动发送邮件smtplib 2.制作二维码图片MyQR 3.绝对值模块math 4.CSV模块 5.openpyxl 模块,操作Excel文件 ExcelMa ...

  2. cma linux 起始地址,CMA模块学习笔记

    CMA模块学习笔记 作者:linuxer 发布于:2017-6-28 18:29 分类:内存管理 前言 本文是近期学习CMA模块的一个学习笔记,方便日后遗忘的时候,回来查询以便迅速恢复上下文. 学习的 ...

  3. Arduino模块学习笔记(一)—GPS模块的使用

    Arduino模块学习笔记(一)--GSP模块的使用 文章目录 Arduino模块学习笔记(一)--GSP模块的使用 所需组件 一.模块使用介绍 1.GPS模块(在室内时,一般获取不到位置信息) 2. ...

  4. Python模块之Pandas模块学习笔记

    目录 一.模块的安装 二.数据结构 1. DataFrame的创建 2. DataFrame索引的修改 3. DataFrame数据信息查看 三.文件的读取和写入 1. 读取 2. 写入 四. 数据的 ...

  5. IPy-IPv4和IPv6地址处理模块学习笔记

    在日常网络规划中,会有很多关于IP地址的分配规划问题,如果是手动分配,在量很大的情况下,容易出错.而利用IPy这个python模块,可以很容易实现对iP地址的分配等操作. 以下是对IPy模块学习的一个 ...

  6. 《西游降魔录》模块学习笔记

    <三维游戏设计师宝典3>附带的光盘是错位的给的不是书中的例子所对应的光盘具体原因不得而知.尽管如此,该错位的光盘却有个非常好的例子<西游降魔录> 的游戏,前两天尝试着写了点自己 ...

  7. 启英泰伦cl1122模块学习笔记

    笔记目录 前言 一.CI1122芯片与其它型号对比 二.资料获取 1.启英泰伦语音AI平台 文档中心: 软硬件开发资料以及平台的使用方法 开发资料: SDK和固件下载,相关开发工具的下载,开发板的硬件 ...

  8. LCD1602液晶显示模块学习笔记

    LCD1602液晶显示模块 一.初识LCD602 1.1.实物图 1.2.引脚图 1.3.引脚功能说明 二.显示位置 三.显示内容 四.指令集 五.工作时序 5.1.写操作时序 5.2.读操作时序 六 ...

  9. NOKIA5110液晶显示模块学习笔记

    现在我们的嵌入式课程设计要求做一个超声波测距的倒车雷达,总体不是很难,但是其中要求的NOKIA显示屏从来没有接触过,在CSDN上也很难找到免费的比较完整的资料,因此就想把这部分的学习过程记录下来,分享 ...

  10. openFOAM combustion模块学习笔记——程序结构

    基础资料 废话不多说,首先罗列一些笔者参考的资料 openFOAM的官方网站为:https://openfoam.org/ 东岳流体网站:http://www.dyfluid.com/ 本文使用的为o ...

最新文章

  1. 你写代码,难道是因为热爱吗?
  2. POJ 1195 Mobile phones
  3. 射频篇(三) 模拟、射频器件学习(3) ——锁相环(PLL)
  4. LINUX下邮件服务器
  5. ipad4没有声音提示消息
  6. GIT项目管理工具(part6)--放弃工作区文件修改及从仓库区恢复文件
  7. quick cocos2d-x 精灵大小(宽高)获取
  8. 前端学习(3164):react-hello-react之添加todoList
  9. linux 下的csp 模块,linux kernel 中MIGRATE_TYPES的理解
  10. HDU2206 IP的计算【文本处理】
  11. VMware centos7镜像安装详细步骤
  12. 5分钟商学院-个人篇-沟通能力
  13. paypal如何退款
  14. 滴滴CTO张博港科大演讲:详解未来交通变革的三层“折叠”
  15. 2020最新版前端学习路线图--Javascript网页编程重点知识
  16. 【HTM】层级实时记忆脑皮质学习算法 一、当前进度
  17. 移动APP测试用例设计实践经验(转载)
  18. speedoffice(Excel)如何设置纸张大小
  19. 【Hack The Box】linux练习-- Jarvis
  20. matlab 与VS混合编程的几个问题

热门文章

  1. 十天学会单片机可能吗?单片机入门需要多久?
  2. mysql 序列号_mysql 序列号生成器(转)
  3. 28款数据恢复软件对比测试
  4. 网络端口扫描器程序设计
  5. 分享996个实用的JavaScript特效你要的全在这里
  6. 《UNIX网络编程 卷1》一、环境配置
  7. MSN蠕虫Myalbum2007.zip专杀工具
  8. pywifi 模块的安装
  9. Jenkins的定时构建与轮询SCM
  10. 【测试基础】Linux文本编辑vi命令