OC基础知识总结二

本文深入探讨了iOS开发中的关键技术概念,如GPU渲染机制、离屏渲染的影响及优化方法,Objective-C中的内存管理策略,以及MVC等设计模式的应用。同时介绍了不同属性关键字的作用和区别,提供了运行时(runtime)技术的实际应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、什么是GPU?什么是离屏渲染?

GPU(Graphic Processing Unit)“图形处理器”,GPU屏幕渲染有两种方式:
1、On-Screen Rendering (当前屏幕渲染)
指的是GPU的渲染操作是在当前屏幕缓冲区中进行。

2、Off-Screen Rendering (离屏渲染)
渲染发生在当前屏幕之外。将渲染结果临时保存(创建缓冲区),等到要用时再取出(需要切换上下文),创建缓冲区和切换上下文都会影响性能。(也可以这么说:GPU在当前屏幕缓冲区以外开辟一个缓冲区进行渲染操作。)
3、优缺点
当前屏幕渲染不需要额外创建新的缓存,也不需要开启新的上下文,相对于离屏渲染性能更好。但是受当前屏幕渲染的局限因素限制(只有自身上下文、屏幕缓存有限等),当前屏幕渲染有些情况下的渲染解决不了的,就使用到离屏渲染。

4、特殊的“离屏渲染”:CPU渲染
如果我们重写了drawRect方法,并且使用任何Core Graphics的技术进行了绘制操作,就涉及到了CPU渲染。整个渲染过程由CPU在App内同步地完成,渲染得到的bitmap(位图)最后再交由GPU用于显示。

