1、Hash方法与isEqual
1.1、== 运算符判断对象内存地址是否相同
1.2、isequal判断对象是否相同(自定义对象通常要重写isEqual方法)
1.3、hash方法通过hash计算会返回一个hash值(最好是唯一)
hash会在被添加到NSSet中调用:(要通过hash值查找新值是否已存在)
hash会在被设置为NSDictionary的key时调用:(利用hash值提高key的查找效率)
2、SDWebimage
判断当前图片类型:只判断图片二进制数据的第一个字节
默认的缓存周期:1周
缓存策略:默认情况下既做内存缓存又做磁盘缓存,下载图片前先检查内存缓存,再检查磁盘缓存
缓存的实现方式:采用了苹果推出的专门用来处理缓存的类NSCache
框架内部允许的最大并发数:6
对系统内存警告的处理方式:框架内部监听系统内存警告的通知,当发生后移除内存缓存中的所有对象
下载队列中对多个图片任务的处理方式:提供了FIFO和LIFO两种方式,默认为FIFO
如何下载图片:采用NSURLConnection发送网络请求,在其代理方法中接收数据并处理进度回调等工作
请求超时的设定:15秒
磁盘缓存图片的命名:以该图片的URL进行MD5散列加密【echo -n “url” |MD5】
缓存路径:~/Library/Caches/default/com.hackemist.SDWebImageCache.default
key—–>URL(如何优化):用黑名单(当一个URL请求失败后,会被添加到黑名单,可以有效的防止一个错误的URL被多次尝试下载)
3、哈希
散列算法就是一种以较短的信息来保证文件唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到逆向规律
4、NSdictionary 、KVO等底层实现
5、Block使用在ARC下, 以下几种情况, Block会自动被从栈复制到堆(默认情况下,block是存档在栈中,可能被随时回收,通过copy操作可以使其在堆中保留一份, 相当于一直强引用着):
1.被执行copy方法
2.作为 方法返回值
3.将Block赋值给附有__strong修饰符的id类型的类或者Blcok类型成员变量时
4.在方法名中含有usingBlock的Cocoa框架方法或者GDC的API中传递的时候.
6、SEL和IMP区别Class
SEL : 类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是方法编号。
IMP:一个函数指针,保存了方法的地址
也就是说方法编号SEL最后还是要通过Dispatch table表寻找到对应的IMP,IMP就是一个函数指针,然后执行这个方法
类在 Objective-C 也为我们准备了类似的机制, Class 类型。当一个类被正确的编译过后,在这个编译成功的类里面,存在一个变量用于保存这 个类的信息。我们可以通过一个普通的字符串取得 这个 Class,也可以通过我们生成的对象取 得这个 Class。Class 被成功取得之后,我们可以把这个 Class 当作一个已经定义好的类来使用 它。这样的机制允许我们在程序执行的过程当中,可以 Class 来得到对象的类,也可以在程序 执行的阶段动态的生成一个在编译阶段无法确定的一个对象。
7、GCD
实现A,B异步执行完后,执行C
方法一:
dispatch_barrier_async
在它前面的任务执行结束后它才执行,在它后面的任务等它执行完成后才会执行
-(void)barrier
{
// 这个队列【不能】使用全局并发队列
dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"----1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----2-----%@", [NSThread currentThread]);
});
// 在它前面的任务执行结束后它才执行,在它后面的任务等它执行完成后才会执行
dispatch_barrier_async(queue, ^{
NSLog(@"----barrier-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----3-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----4-----%@", [NSThread currentThread]);
});
}
方法二:
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 添加任务A到group
dispatch_group_async(group, queue, ^{
// 添加任务A到group
});
// 添加任务B到group
dispatch_group_async(group, queue, ^{
// 添加任务B到group
});
// 当任务A和任务B都执行完后到此来执行任务C
dispatch_group_notify(group, queue, ^{
// 如果这里还有基于上面两个任务的结果继续执行一些代码,建议还是放到子线程中,等代码执行完毕后在回到主线程
// 回到主线程
dispatch_async(group, dispatch_get_main_queue(), ^{
// 执行相关UI显示代码...
});
});
iOS中锁
1、@synchronized【性能较差】
只有当标识相同时,才为满足互斥,@synchronized指令实现锁的优点就是我们不需要在代码中显式的创建锁对象,便可以实现锁的机制,但作为一种预防措施,@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。
2、dispatch_semaphore
dispatch_semaphore_t signal = dispatch_semaphore_create(1);
dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(signal, overTime);
NSLog(@"需要线程同步的操作1 开始");
sleep(2);
NSLog(@"需要线程同步的操作1 结束");
dispatch_semaphore_signal(signal);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
dispatch_semaphore_wait(signal, overTime);
NSLog(@"需要线程同步的操作2");
dispatch_semaphore_signal(signal);
})
dispatch_semaphore是GCD用来同步的一种方式,与他相关的共有三个函数,分别是dispatch_semaphore_create,dispatch_semaphore_signal,dispatch_semaphore_wait。
(1)dispatch_semaphore_create的声明为:
dispatch_semaphore_t dispatch_semaphore_create(long value);
传入的参数为long,输出一个dispatch_semaphore_t类型且值为value的信号量。
值得注意的是,这里的传入的参数value必须大于或等于0,否则dispatch_semaphore_create会返回NULL。
(2)dispatch_semaphore_signal的声明为:
long dispatch_semaphore_signal(dispatch_semaphore_t dsema)
这个函数会使传入的信号量dsema的值加1;
(3) dispatch_semaphore_wait的声明为:
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
这个函数会使传入的信号量dsema的值减1;这个函数的作用是这样的,如果dsema信号量的值大于0,该函数所处线程就继续执行下面的语句,并且将信号量的值减1;如果desema的值为0,那么这个函数就阻塞当前线程等待timeout(注意timeout的类型为dispatch_time_t,不能直接传入整形或float型数),如果等待的期间desema的值被dispatch_semaphore_signal函数加1了,且该函数(即dispatch_semaphore_wait)所处线程获得了信号量,那么就继续向下执行并将信号量减1。如果等待期间没有获取到信号量或者信号量的值一直为0,那么等到timeout时,其所处线程自动执行其后语句。
dispatch_semaphore
是信号量,但当信号总量设为 1 时也可以当作锁来。在没有等待情况出现时,它的性能比 pthread_mutex
还要高,但一旦有等待情况出现时,性能就会下降许多。相对于 OSSpinLock 来说,它的优势在于等待时不会消耗 CPU 资源。
如上的代码,如果超时时间overTime设置成>2,可完成同步操作。如果overTime<2的话,在线程1还没有执行完成的情况下,此时超时了,将自动执行下面的代码。
3、NSLock
NSLock是Cocoa提供给我们最基本的锁对象,这也是我们经常所使用的,除lock和unlock方法外,NSLock还提供了tryLock和lockBeforeDate:两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),刚并不会阻塞线程,并返回NO。lockBeforeDate:方法会在所指定Date之前尝试加锁,如果在指定时间之前都不能加锁,则返回NO。
4、NSRecursiveLock递归锁
//NSLock *lock = [[NSLock alloc] init];
NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
static void (^RecursiveMethod)(int);
RecursiveMethod = ^(int value) {
[lock lock];
if (value > 0) {
NSLog(@"value = %d", value);
sleep(1);
RecursiveMethod(value - 1);
}
[lock unlock];
};
RecursiveMethod(5);
});
NSRecursiveLock实际上定义的是一个递归锁,这个锁可以被同一线程多次请求,而不会引起死锁。这主要是用在循环或递归操作中。
这段代码是一个典型的死锁情况。在我们的线程中,RecursiveMethod是递归调用的。所以每次进入这个block时,都会去加一次锁,而从第二次开始,由于锁已经被使用了且没有解锁,所以它需要等待锁被解除,这样就导致了死锁,线程被阻塞住了。
在这种情况下,我们就可以使用NSRecursiveLock。它可以允许同一线程多次加锁,而不会造成死锁。如果我们将NSLock代替为NSRecursiveLock,上面代码则会正确执行。
5、NSConditionLock条件锁
当我们在使用多线程的时候,有时一把只会lock和unlock的锁未必就能完全满足我们的使用。因为普通的锁只能关心锁与不锁,而不在乎用什么钥匙才能开锁,而我们在处理资源共享的时候,多数情况是只有满足一定条件的情况下才能打开这把锁
6、OSSpinLock
OSSpinLock 自旋锁,性能最高的锁。原理很简单,就是一直 do while 忙等。它的缺点是当等待时会消耗大量 CPU 资源,所以它不适用于较长时间的任务。 不过最近YY大神在自己的博客不再安全的 OSSpinLock中说明了OSSpinLock已经不再安全,请大家谨慎使用。
OSSpinLock和dispatch_semaphore的效率远远高于其他。
@synchronized和NSConditionLock效率较差。
Home push A 和Home present B,生命周期方法调用顺序
Home push A:
2017-08-22 15:54:41.491812 test[69211:12624968] A-viewDidLoad
2017-08-22 15:54:41.505239 test[69211:12624968] Home-viewWillDisappear
2017-08-22 15:54:41.505423 test[69211:12624968] A-viewWillAppear
2017-08-22 15:54:42.028112 test[69211:12624968] Home-viewDidDisappear
2017-08-22 15:54:42.028310 test[69211:12624968] A-viewDidAppear
Home Present B
2017-08-22 15:57:13.000129 test[69211:12624968] B-viewDidLoad
2017-08-22 15:57:13.005573 test[69211:12624968] Home-viewWillDisappear
2017-08-22 15:57:13.005740 test[69211:12624968] B-viewWillAppear
2017-08-22 15:57:13.509749 test[69211:12624968] B-viewDidAppear
2017-08-22 15:57:13.509927 test[69211:12624968] Home-viewDidDisappear