因为篇幅问题,会分三篇描述对应不一样内容。辅助工具,底层原理,开发中要注意问题三个方面,谈谈对应的总结。本人以为书只是一个索引,特别对于技术类书籍,基本都是经过书籍引入一些观点,而后在经过其它第三方途径进行扩展。因此本文描述内容不必定就是书本内容,会与自身实践经验,还有部份内容精简和拓展。有些基础概念第三方描述已足够详细,实例也足够详细,本文仅仅提出一些我的总结理解,不在重复描述具体功能原理。html
文字不如图片直观,因此先上一张本系列描述的观点的思惟导图,梳理脉络。红色部分为本文内容梳理。ios
《思惟导图连接(点我打开)最新版本》objective-c
在Objective-C中,任何类的定义都是对象。类和类的实例(对象)没有任何本质上的区别。编程
isa:是一个Class 类型的指针. 每一个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从自己查找类方法的实现,若是没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向自己,这样造成了一个封闭的内循环。异步
类比8位MCU的pc指针,我我的理解isa指针,在硬件层面上就是指向代码的运行地址能够试RAM地址或ROM地址,等同MCU汇编的PC指针,调用函数时,须要先把当前函数地址压入堆栈,燃后放置新地址到PC指针,而后退去取回原堆栈内的地址。可是OC isa 在这个基础上增长了继承的概念。async
如下是实例引用流程:编程语言
每个对象本质上都是一个类的实例。其中类定义了成员变量和成员方法的列表。对象经过对象的isa指针指向类。函数
每个类本质上都是一个对象,类实际上是元类(meteClass)的实例。元类定义了类方法的列表。类经过类的isa指针指向元类。工具
全部的元类最终继承一个根元类,根元类isa指针指向自己,造成一个封闭的内循环。atom
指一个程序在运行(或者在被执行)的状态。也就是说,当你打开一个程序使它在电脑上运行的时候,那个程序就是处于运行时刻。在一些编程语言中,把某些能够重用的程序或者实例打包或者重建成为“运行库"。这些实例能够在它们运行的时候被链接或者被任何程序调用。
objective-c中runtime:是一套比较底层的纯C语言API, 属于1个C语言库, 包含了不少底层的C语言API。 在咱们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码。
RunTime基本经常使用法 (《iOS开发进阶》页码:220 - 225 ps:这里说得不够细)
//1 动态增长变量 @property (nonatomic, assign) BOOL isNotIgnore; //runtime 动态绑定 属性 - (BOOL)isNotIgnore{ //_cmd == @select(isIgnore); 和set方法里一致 return [objc_getAssociatedObject(self, _cmd) boolValue]; } - (void)setIsNotIgnore:(BOOL)isNotIgnore{ // 注意BOOL类型 须要用OBJC_ASSOCIATION_RETAIN_NONATOMIC 不要用错,不然set方法会赋值出错 objc_setAssociatedObject(self, @selector(isNotIgnore), @(isNotIgnore), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } //2 对象方法的交换 /** * 对象方法的交换 * * @param anClass 哪一个类 * @param method1Sel 方法1 * @param method2Sel 方法2 */ + (void)exchangeInstanceMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel { Method method1 = class_getInstanceMethod(anClass, method1Sel); Method method2 = class_getInstanceMethod(anClass, method2Sel); method_exchangeImplementations(method1, method2); } //3 动态类方法的交换 /** * 类方法的交换 * * @param anClass 哪一个类 * @param method1Sel 方法1 * @param method2Sel 方法2 */ + (void)exchangeClassMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel { Method method1 = class_getClassMethod(anClass, method1Sel); Method method2 = class_getClassMethod(anClass, method2Sel); method_exchangeImplementations(method1, method2); } //4 动态类方法的交换 /** * 对象方法重置 * * @param anClass 哪一个类 * @param method1Sel 方法1 */ + (void)setClassMethod:(Class)anClass oldMethodSel:(SEL) oldMethodSel newMethodSel:(SEL)newMethodSel { Method oldMethod = class_getInstanceMethod(anClass, oldMethodSel); Method newMethod = class_getInstanceMethod(anClass, newMethodSel); method_setImplementation(oldMethod, method_getImplementation(newMethod)); }
这个概念其实对应如今已经有点老了,32为设备已在苹果放弃支持的日程表上了。可是对于一些基础仍是有必要了解一下。简单就是在64位设备上,同一地址裂开2部分使用,那其中32位最基础值类保存,另外位数存指针,索引表之类的数据,复用一个地址上的存储空间。这点和mcu内存一个byte,低4位和高4分开存在2个0-16的数值,是相似的。
假设咱们要存储一个NSNumber对象,其值是一个整数。正常状况下,若是这个整数只是一个NSInteger的普通变量,那么它所占用的内存是与CPU的位数有关,在32位CPU下占4个字节,在64位CPU下是占8个字节的。而指针类型的大小一般也是与CPU位数相关,一个指针所占用的内存在32位CPU下为4个字节,在64位CPU下也是8个字节。
普通的iOS程序,若是没有Tagged Pointer对象,从32位机器迁移到64位机器中后,虽然逻辑没有任何变化,但这种NSNumber、NSDate一类的对象所占用的内存会翻倍
为了改进上面提到的内存占用和效率问题,苹果提出了Tagged Pointer对象。因为NSNumber、NSDate一类的变量自己的值须要占用的内存大小经常不须要8个字节,拿整数来讲,4个字节所能表示的有符号整数就能够达到20多亿(注:2^31=2147483648,另外1位做为符号位),对于绝大多数状况都是能够处理的。
__block修饰变量,在block中,使用能直接改变变量的值。
没有__block修饰变量,在block使用,等于原变量copy了一个新变量,改变其值不影响原值。
这个问题出如今block替换代理时,引用变量致使控制器不释放比较常见。由于copy致使原变量引用加一。
因此block引用self,必须加上弱引声明。
__weak typeof(BaseViewController) *weakSelf = self;
本质缘由是由于对象和其余数据类型在系统中的存储空间不同,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的全部局部变量会被回收,指向对象的指针也被回收,此时对象已经没有指针指向,但依然存在于内存中,形成内存泄露。
每一个OC对象都有本身的引用计数器,是一个整数表示对象被引用的次数,即如今有多少东西在使用这个对象。对象刚被建立时,默认计数器值为1,当计数器的值变为0时,则对象销毁。 在每一个OC对象内部,都专门有4个字节的存储空间来存储引用计数器。判断对象要不要回收的惟一依据就是计数器是否为0,若不为0则存在。
block中,因为对象会copy,全部会作成原变量引用加入,全部会致使不释放。
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(globalQueue, ^{ //子线程异步执行下载任务,防止主线程卡顿 NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"]; NSError *error; NSString *htmlData = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error]; if (htmlData != nil) { dispatch_queue_t mainQueue = dispatch_get_main_queue(); //异步返回主线程,根据获取的数据,更新UI dispatch_async(mainQueue, ^{ NSLog(@"根据更新UI界面"); }); } else { NSLog(@"error when download:%@",error); } });
- (void)groupSync { dispatch_queue_t disqueue = dispatch_queue_create("com.shidaiyinuo.NetWorkStudy", DISPATCH_QUEUE_CONCURRENT); dispatch_group_t disgroup = dispatch_group_create(); dispatch_group_async(disgroup, disqueue, ^{ NSLog(@"任务一完成"); }); dispatch_group_async(disgroup, disqueue, ^{ sleep(8); NSLog(@"任务二完成"); }); dispatch_group_notify(disgroup, disqueue, ^{ NSLog(@"dispatch_group_notify 执行"); }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ dispatch_group_wait(disgroup, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC)); NSLog(@"dispatch_group_wait 结束"); }); }
@property (nonatomic, strong) dispatch_block_t dispatch_stopLoading_block; @weakify(self) if (self.dispatch_stopLoading_block) { dispatch_block_cancel(self.dispatch_stopLoading_block); self.dispatch_stopLoading_block = NULL; } self.dispatch_stopLoading_block = dispatch_block_create(0, ^{ @strongify(self) NSLog(@"任务一完成"); }); //任务延迟启动 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), self.dispatch_stopLoading_block);
//因为设定的信号值为2,先执行两个线程,等执行完一个,才会继续执行下一个,保证同一时间执行的线程数不超过2。 -(void)dispatchSignal{ //crate的value表示,最多几个资源可访问 dispatch_semaphore_t semaphore = dispatch_semaphore_create(2); dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //任务1 dispatch_async(quene, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"run task 1"); sleep(1); NSLog(@"complete task 1"); dispatch_semaphore_signal(semaphore); });<br> //任务2 dispatch_async(quene, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"run task 2"); sleep(1); NSLog(@"complete task 2"); dispatch_semaphore_signal(semaphore); });<br> //任务3 dispatch_async(quene, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"run task 3"); sleep(1); NSLog(@"complete task 3"); dispatch_semaphore_signal(semaphore); }); }
原文:http://raychow.linkfun.top/2018/01/07/archives/1_ios/2017-section-2/index/