iOS 知识点总结

一、 instancetype和id的区别

1、instancetype在类型表示上,跟id一样,可以表示任何对象类型
2、instancetype只能用在返回值类型上,不能像id一样用在参数类型上
3、instancetype比id多一个好处:编译器会检测instancetype的真实类型
注:作为返回值时,凡是用id的地方,都建议换成instancetype

二、属性的本质

@property = ivar + getter + setter;
实例变量+ setter方法+ setter方法,也就是说使用@property 系统会自动生成成员变量、setter和getter方法;

三、@synthesize 和 @dynamic 分别有什么作用

  • @property 有两个对应的词,分别是 @synthesize和 @dynamic。如果@synthesize 和 @dynamic 都没写,默认的就是 @syntheszie var = _var;
  • @synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。
  • @dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为 @dynamic var,然后你没有提供 @setter 方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

四、atomic

atomic的本意是指属性的存取方法是线程安全的,并不保证整个对象是线程安全的,在多线程中,atomic只保证getter、setter方法安全,并不保证其它操作,例如字符串拼接,数组移除元素等,并没有执行getter和setter方法,顾不是绝对安全的。

五、Block本质

  • block本质上也是一个OC对象,它内部也有个isa指针
  • block是封装了函数调用以及函数调用环境的OC对象
  • block是封装函数及其上下文的OC对象
3066088-1f0f23fe32523bce.png
image.png
  • auto变量block访问方式是值传递,auto自动变量可能会销毁的,内存可能会消失,不采用指针访问;
  • static变量block访问方式是指针传递,static变量一直保存在内存中,指针访问即可;
  • block不需要对全局变量捕获,都是直接采用取值的


    3066088-d16cb90dfdc005e7.png
    image.png
  • block里访问self会被捕获:self是当调用block函数的参数,参数是局部变量,self指向调用者
  • block里访问成员变量会被捕获:成员变量的访问其实是self->xx,先捕获self,再通过self访问里面的成员变量

block三种类型:

1、__NSGlobalBlock __ 在数据区 :没有访问auto变量的block是__NSGlobalBlock __ ,放在数据段;调用copy操作后,什么也不做
2、__NSMallocBlock __ 在堆区 : [__NSStackBlock __ copy]操作就变成了__NSMallocBlock __ ;复制效果是:引用计数增加,副本存储位置是堆
3、__NSStackBlock __ 在栈区 : 访问了auto变量的block是__NSStackBlock __ ;调用copy操作后,复制效果是:从栈复制到堆;副本存储位置是堆

在ARC环境下,编译器会根据一下几种情况自动将栈上的block复制到堆上:

1、block作为函数返回值时
2、将block赋值给__strong指针时
3、block作为Cocoa API中方法名含有usingBlock的方法参数时
4、block作为GCD API的方法参数时

当block内部访问了对象类型的auto变量时:

如果block在栈空间,不管外部变量是强引用还是弱引用,block都会弱引用访问对象
如果block在堆空间,如果外部强引用,block内部也是强引用;如果外部弱引用,block内部也是弱引用。
栈block:
a) 如果block是在栈上,将不会对auto变量产生强引用
b) 栈上的block随时会被销毁,也没必要去强引用其他对象
堆block:
1.如果block被拷贝到堆上:
a) 会调用block内部的copy函数
b) copy函数内部会调用_Block_object_assign函数
c) _Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用
2.如果block从堆上移除
a) 会调用block内部的dispose函数
b) dispose函数内部会调用_Block_object_dispose函数
c) _Block_object_dispose函数会自动释放引用的auto变量(release)

__block 修饰符作用:

  • __block可以用于解决block内部无法修改auto变量值的问题
  • __block不能修饰全局变量、静态变量(static)
  • 编译器会将__block变量包装成一个对象
  • __block修改变量:age->__forwarding->age
  • __Block_byref_age_0结构体内部地址和外部变量age是同一地址

六、NSCache和NSMutableDictionary的相同点与区别:

相同点:
NSCache和NSMutableDictionary功能用法基本是相同的。
区别:
NSCache是线程安全的,NSMutableDictionary线程不安全
NSCache线程是安全的,Mutable开发的类一般都是线程不安全的
当内存不足时NSCache会自动释放内存(所以从缓存中取数据的时候总要判断是否为空)
NSCache可以指定缓存的限额,当缓存超出限额自动释放内存
缓存限额:
缓存数量
@property NSUInteger countLimit;
缓存成本
@property NSUInteger totalCostLimit;
苹果给NSCache封装了更多的方法和属性,比NSMutableDictionary的功能要强大很多

七、runtime通过selector找到对应的IMP地址的两种方式

方式一:

类方法(假设有一个类 A)
class_getMethodImplementation(objc_getMetaClass("A"),@selector(methodName));
实例方法
class_getMethodImplementation([A class],@selector(methodName));

方式二:

类方法
Method class_getClassMethod(Class cls, SEL name)

实例方法
Method class_getInstanceMethod(Class cls, SEL name)

最后调用IMP method_getImplementation(Method m) 获取IMP地址

八、避免设置圆角引起离屏渲染的优化

方式一:使用贝塞尔曲线UIBezierPath和Core Graphics框架画出一个圆角

UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];       
imageView.image = [UIImage imageNamed:@"myImg"];        
//开始对imageView进行画图        
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);        
//使用贝塞尔曲线画出一个圆形图        
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds cornerRadius:imageView.frame.size.width] addClip];       
 [imageView drawRect:imageView.bounds];       
imageView.image = UIGraphicsGetImageFromCurrentImageContext();       
//结束画图        
UIGraphicsEndImageContext();       
[self.view addSubview:imageView];

方式二:使用CAShapeLayer和UIBezierPath设置圆角

 UIImageView *imageView=[[UIImageView alloc]initWithFrame:CGRectMake(100,100,100,100)];
 imageView.image = [UIImage imageNamed:@"myImg"];
 UIBezierPath *maskPath=[UIBezierPath bezierPathWithRoundedRect:imageView.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:imageView.bounds.size];
 CAShapeLayer *maskLayer= [[CAShapeLayer alloc]init];
 //设置大小
 maskLayer.frame=imageView.bounds;
 //设置图形样子
 maskLayer.path=maskPath.CGPath;
 imageView.layer.mask=maskLayer;
 [self.view addSubview:imageView];

九、使用ShadowPath指定layer阴影效果路径避免离屏渲染

imageView.layer.shadowColor=[UIColor grayColor].CGColor;        
imageView.layer.shadowOpacity = 1.0;        
imageView.layer.shadowRadius = 2.0;        
UIBezierPath *path = [UIBezierPath bezierPathWithRect:imageView.frame]; 
imageView.layer.shadowPath = path.CGPath;

转载于:https://www.jianshu.com/p/caa4e6b5abad

猜你喜欢

转载自blog.csdn.net/weixin_33873846/article/details/91254029