1、简述UIViewController的生命周期(注意:didReceiveMemoryWarning只有内存警告才会走)
alloc -> init -> loadView->viewDidLoad->viewWillApper->viewDidApper->viewWillDisApper-didReceiveMemoryWarning->dealloc
2、 import跟 include又什么区别,@class呢,#import<>跟# Import""又什么区别?
#import是 Objective-C导入头文件的关键字,
include是C/C++导入头文件的关键字。
使用# import头文件会自动只导入一次,不会重复导入,相当于 #include和 #pragma once;
@class则告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含;
# import<>用来包含系统的头文件,# import""用来包含用户头文件。
3、锁
4、KVC
5、KVO
6、HASH的特点:
@1、算法是公开的,@2、对相同数据的运算,得到的结果是一样的,@3、对不同数据运算,如MD5得到的结果默认是128位,32个字符(16进制标识)@ 4、算法不能逆运算,@5、信息摘要,信息“指纹”,是用来做数据识别的。
用途:用户密码的加密、搜索引擎、版权、数字签名
密码加密方式:直接使用MD5、MD5加盐、HMAC加密方案、添加一点东西
对称加密:明文通过秘钥加密得到密文。密文通过秘钥解密得到明文。
非对称加密(RSA):分公钥和私钥,一般公钥只能用来加密,私钥只能用来解密和生成公钥。加密速度比较低,私钥由自己生成,再由私钥生成公钥,将公钥分发出去
用户注册的时候:需要把用户的密码进行hash过后传到后台进行保存
用户登录密码加密:1、服务器获取key和密码进行HMAC加密 +获取当前的时间戳,然后进行hash,发给服务器
服务器:1、服务器获取key和密码进行HMAC加密 +获取当前的时间戳(时间戳可能会有延迟,可以往后一分钟进行拼接),然后进行hash,然后把客户端传过来的字符串是否相同,相同就登录成功,
7、Socket
8、weak与assign:weak一般在delegate中使用,解决循环引用问题,防止内存泄露,因为修饰的对象释放后,引用计数为0,指针自动被置为nil,assign可修饰对象,和基本数据类型,修饰对象,会产生野指针问题;如果修饰基本数据类型则是安全的。修饰的对象释放后,指针不会自动被置空,此时向对象发消息会崩溃。
copy与strong的区别?:在不可变的数据类型中都是浅拷贝,而在可变的数据类型中strong是浅拷贝,而copy是深拷贝
深拷贝和浅拷贝的区别
深拷贝:内容拷贝,拷贝数据到一个新的内存区域,两个对象的值虽然相同,但是内存地址不一样,两个对象都不相关了
浅拷贝:是拷贝原来对象的指针,而内存地址不变,当原来的指针对象值改变的时候,拷贝的指针对象的值也会变
@property 这个关键词的唯一作用就是声明getter、setter方法接口
@synthesize 实现setter、getter方法,找不到实例变量则主动创建一个:
例如:@synthesize proName =_proName
@dynamic 语义是用户要求自动生成setter getter方法,系统不会自动生成,;
atomic 默认属性。当前进程进行到一半,其他线程来访问当前线程,可以保证先执行完毕当前线程。只是保证setter/getter完整,不是线程安全。
nonatomic 非默认属性。两个线程同时访问同一个属性将会导致无法预计的结果。优点是程序运行速度快。
retain 强应用类型,在ARC自动内存管理时,相当于strong;
autorelease:本质就是延迟调用release方法 。底层主要数据结构是__AtAutoreleasePool,AutoreleasePoolPage
最终都是通过AutoreleasePoolPage对象来管理的。
AutoreleasePool(自动释放池)是 OC 中的一种内存管理机制,它持有释放池里的对象的所有权,在自动释放池销毁时,统一给所有对象发送一次 release 消息。通过这个机制,可以延迟对象的释放。
autoreleasepool在何时被释放?
Runloop创建的AutoreleasePool,只会在Runloop即将休眠或退出的时候销毁,这时候池中的对象才会被释放
说一下iOS内存分区情况?
内存其实分为五大分区,栈区(系统管理的地方)、堆区(程序员控制的地方)、常量区(全局区)、静态区和代码区,
栈区:栈是编译器自动分配释放来管理内存,用户存放程序临时创建的变量、函数值等,由于栈的先进后出的特点,特别适合保存恢复当前的代码块区域操作
堆区:是由程序员分配和释放,(程序不释放,可能会导致内存泄露),是动态分配内存段,大小不固定,可动态扩张和缩放
堆区的内存分配使用的是alloc,ARC的内存管理,是编译器在编译的时候自动添加retain,release,autorelease,堆区的地址是从低到高
常量区:常量存储区是一块比较特殊的存储区,存放的都是常量
全局静态区:分为数据区和bss区,数据区存放可执行文件中已经初始化的全局变量,bss区存放的是未初始化的全局变量和未初始化的静态变量
代码区:就是存放APP代码,防止运行时被修改,所以只能读取,不能写入
iOS 如何解决循环引用?
1.在delegate中用weak弱引用
2、block:使用__weak typeof(self) weakSelf = self;打断循环引用,如果担心对象在block中提前释放:用 __strong typeof (self) strongSelf = weakSelf;
3、定时器(NSTimer),在何时的地方将其invalidate并置为nil即可
runloop和线程的关系?
runloop和线程是一一对应的关系,主线程的runloop是自动开启的,子线程需要手动开启([[NSRunLoop currentRunLoop]run])
isa指针的理解,对象isa指针指向哪里?
isa指针指向等价于 is kind of
实例对象isa指向类对象、类对象的isa指向元类对象、元类对象的isa指向元类的基类
两种类型:isa指针,superclass指针
Runtime是怎么实现weak?
Runtime对注册的类会进行布局,对于weak对象会放入一个hash表中,用weak指向的“对象的内存地址”作为key,当对象的引用计数为0的时调用dealloc方法,此时会在weak表中搜索,将所有weak对象置为nil;
Runtime是一套C语言的API,,编写的OC代码都是转换成Runtime_API进行调用
OC是动态时语言:在运行时确定一个对象的类型,调用那个对象的方法,都需要Runtime来做类和对象的动态创建,消息传递和消息转发
load 和 initialize的区别?
initalize该类只调用一次,load是每次进入该类都会调用
iOS 中造成tableView卡顿的原因都有哪些呢?
1、没有使用cell的重用标识符,导致一直创建新的cell
2、每次cell的重新布局
3、没有提前计算并缓存cell的属性及内容
4、加载网络数据,下载图片,没有使用异步加载和缓存图片
5、没有做缓存行高,每次都需要计算行高
如何降低APP包的大小?
删除不必要的图片,删除不需要的类文件,删除项目中没有用到的库文件,删除不需要的资源文件
iOS内存泄露排查方法?
内存泄露是指申请的内存空间使用完成之后没有及时回收,导致页面不释放,从而加剧内存暴增
静态内存泄露分析方法:通过xcode打开项目,点击Product,在下拉菜单中点击Analyze就可以进行静态内存泄漏分析
动态分析:Instrument中的Leaks来分析
iOS常见的项目设计模式:MVC,MVVM
iOS 结构设计模式:KVO、KVC、桥接模式、单利模式、代理模式
什么是多线程?
即1个进程中可以开启多条线程,每条线程可以同时执行不同的任务。
一、多线程的优缺点:
优点: 1.能适当提高程序的执行效率 2.能适当提高资源的利用率(cpu,内存); 3.线程上的任务执行完成之后,线程会自动销毁;
缺点: 1.开启线程需要占用一定的内存空间(默认占用512KB); 2.开启大量的线程,会占用大量的内存空间,降低程序的性能;
3.线程越多,cpu在调用线程上的开销就越大;4.程序设计更加复杂,比如线程间的通信,多线程的数据共享
如何保证线程的安全?:线程加锁
线程中的死锁?
死锁形成的原因:
系统资源不足
进程(线程)推进的顺序不恰当;
资源分配不当
死锁形成的条件:
互斥条件:一个资源每次只能被一个进程使用
占有且等待:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
1. 为什么说Objective-C是一门动态的语言?4.如何令自己所写的对象具有拷贝功能?
因为Objective—C可以通过Runtime这个运行机制,在运行时动态的添加变量、方法、类等
2、为什么代理要用weak?代理的delegate和dataSource有什么区别?block和代理的区别?
防止循环引用 ,delegate偏重于与用户交互的回调,datasource偏重于数据的返回
区别在于:代理倾向于过程,block倾向于结果。.代理书写起来繁琐一些,block很便捷。代理运行成本低,block运行成本高。优先使用block(单次,或回调很少,不频繁),如果需要频繁的回调,数量比较多的回调,例如tableView的代理方法,界面滚动的时候会反复调用,就适合用代理。单次,或者比较少的回调适合用block。有利于优化性能。
A:属性的本质是@property = ivar+getter+setter,也就是说@property系统会自动生成getter和setter方法。属性默认的关键字包括atomic,nonatomic,@synthesize,@dynamic,getter=getterName,setter=setterName,readwrite,readonly,assign,retain,copy。
@dynamic:表示变量对应的属性访问器方法,是动态实现的,你需要在 NSObject 中继承而来的 +(BOOL) resolveInstanceMethod:(SEL) sel 方法中指定 动态实现的方法或者函数。
@synthesize:如果没有实现setter和getter,编译器能够自动实现getter和setter方法。
A:若想让自己写的对象具有拷贝功能,则需要实现NSCopying协议。如果自定义的对象分为可变版本和非可变版本,那么就要同时实现NSCopying和NSMutableCopying协议,不过一般没什么必要,实现NSCopying协议就够了。
5.可变集合类 和 不可变集合类的 copy 和 mutablecopy有什么区别?如果是集合是内容复制的话,集合里面的元素也是内容复制么?
A:对于不可变对象,copy操作是浅复制,mutableCopy是深复制。对于不可变对象,mutableCopy不仅仅是深复制,返回的对象类型还是不可变对象类型相应的可变对象的类型。内容复制也就是深拷贝,集合的深复制有两个方法,可以用initWithArray:copyItems:将第二个参数设置为YES即可进行深复制,如:NSDictionary shallowCopyDict =[NSDictionary alloc]initWithDictionary:someDictionary copyItems:YES];如果用这个方法深复制,集合里的每个元素都会收到copyWithZone:消息。如果集合里的对象遵循NSCopying协议,那么对象就会深复制到新的集合。如果对象没有遵循NSCopying协议,而尝试用这种方法进行深复制则会出错。copyWithZone:这种拷贝方式只能提供一层内存拷贝,而非真正的深拷贝。第二种方法是将集合进行归档解档,如:NSArray trueDeepCopyArray =[NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];
6.为什么IBOutlet修饰的UIView也适用weak关键字?
A:因为既然有外链那么视图在xib或者storyboard中肯定存在,视图已经对它有一个强引用了。
7. nonatomic和atomic的区别?atomic是绝对的线程安全么?为什么?如果不是,那应该如何实现?
A:nonatomic和atomic的区别在于两者自动生成getter和setter的方法不一样,如果你自己写getter和setter方法,那么(getter,setter,retain,copy,assign)只起提示作用,写不写都一样。
对于atomic的属性,系统生成的getter和setter会保证get,set的操作完整性,不受其他线程影响。比如线程A的getter方法运行到一半,线程B调用了setter,那么线程A的getter还是能得到一个完整的对象。
而nonatomic就没有这个保证了,所以速度要比atomic快。
不过atomic可不能保证线程安全,如果线程A调用了getter,与此同时线程B和线程C都调了setter,那最后线程Aget到的值,三种都有可能:可能是B,C set之前原始的值,也可能是B set的值,也可能是C set的值。同时这个最终的值,也可能是B set的值,也可能是C set的值。要保证安全,可以使用线程锁。