OC基础知识(面试必看)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_25639809/article/details/80001998

OC基础知识

一、属性和关键字
·成员变量与属性的区别:声明了@property并@synthesize后编译器会为实例变量生成getter和setter方法,成员变量用来存储属性的值

·修饰属性的关键字: atomic/nonatomic readwrite/readonly assign/weak retain/strong/copy/ (weak/strong只能在arc下使用)
引入其他文件中声明的全局变量时,使用extern 关键字
·属性默认修饰关键字:atomic,readwrite
·原子性操作:要么都执行,要么都不执行(atomic原子操作能保证多线程安全)
·野指针:用strong或者weak修饰的对象的retainCount为0时,属性会被置为nil,不会造成野指针,不会引起崩溃,而用retain/assign 修饰的对象retainCount为0时,是不会进行任何操作的,如果再用属性去调用该对象时,可能会有崩溃现象,野指针操作

·copy与strong的区别:copy会开辟新内存复制一份新的数据
·retain与strong的区别:strong只能在arc下使用,
·copy与mutablecopy的区别:
copy:对不可变对象copy是浅拷贝,对可变对象copy是深拷贝
mutableCopy:一定是深拷贝
(深拷贝时,copy出的是不可变对象,mutablecopy出的是可变对象)
自定义对象copy:遵守NSCopying,NSMutableCopying协议,实现copyWithZone mutableCopyWithZone 方法
NSArray用copy修饰,NSMutableArray用strong修饰

二、block和代理

“闭包(Closure)是由函数和与其相关的引用环境组合而成的实体.” block就是OC对闭包的实现
block 本质应该是一个函数指针加上一个对应捕获上下文变量的内存块(结构体或者类)
Block当做Objective-C的匿名函数
block是代码块,其本质和变量类似

1、什么是block?
block其实就是一个代码块,把你想要执行的代码封装在这个代码块里,等到需要的时候再去调用。那block是OC对象吗?答案是肯定的
2、block要用copy修饰,还是用strong
block变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆,所以说为了block属性声明和实际的操作一致,最好声明为copy。

在声明Block时,使用strong和retain会有截然不同的效果。strong等于copy,retain等于assign

3、block有几种
在 iOS中, block一共分三种。
(1)全局静态 block,不会访问任何外部变量,执行完就销毁。
(2)保存在栈中的 block,当函数返回时会被销毁,和第一种的区别就是调用了外部变量。
(3)保存在堆中的 block,当引用计数为 0 时会被销毁。例如按钮的点击事件,一直存在,即使执行过,也不销毁,因为按钮还可能被点击,持有按钮的View被销毁,它才会被销毁。

4、__block关键字的使用
在Block的{}体内,是不可以对外面的变量进行更改的,使用__block就能改变block块中变量的值

5、__block和__weak的区别 
(1)__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。 
(2)__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。 
(3)__block对象可以在block中被重新赋值,__weak不可以。 
(4)__block对象在ARC下可能会导致循环引用,非ARC下会避免循环引用,__weak只在ARC下使用,可以避免循环引用。

扫描二维码关注公众号,回复: 4509207 查看本文章

6、block与代理的区别:(都是一对一,通知是一对多)
(1)block 更轻型,使用更简单,代码易读,能够直接访问上下文,使用不当会造成循环引用
(2)代理降低了类之间的耦合性,它的相关代码会被分离到各处,没有 block 好读
(3)delegate运行成本低,block的运行成本高。block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是加计数,使用完或者block置nil后才消除。delegate只是保存了一个对象指针,直接回调
(4)如果回调只有一种或两种情况的时候,使用block进行回调比较方法,如果有多种回调情况的,采用协议代理

三、类和对象
·OC 中的拓展方法:类别、协议、延展、继承
//用类别可以添加属性,但是实现的时候要借助runtime 添加键值对和访问权限
//延展:选择性公开在原类实现文件中声明的成员变量、属性、和方法

·类别与继承的区别:
类别一般不能扩展类的属性
不改变原类的条件下,想类添加方法
类别可以把相关的方法分组到多个单独的文件中,便于管理

·类别与扩展的区别:
类别中原则上只能增加方法
扩展不仅可以增加方法,还可以增加属性;
扩展中声明的方法没被实现,编译器会报警;
扩展没有独立的实现部分,实现需在原类的.m文件中;且必须写在@implementation的上方
扩展添加的属性和方法属于私有属性和方法;
扩展只能针对自定义的类,不能给系统类增加类扩展

