iOS补充知识

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等底层实现


iOS补充知识_第1张图片

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

你可能感兴趣的:(iOS补充知识)