1、MVC设计模式的理解
M:model模型保存所有应用程序里要使用的数据,比如一款太空大战游戏,模型要负责保存飞船的大小、飞行速度、位置信息、装载了多少只枪等等这些信息。并且要处理数据之间的逻辑 比如飞船要打中敌机多少次能把敌机击落。数据都可以放在自定义类型、NSArray及其子类型、NSDictionary及其子类型中,视图的显示都用UIView及其子类来实现
模型只是负责记录数据,跟数据的显示是没关系的,数据的显示是控制器跟视图的任务
C:controller控制器负责控制视图如何去显示模型里要显示的数据 它要负责把模型里的数据传输给视图(控制器是通过视图控制器的【生命周期】来控制视图变化的)。控制器在UIViewController的子类中实现,在控制器的ViewDidLoad、ViewWillAppear、ViewDidAppear、ViewDidDisappear、ViewWillDisappear等方法中实现数据和视图的交互。
V:view视图视图就是视图控制器的小跟班,它的任务就是负责显示视图,完全听命于视图控制器,视图控制器让视图做什么视图就做什么
三者之间常见消息传递方式有:代理、通知、block、kvo等。
2、UIViewController的生命周期方法调用顺序
alloc
init
-(void)loadView;
- (void)viewDidLoad;
- (void)viewWillAppear:(BOOL)animated;
- (void)viewDidAppear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
3、UITableView的执行流程是怎么样的
section个数-section高度-section的view-section里面的cell个数-section里面cell的高度-cell的内容
"numberOfSectionsInTableView:"返回TableView的section数目
tableView:heightForHeaderInSection遍历各组表头高度
“tableView:viewForHeaderInSection:”遍历各组是否有表头view
"tableView:numberOfRowsInSection:"设置section1中行数
"tableView:heightForRowAtIndexPath:”从第一组第一行开始到最后一组最后一行设置cell高度。
"tableView:cellForRowAtIndexPath:”设置每一行的cell
这样整个TableView就设置完毕了.
4、UITableViewCell怎样使用更流畅?
1)首先cell的复用机制节约了系统资源;
其次应当注意有些复杂的大数据或网络数据应采用异步加载的方式进行加载,以免cell刷出时发生卡顿。
2)避免在cell的高度计算方法中做大量的计算工作。
3)不要一次性加载所有的图片,等到tableview停止滚动的时候再加载在屏幕显示区域的cell中的图片
5、push推送机制
iOS在系统级别有一个推送服务程序使用5223端口。使用这个端口的协议源于Jabber后来发展为XMPP,被用于Gtalk等IM软件中。所以,iOS的推送,可以不严谨的理解为:
苹果服务器朝手机后台挂的一个IM服务程序发送的消息。
然后,系统根据该IM消息识别告诉哪个Apps具体发生了什么事。
然后,系统分别通知这些Apps。
流程:
provider(自己的服务器)——APNs(Apple Push Notification service)——iPhone———ClientApp
6、简述开发中使用过的设计模式。
(一)代理模式
应用场景:当一个类的某些功能需要由别的类来实现,但是又不确定具体会是哪个类实现。
优势:解耦合
敏捷原则:开放-封闭原则
实例:tableview的 数据源delegate,通过和protocol的配合,完成委托诉求。
tableviewcell点击事件的delegate
自定义的delegate
(二)观察者模式
应用场景:一般为model层对,controller和view进行的通知方式,不关心谁去接收,只负责发布信息。
优势:解耦合
敏捷原则:接口隔离原则,开放-封闭原则
实例:Notification通知中心,注册通知中心,任何位置可以发送消息,注册观察者的对象可以接收。
[[NSNotificationCenter defaultCenter] addObsever:aObserver selector:@selctor(doSomething) name:@“aName” object:nil]
kvo,键值对改变通知的观察者。
观察tableview的contentOffset,当这个值发现变化时触发方法-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
[tabeView addobserver:aObserver forKeyPath:@"contentOffset” options:NSKeyValueObservingOptionNew context:nil]
(三)MVC模式
应用场景:是一中非常古老的设计模式,通过数据模型,控制器逻辑,视图展示将应用程序进行逻辑划分。
优势:使系统,层次清晰,职责分明,易于维护
敏捷原则:对扩展开放-对修改封闭
实例:model-即数据模型,view-视图展示,controller进行UI展现和数据交互的逻辑控制。
(四)单例模式
应用场景:确保程序运行期某个类,只有一份实例,用于进行资源共享控制。
优势:使用简单,延时求值,易于跨模块
敏捷原则:单一职责原则
实例:[UIApplication sharedApplication]。
注意事项:确保使用者只能通过getInstance方法才能获得,单例类的唯一实例。
java,C++中使其没有公有构造函数,私有化并覆盖其构造函数。
object c中,重写allocWithZone方法,保证即使用户用alloc方法直接创建单例类的实例,
返回的也只是此单例类的唯一静态变量。
7、面向对象的特点:继承、封装、多太
8、冒泡排序://冒泡
for(inti =0; i < [stuscount]-1; i++) {
for(intj =0; j < [stuscount]-1-i; j++) {
//获取第j j+1学生的地址
Student*stu1 = [stusobjectAtIndex:j];
Student*stu2 = [stusobjectAtIndex:j+1];
if([stu1score] < [stu2score]) {
//交换
[stusexchangeObjectAtIndex:jwithObjectAtIndex:j+1];
}
}
}
9、什么是UDP和TCP的区别是什么?
TCP的全称为传输控制协议。这种协议可以提供面向连接的、可靠的、点到点的通信。
UDP的全称为用户数据报协议,它可以提供非连接的不可靠的点到多点的通信
10、
描述一下iOS的内存管理,在开发中对于内存的使用和优化包含哪些方面。我们在开发中应该注意哪些问题。
参考答案:
内存管理黄金法则:谁使对象的引用计数+1,谁就负责管理使该对象的引用计数-1。
在MRC下,对于需要手动释放的对象的内存管理,我们通过release使对象引用计数-1,若其引用计数变成0,则对象会被立刻释放掉。对于autorelease交给自动释放池管理的对象,每个runloop循环结束就会去自动释放池中使所有autorelease类型对象的引用计数减一,若变成0,则释放之。
在ARC下,我们没有不能直接调用retain/release来管理释放,都是交给自动释放池来管理的。因此,若创建临时变量,想要使用完就释放之,需要在临时变量放到新创建的自动释放池里,这样就可以使用完后就到达了自动释放池的一个循环,就会去使对象引用计数减一,变成0后释放之。
最后:对于交给自动释放池管理的对象,是在每个run loop事件循环结束时才会去使对象引用计数减一,此时引用计数为0的才会得到释放。
retain(引用计数加1)->release(引用计数减1)
alloc(申请内存空间)->dealloc(释放内存空间)
readwrite:表示既有getter,也有setter (默认)
readonly:表示只有getter,没有setter
nonatomic:不考虑线程安全
atomic:线程操作安全(默认)
retain:release旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
assign:简单赋值,不更改索引计数(默认)
copy:其实是建立了一个相同的对象,地址不同(retain:指针拷贝copy:内容拷贝)
strong:(ARC下的)和(MRC)retain一样(默认)
weak:(ARC下的)和(MRC)assign一样,weak当指向的内存释放掉后自动nil化,防止野指针
unsafe_unretained声明一个弱应用,但是不会自动nil化,也就是说,如果所指向的内存区域被释放了,这个指针就是一个野指针了。
autoreleasing用来修饰一个函数的参数,这个参数会在函数返回的时候被自动释放。
对于内存的使用和优化常见的有以下方面:
重用问题:如UITableViewCells、UICollectionViewCells、UITableViewHeaderFooterViews设置正确的reuseIdentifier,充分重用。
参考答案:
[[UITableViewCellalloc]initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:cellIdentifier]
这个方法就是重用机制的核心了。比如,有一个界面可显示10个cell,那么创建10次cell,并给cell指定同样的重用标识(当然,可以为不同显示类型的cell指定不同的标识)并且10个cell将全部都加入到visiableCells数组,reusableTableCells为空.
滚动tableView,当有一个cell完全移出屏幕时,这个cell就会被加入到reusableTableCells。而新出现的那个cell将加入到visiableCells,而这个cell就是被重用的。如果要让tableview不重用,不设置reuseIdentifier就可以了。
选择正确的数据结构:学会选择对业务场景最合适的数组结构是写出高效代码的基础。比如,数组: 有序的一组值。使用索引来查询很快,使用值查询很慢,插入/删除很慢。字典: 存储键值对,用键来查找比较快。集合: 无序的一组值,用值来查找很快,插入/删除很快。
gzip/zip压缩:当从服务端下载相关附件时,可以通过gzip/zip压缩后再下载,使得内存更小,下载速度也更快。
延迟加载:对于不应该使用的数据,使用延迟加载方式。对于不需要马上显示的视图,使用延迟加载方式。比如,网络请求失败时显示的提示界面,可能一直都不会使用到,因此应该使用延迟加载。
数据缓存:对于cell的行高要缓存起来,使得reload数据时,效率也极高。而对于那些网络数据, 不需要每次都请求的,应该缓存起来,可以写入数据库,也可以通过plist文件存储。
处理内存警告:一般在基类统一处理内存警告,将相关不用资源立即释放掉
避免反复处理数据:许多应用需要从服务器加载功能所需的常为JSON或者XML格式的数据。在服务器端和客户端使用相同的数据结构很重要。
11 什么是单例,如何设计单例?
参考答案:
单例就是全局都只有一个对象存在,而且是在整个App运行过程中都存在。每个App都会有单例,比如UIApplication。而我们在做用户数据存储时,通常都会用单例存储,因为应用在所有操作中,经常要求先登录。
下面这种写法是最常用的写法,这个是线程安全的。
+(instancetype)shared{
staticHYBUserManager*sg_userManager=nil;
staticdispatch_once_tonceToken;
dispatch_once(&onceToken,^{
if(sg_userManager==nil){
sg_userManager=[[HYBUserManageralloc]init];
}
});
returnsg_userManager;
}
12、为什么很多内置的类,如TableViewController的delegate的属性是assign不是retain?
循环引用
所有的引用计数系统,都存在循环应用的问题。例如下面的引用关系:
•对象a创建并引用到了对象b.
•对象b创建并引用到了对象c.
•对象c创建并引用到了对象b.
这时候b和c的引用计数分别是2和1。当a不再使用b,调用release释放对b的所有权,因为c还引用了b,所以b的引用计数为1,b不会被释放。b不释放,c的引用计数就是1,c也不会被释放。从此,b和c永远留在内存中。
这种情况,必须打断循环引用,通过其他规则来维护引用关系。比如,我们常见的delegate往往是assign方式的属性而不是retain方式
的属性,赋值不会增加引用计数,就是为了防止delegation两端产生不必要的循环引用。如果一个UITableViewController对象a通过retain获取了UITableView对象b的所有权,这个UITableView对象b的delegate又是a,
如果这个delegate是retain方式的,那基本上就没有机会释放这两个对象了。自己在设计使用delegate模式时,也要注意这点。
定义属性时,什么情况使用copy、assign、retain?
assign用于简单数据类型,如NSInteger,double,bool,
retain和copy用于对象,
copy用于当a指向一个对象,b也想指向同样的对象的时候,如果用assign,a如果释放,再调用b会crash,如果用copy的方式,a和b各自有自己的内存,就可以解决这个问题。
retain会使计数器加一,也可以解决assign的问题。
13、浅拷贝与深拷贝的区别是什么
用最简单的话说:浅拷贝就是指针拷贝(指向原有内存空间),而深拷贝是内容拷贝(有新的内存空间)。
或者说:浅复制并不拷贝对象本身而仅仅是拷贝指向对象的指针;深复制是直接拷贝整个对象内存到另一块内存中。
14、#import和#include的区别,@class代表什么?
#import和#include指令都是用于包含头文件的,前者是保证只会包含一次,不会重复包含;后者是c语言中原来就有的包含头文件的指令,在objc开发中,若是c文件,一件会使用#include指令来包含头文件,
@class是类前向声明的指令,相当于告诉编译器有这样一个类,但是类的定义在后面提供。在编译时期,编译器看到@class指令声明了对应的类型,是可以正常编译过的。这是很常用的指令,主要是防止循环引用。
如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。