5、优化方案:
iOS 9.0 之后UIButton设置圆角会触发离屏渲染,而UIImageView里png图片设置圆角不会触发离屏渲染了,如果设置其他阴影效果之类的还是会触发离屏渲染的。
UIButton的效果,可以设置阴影和圆角显示,但是如果layer树中的某个layer设置了圆角,树中所有layer的阴影效果 都将显示不了了。如果既想有圆角又想要阴影,好像只能做两个重叠的UIView,一个的layer显示圆角,一个的layer显示阴影.....
UIButton设置圆角+阴影

 CALayer *layer = [CALayer layer];
    layer.frame = CGRectMake(100, 300, 100, 100);
    layer.backgroundColor = [UIColor blackColor].CGColor; 
    layer.shadowOffset = CGSizeMake(10, 10);    
    layer.shadowOpacity = 0.7;  
    layer.cornerRadius = 10;    
    //这里self表示当前自定义的view    
    [self.view.layer addSublayer:layer];

    UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(100, 300, 100, 100)];
    [button addTarget:self action:@selector(shadowClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];    
    button.layer.masksToBounds =YES;    
    button.layer.cornerRadius =10;

6、view的drawRect集成于CoreGraphics走的是CPU ,消耗性能较大、

7、动画避免离屏渲染的方法:
* CALayer属于CoreAnimation与被萨尔曲线可以实现不在view的drawRect方法中换出一些想要的图形。
* CAShapeLayer动画渲染直接提交到手机的GPU中,相较于view的drawRect方法使用CPU渲染而言,效率极高,能大大优化内存使用情况。
知识点链接:https://www.jianshu.com/p/492a151ba25b

2、new和alloc/init的区别?

概括来说,new和alloc/init在功能上几乎是一致的,分配内存并完成初始化。
差别在于,采用new的方式只能采用默认的init方法完成初始化,
采用alloc的方式可以用其他定制的初始化方法。

3、@class和 #import的区别?

@class class1只是告诉编译器,class1是一个类,你不要以为class1是个未声明的野类,除此之外,没了。
但是 #import “class1.h”会告诉编译器,class1这个类中有什么东西,即class1.h中包含的函数和变量。
所以.h中使用@class绰绰有余,若你有需要创建或访问class1中的函数和变量,则必须使用#import。

4、简述一下MVC、MVP、MVVM?

MVC:当用户出发事件的时候,view层会发送指令到controller层,接着controller去通知model层更新数据,model层更新完数据以后直接显示在view层上,这就是MVC的工作原理。
如何理解MVVM设计模式
ViewModel层,就是View和Model层的粘合剂,他是一个放置用户输入验证逻辑,视图显示逻辑,发起网络请求和其他各种各样的代码的极好的地方。说白了,就是把原来ViewController层的业务逻辑和页面逻辑等剥离出来放到ViewModel层。
View层,就是ViewController层,他的任务就是从ViewModel层获取数据,然后显示。
链接:https://www.jianshu.com/p/ed2d3c1faaaa

5、属性实质是什么?默认关键字是什么?

属性是描述类的特征,也就是具备什么特性。包括三个部分,带下划线的成员变量,get、setter方法。
默认的属性关键字分两种情况:
一种是基本数据类型,一种是OC普通对象。不管哪种情况默认都有atomic原子属性和readwrite可读写属性,区别是基本数据类型默认是有个assign属性关键字,而OC对象对应的默认有个strong属性关键字。

基本数据类型的默认关键字有:atomic,readwrite,assign
普通OC对象的默认关键字有:atomic,readwrite,strong

6、#include和#import的区别是什么?

#include是c/c++导入头文件的关键字,#import 是oc导入头文件的关键字,#import会自动导入一次,不会重复导入,不会引起交叉编译。

7、weak&assign的不同点:

1、weak策略在属性所指的对象遭到摧毁时,系统会将weak修饰的属性对象的指针指向nil,OC给nil发消息不会有问题。
2、如果使用assign策略在属性所指的对象遭到摧毁时,属性对象指针还指向原来的对象,由于对象的已经被销毁,这时候就产生了野指针,如果这时候再给此对象发送消息,很容易造成程序崩溃,assign可以用于修饰非OC对象,而weak必须用于OC对象。
野指针:指向一个已释放的对象或没有访问权限的内存的指针。
https://www.jianshu.com/p/8b3cf2187255

8、什么是堆?什么是栈?

堆栈是两种数据结构。
堆先进先出,栈先进后出。
空间分配:
栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
缓存方式:
栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。
堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。

9、哈希表怎么实现

哈希表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。

10、NSNotification、Block、Delegate和KVO的区别?

代理是一种回调机制,且是一对一的关系,通知是一对多的关系,一个对向所有的观察者提供变更通知;
效率:Delegate比NSNOtification高;
Delegate和Block一般是一对一的通信;
Delegate需要定义协议方法,代理对象实现协议方法,并且需要建立代理关系才可以实现通信;
Block : Block更加简洁,不需要定义繁琐的协议方法,但通信事件比较多的话,建议使用Delegate;

11、runtime的使用场景?

1、方法交换。(无埋点hook方法、监控控件的点击)。
2、增加类别属性。(objc_getAssicoate,set,并设置属性关键字)
3、获取类的所有属性和成员变量。字典转模型。典型为MJExtention

13、问题:苹果是如何实现Autorelease Pool的?

解答:Autorelease Pool作用:缓存池,可以避免我们经常写relase的一种方式。其实就是延迟release,将创建的对象,添加到最近的autoreleasePool中,等到autoreleasePool作用域结束的时候,会将里面所有的对象的引用计数器 - autorelease.
链接:https://www.jianshu.com/p/c3a5ffcd856b

14、给类动态的添加weak修饰的属性?

首先,给 Category 属性是需要使用runtime中的关联来实现set 和 get 方法。但runtime只提供如下几种修饰实现,并没有weak。
思路是这样的,虽然runtime没有开放weak解决方案,但OBJC对象是可以实现weak的,所以让需要被修饰的对象去持有一个strong的对象,然后当被修饰的对象被释放的时候,持有的对象也会被释放,那么我们就可以捕捉到释放的事件,进而使用OBJC_ASSOCIATION_ASSIGN 来实现弱引用,在释放事件里面再将其释放掉,进而实现weak功能。
// 这里关联的key必须唯一,如果使用_cmd,对一个对象多次关联的时候,前面的对象关联会失效。
https://blog.youkuaiyun.com/yan_1564335/article/details/53996538

15、输出值

1、a代表有5个元素的数组的首地址,a[5]的元素分别是1, 2, 3, 4, 5。
2、a+1表示数据首地址+1,那么就是a[1],也就是对应值为2。
3、(&a + 1),因为a代表的是整个数组,它的空间大小为5*sizeof(int),因此&a + 1就是a+5。为什么呢?
因为:a是个常量指针,指向当前数组的首地址,指针+1就是移动sizeof(int)个字节。所以就指向了数组(a[4])后面的一个位置a[5],超出了数组的范围,所以指向的值就不确定是多少了,出现随机值。
4、此时ptr是指向int *类型的指针,指向的就是a+5,那么ptr+1就相当于a+6,超出了数组范围就是一个随机值了。

```
int a[5] = {1, 2, 3, 4, 5};
int *ptr = (int *)(&a + 1);
NSLog(@"---------%d, ----------%d", *(a + 1), *(ptr + 1));
```

输出结果如下:

---------2, -----------1689714611
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值