三、内存管理
基本数据类型的数据 内存在栈上,栈内存由系统去开辟和回收,对象类型的数据 内存在堆上,内存管理就是对对象的内存管理、对堆内存的管理(系统中有一个管理系统空闲空间的链表存放着空闲状态的内存,申请内存时 系统会遍历链表找到大于等于申请的内存的结点将该结点分配给发起申请的对象,并将该结点从存储空闲内存空间的链表中移除;释放一个对象时,对象占的内存回到空闲状态系统又会将对象的堆结点存入链表中,等待下一次分配)
·iOS内存管理:对象通过引用计数来进行内存管理,引用计数记录对象被几个指针引用。引用计数为零时对象就会被销毁。
·内存管理原则:谁创建,谁释放,谁引用,谁管理
·内存管理方式:ARC、MRC、autorelease(自动释放池)

·引用计数:继承NSObject的类都有一个引用计数器retainCount,用于记录当前被几个指针引用,引用计数为零时对象就会被销毁。
·autorelease:延迟释放,调用autorelease对象的retainCount 不会立刻减1,而是被添加到自动释放池管理延迟释放对象的数组,等待自动释放池执行结束时才会真正的释放 retainCount - 1

mrc:
-(void)setName:(NSString *)name {
if(_name){
[_name release]; //-1
}
_name = [name retain]; //+1
}
id obj = [[NSObject alloc]init];//获取引用计数
printf(“retain count = %ld\n”,CFGetRetainCount((__bridge CFTypeRef)(obj)));

·类方法创建的对象不需要手动release,原因是在类方法中添加了autorelease。缺点:不知道对象什么时候被释放,可能造成提前释放
·向数组/字典中添加对象时 对象的retainCount会加一,从数组/字典中移出对象,对象的retainCount会减一

Objective-C语言本身是支持垃圾回收机制的,但有平台局限性,仅限于Mac桌面系统开发中

四、设计模式

MVC、MVVM、单例、代理(@required、@optional)、工厂、观察者

·单例的写法
单例指的是某个类的对象,在整个程序运行期间,只被创建一次,并且在整个程序运行期间都不会被销毁,使用单例的优点:不用多次创建对象、整个工程都可以访问这个对象的数据,实现数据共享
缺点:单例对象在程序运行期间都不会被销毁,很多时候都占用内存,内存泄露问题(在工程中谨慎使用单例模式)
static Person * p = nil;

@implementation Person

//OC中最简单的单例实现方式,但是并不推荐这样去写,多线程环境下,这样是不能保证线程安全
+(instancetype)sharePerson{

if(!p){
    p = [[self alloc]init];
}
return p;

}

+(instancetype)defaultPerson{
//使用关键字对对象加锁,保证线程安全,这是苹果推荐的单例实现方法之一
@synchronized (p) {
if(p == nil){
p = [[Person alloc]init];
}
}
return p;
}

+(instancetype)currentPerson{
//采用GCD dispatch_once 保证创建对象的代码在整个程序运行期间只被执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if(p == nil){
p = [[Person alloc]init];
}
});
return p;
}

·MVC设计模式的缺点:
厚重的ViewController
遗失的网络逻辑(无立足之地)
较差的可测试性

· MVVM
MVVM将 Controller 中的展示逻辑抽取出来,放置到一个专门的地方,而这个地方就是 viewModel 。MVVM衍生于MVC,是对 MVC 的一种演进,它促进了 UI 代码与业务逻辑的分离。它正式规范了视图和控制器紧耦合的性质,并引入新的组件。
view 和 view controller正式联系在一起,我们把它们视为一个组件
view 和 view controller 都不能直接引用model,而是引用视图模型(viewModel)
viewModel 是一个放置用户输入验证逻辑,视图显示逻辑,发起网络请求和其他代码的地方
使用MVVM会轻微的增加代码量,但总体上减少了代码的复杂性

·MVVM 的优点
低耦合:View 可以独立于Model变化和修改,一个 viewModel 可以绑定到不同的 View 上
可重用性:可以把一些视图逻辑放在一个 viewModel里面,让很多 view 重用这段视图逻辑
独立开发:开发人员可以专注于业务逻辑和数据的开发 viewModel,设计人员可以专注于页面设计
可测试:通常界面是比较难于测试的,而 MVVM 模式可以针对 viewModel来进行测试

·MVVM 的缺点
数据绑定使得Bug 很难被调试。你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题。
对于过大的项目,数据绑定和数据转化需要花费更多的内存(成本)。

·观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式的实现有两种方法:Notification、KVO。

