1、网络层和业务层的对接设计
2、网络层的安全防范
1、MVC 模式存在 Controller 中代码臃肿的问题
之所以会出现 MVC 模式,是因为发现在开发中会有很多代码可以进行复用,同时事实也正是如此,MVC 三个没款中,Model 和 View 的代码确实可以因为 MVC 模式而进行复用,在 github 上也有很多开源的项目中封装了很多 View,我们可以很方便得使用这些 view,model 类作为一个数据转化逻辑的类也可以在同一个项目中进行多次复用,但是 Controller 却很难在一个项目中进行复用,所以我们在写代码的时候尽量在 Controller 中只写那些无法复用的代码,例如将 view 添加到 controller 上,将 model 的数据传给 view 等等,但是实际上很难做到这一点,往往有很多代码我们都不知道放在哪里,到了最后便放在了 controller 里面,导致 controller 变得十分臃肿。
2、对 MVC 模式中的 Controller 进行瘦身
我们可以从下面几点对 Controller 进行瘦身:
3、MVVM 模式的认知
4、总结
应该结合 MVC 和 MVVM 的各自的优点去让 Controller 进行瘦身,而不应该盲目地去追求新技术,亦或是过于保守,不愿意向前发展。
1、常规的设置方式带来的性能损耗
使用 cornerRadius 属性设置圆角是不会产生离屏渲染的,同时也不会真正在 UI 上产生圆角,这时候我们需要将 masksToBounds 设置为 YES,才能够产生在 UI 上的圆角效果,但是同时,这样也会导致离屏渲染。产生离屏渲染对于性能上有很大的消耗,将会降低 FPS 帧数,原因是因为离屏渲染需要将图像的处理放在屏幕之外的内存缓存区进行处理,处理结束之后才把得到的图像放到主屏幕上。在这个过程中产生最大消耗的是两次上下文的交互,将处理放到屏幕之外的缓存区,然后把得到的图像放到主屏幕上。
2、使用不产生离屏渲染的方式来创造圆角
使用贝塞尔曲线 UIBezierPath 和 Core Graphics 框架画出一个圆角
- UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)]; imageView.image = [UIImage imageNamed:@"1"]; //开始对imageView进行画图
- UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, [UIScreen mainScreen].scale); //使用贝塞尔曲线画出一个圆形图
- [[UIBezierPath bezierPathWithRoundedRect:imageView.bounds cornerRadius:imageView.frame.size.width] addClip];
- [imageView drawRect:imageView.bounds];
- imageView.image = UIGraphicsGetImageFromCurrentImageContext(); //结束画图
- UIGraphicsEndImageContext();
- [self.view addSubview:imageView];
3、总结
创建一个背景和新的 UIImageView,UIImageView 是位于背景之上的,先把背景的透明度改为 0,然后进行动画,动画的效果是将新的 UIImageView 从原始的位置(这个位置是原来的 UIImageView 在新的背景上对应的 frame)变化到放大的位置,然后监听背景的点击事件,点击的时候进行透明度和 frame 的相反变化即可。具体过程我封装好了上传到 Github 了,
这里将会涉及到 JSPatch 这个框架的使用,这个框架的作用就是对 bug 进行热修复.. 后续更新
1、block
2、delegate
3、NSTimer
解决办法:使用一个 NSTimer 的 Catagory,然后重写初始化方法,在实现中利用 block,从而在调用的时候可以使用 weakSelf 在 block 执行任务
请查看这篇文章,讲得很深入:
列举的顺序就是修饰符在声明的时候的顺序
1、原子性修饰符
2、读写权限修饰符
3、内存管理修饰符
4、读写方法名修饰符
例如上面的代码,使用 strong 表示的是 self.name 和 anotherName 这两个指针同时指向了一个对象,过程是 self.name 指向了 anotherName 指向的对象,而如果使用 copy 的话,self.name 和 anotherName 这两个指针同时指向了不同的对象,过程是 copy 会将 anotherName 所指向的对象拷贝一份出来(浅拷贝),然后让 self.name 指向这个被拷贝出来的对象。
- self.name = anotherName;
1、pthread
基于 C 语言,不常用
2、NSThread
需要自己手管理线程的生命周期,偶尔使用,例如获取当前线程
- [NSThread currentThread];
3、GCD(Grand Central Dispatch)
GCD 是苹果开发出来的多核编程的解决方案,虽然是基于 C 语言的,但是采用了 block 进行封装,使用起来也很方便,同时也很重要,推荐使用 GCD 进行多线程编程
4、NSOperation
是苹果对于 GCD 的封装,效率不及 GCD
主队列:是一个特殊的串行队列,在主线程中运行,用于刷新 UI,是一个串行队列
- //串行队列
- dispatch_queue_t queue = dispatch_get_main_queue;
自定义创建队列: 既可以创建串行队列也可以创建并行队列。
- //串行队列
- dispatch_queue_t queue = dispatch_queue_create("nineteen", NULL);
- dispatch_queue_t queue = dispatch_queue_create("nineteen", DISPATCH_QUEUE_SERIAL);
- //并行队列
- dispatch_queue_t queue = dispatch_queue_create("nineteen", DISPATCH_QUEUE_CONCURRENT);
全局并行队列:系统提供的并行队列
- //并行队列
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
循环执行任务:dispatch_apply 类似一个 for 循环,并发地执行每一项。所有任务结束后,dispatch_apply 才会返回,会阻塞当前线程(类似同步执行)。
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- /*
- *count: 循环执行次数
- *queue: 队列,可以是串行队列或者是并行队列(使用串行队列可能导致死锁)
- *block: 任务
- */
- dispatch_apply(count, queue, ^(size_t i) {
- NSLog(@"%zu %@", i, [NSThread currentThread]);
- });
队列组:队列组将很多队列添加到一个组里,当组里所有任务都执行完后,它会通过一个方法通知我们。基本流程是首先创建一个队列组,然后把任务添加到组中,最后等待队列组的执行结果。
- //创建队列组
- dispatch_group_t group = dispatch_group_create();
- //创建队列
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- //并行队列执行3次循环 (队列组只能用异步方法执行)
- dispatch_group_async(group, queue, ^{
- for (NSInteger i = 0; i < 3; i++) {
- NSLog(@"group-01 - %@", [NSThread currentThread]);
- }
- });
- //主队列执行5次循环
- dispatch_group_async(group, dispatch_get_main_queue(), ^{
- for (NSInteger i = 0; i < 5; i++) {
- NSLog(@"group-02 - %@", [NSThread currentThread]);
- }
- });
- //都完成后会自动通知
- dispatch_group_notify(group, dispatch_get_main_queue(), ^{
- NSLog(@"完成 - %@", [NSThread currentThread]);
- });
实现单例模式
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- //dispatch_once中的代码只执行一次,常用来实现单例
- });
GCD 延迟操作
- //创建队列
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- //设置延时,单位秒
- double delay = 3;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{
- //3秒后需要执行的任务
- });
五个案例了解 GCD 的死锁
1、
案例:
- NSLog(@"1"); // 任务1
- dispatch_sync(dispatch_get_main_queue(), ^{
- NSLog(@"2"); // 任务2
- });
- NSLog(@"3"); // 任务3
结果:
- 1
2、
案例:
- NSLog(@"1"); // 任务1
- dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
- NSLog(@"2"); // 任务2
- });
- NSLog(@"3"); // 任务3
结果:
- 1
- 2
- 3
3、
案例:
- dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);
- NSLog(@"1"); // 任务1
- dispatch_async(queue, ^{
- NSLog(@"2"); // 任务2
- dispatch_sync(queue, ^{
- NSLog(@"3"); // 任务3
- });
- NSLog(@"4"); // 任务4
- });
- NSLog(@"5"); // 任务5
结果:
- 1
- 5
- 2
- // 5和2的顺序不一定
4、
案例:
- NSLog(@"1"); // 任务1
- dispatch_async(dispatch_get_global_queue(0, 0), ^{
- NSLog(@"2"); // 任务2
- dispatch_sync(dispatch_get_main_queue(), ^{
- NSLog(@"3"); // 任务3
- });
- NSLog(@"4"); // 任务4
- });
- NSLog(@"5"); // 任务5
结果:
- 1
- 2
- 5
- 3
- 4
- // 5和2的顺序不一定
5、
案例:
- dispatch_async(dispatch_get_global_queue(0, 0), ^{
- NSLog(@"1"); // 任务1
- dispatch_sync(dispatch_get_main_queue(), ^{
- NSLog(@"2"); // 任务2
- });
- NSLog(@"3"); // 任务3
- });
- NSLog(@"4"); // 任务4
- while (1) {
- }
- NSLog(@"5"); // 任务5
结果:
- 1
- 4
- // 1和4的顺序不一定
如果加锁操作处于一个循环或者递归中,在第一次加锁还没有解锁的时候,就进行了第二次加锁,所以就造成死锁现象,这时候应该使用递归锁来防止死锁的发生。
ARC 会自动处理对象的声明周期,编译的时候在合适的地方插入内存管理代码
一般主线程会自动运行 RunLoop,我们一般情况下不会去管。在其他子线程中,如果需要我们需要去管理。使用 RunLoop 后,可以把线程想象成进入了一个循环;如果没有这个循环,子线程完成任务后,这个线程就结束了。所以如果需要一个线程处理各种事件而不让它结束,就需要运行 RunLoop。
- - (void)start{
- ...
- self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
- ...
- if(self.connection){
- ...
- CFRunLoopRun( )
- ...
- }
- }
- - (void)cancelInternalAndStop {
- if (self.isFinished) return;
- [self cancelInternal];
- CFRunLoopStop(CFRunLoopGetCurrent());
- }
在创建 self.connection 成功后,执行了 CFRunLoopRun(),开启了 runloop。在 failed 或 finished 的时候会调用 CFRunLoopStop 停止 runloop。如果不开启 runloop 的话,在执行完 start () 后任务就完成了,NSURLConnection 的代理就不会执行了。runloop 相当于子线程的循环,可以灵活控制子线程的生命周期。
AFNetworking 解决这个问题采用了另一种方法:单独起一个 global thread,内置一个 runloop,所有的 connection 都由这个 runloop 发起,回调也都由它接收。这是个不错的想法,既不占用主线程,又不耗 CPU 资源:
来源: http://www.bubuko.com/infodetail-1988450.html