·工厂模式
工厂模式也称为虚构造器,它适用于:一个类无法预期生成那个类对象,想让其子类来指定所生成具体对象。
类有一组子类,可以共用一套接口,但是实例化的方式略有差异。用工厂的方式实现,使得客户端(类的调用着)能够专注于接口。而不需要访问具体的实现类。

·何时使用工厂模式
编译时无法确定预期要创建的对象类
类想让子类决定运行时创建什么

·实现:抽象基类或协议。

五、runtime
1>OC 是一个全动态语言,OC 的一切都是基于 Runtime 实现的
平时编写的OC代码, 在程序运行过程中, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者
2>runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API
3>runtimeAPI的实现是用 C++ 开发的(源码中的实现文件都是mm),是一套苹果开源的框架

OC在编译的时候并不知道要调用哪个方法函数,只有在运行的时候才知道调用的方法函数名称,来找到对应的方法函数进行调用。

·runtime的作用:(https://www.cnblogs.com/allencelee/p/7573627.html
发送消息、交换方法、分类添加属性、动态添加方法、字典转模型KVC实现

·动态添加方法的实现:
SEL sel = @selector (start:) ; // 指定action  
if ([obj respondsToSelector:sel]) 
{ //判断该对象是否有相应的方法  
[obj performSelector:sel withObject:self]; //调用选择器方法  
}
// 默认方法都有两个隐式参数,
void eat(id self,SEL sel)
// 当一个对象调用未实现的方法,会调用这个方法处理,并且会把对应的方法列表传过来.
+ (BOOL)resolveInstanceMethod:(SEL)sel

六、runloop 运行回路
·工作模式:NSDefaultRunLoopMode UITrackingRunLoopMode NSRunLoopCommonModes
优先处理UI模式的事件,再处理Default模式,Common为前两者的集合

一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一个机制,让线程能随时处理事件但并不退出

七、网络
·TCP和UDP的区别:
TCP可靠,稳定,慢,效率低,占用系统资源高,易被攻击
(交换数据前,必须先在双方之间建立一个TCP连接)三次握手 四次挥手
UDP快,比TCP稍安全,不可靠,不稳定

套接字(Socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元

HTTP请求包由三个部分构成,分别是:请求方法-URI-协议/版本,请求头,请求正文。
HTTP响应包由三个部分构成,分别是:协议-状态代码-描述,应答头,应答正文。

·MD5加密的特点:
不可逆、长度固定、容易计算、抗修改性、安全

八、其他

在非ARC工程中采用ARC去编译某些类:-fobjc-arc。
在ARC下的工程采用非ARC去编译某些类:-fno-fobjc-arc

·NSObject内省方法:
1、isKindOfClass:Class
检查对象是否是那个类或者其继承类实例化的对象
2、isMemberOfClass:Class
检查对象是否是那个类但不包括继承类而实例化的对象
3、respondToSelector:selector
检查对象是否包含这个方法
4、conformsToProtocol:protocol
检查对象是否符合协议,是否实现了协议中所有的必选方法。

·事件传递响应链
系统会将事件加入到UIApplication管理的一个任务队列中,以栈的形式存储,先进先出先执行。
UIApplication会将事件发送给我们最底层的窗口UIWindow,这里的UIWindow值的是keyWindow(主),也只有显示在keyWindow上的视图才能接受点击事件的响应。
UIWindow将事件发送给控制器(或者视图),如果控制器能处理事件的响应,而且触摸点在自己的身上,那么继续寻找子视图。
遍历所有的子视图,重复上一步的判断,以此循环,直到条件不满足。
(- 如果找到的作用点在子视图上,但是子视图的userInteractionEnabled属性设置NO(是否响应的设置),那么这个事件就会被废弃。 - 如果找不到触摸点没有在点击的子视图上,那么这个事件由父视图执行。 - 如果摸点在子视图的区域,但是设置了隐藏或者透明度为0时,那这个事件同样由父视图执行。)

//对象的生命周期:对象的生命周期从 alloc 开始,到delloc结束
loadView—viewDidLoad—drawRect—viewWillApper—viewDidAppear—viewWillDisAppear

//iOS 中的四个基本框架:Foundation、SystemConfiguration、UIKit、CFNetWork
Cocoa是OS X和 iOS操作系统的程序的运行环境。
Cocoa众多框架中最重要最基本的两个框架是:Foundation 和 UIKit。
Cocoa中的NSRunLoop类并不是线程安全的

猜你喜欢

转载自blog.csdn.net/qq_25639809/article/details/80001998