理解!理解!!理解!!!

1、如何理解MVC设计模式

MVC是一种架构模式,M表示MOdel,V表示视图View,C表示控制器Controller:

Model负责存储、定义、操作数据;

View用来展示书给用户,和用户进行操作交互;

Controller是Model和View的协调者,Controller把Model中的数据拿过来给View用。Controller可以直接与Model和View进行通信,而View不能和Controller直接通信。View与Controller通信需要利用代理协议的方式,当有数据更新时,MOdel也要与Controller进行通信,这个时候就要用Notification和KVO,这个方式就像一个广播一样,MOdel发信号,Controller设置监听接受信号,当有数据更新时就发信号给Controller,Model和View不能直接进行通信,这样会违背MVC设计模式。


2、Objective-C 中是否支持垃圾回收机制?

OC是支持垃圾回收机制的(Garbage collection简称GC),但是apple的移动终端中,是不支持GC的,Mac桌面系统开发中是支持的.

移动终端开发是支持ARC(Automatic Reference Counting的简称),ARC是在IOS5之后推出的新技术,它与GC的机制是不同的。我们在编写代码时, 不需要向对象发送release或者autorelease方法,也不可以调用delloc方法,编译器会在合适的位置自动给用户生成release消息(autorelease),ARC 的特点是自动引用技术简化了内存管理的难度.


3、键路径(keyPath)、键值编码(KVC)和键值观察(KVO)

键路径

键-值编码技术用于进行这样的查找—它是一种间接访问对象属性的机制。 - 键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接在一起的对象性质序列。第一个键的性质是由先前的性质决定的,接下来每个键的值也是相对于其前面的性质。

键路径使您可以以独立于模型实现的方式指定相关对象的性质。通过键路径,您可以指定对象图中的一个任意深度的路径,使其指向相关对象的特定属性。

键值编码KVC

键值编码是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取方法,直接或通过实例变量访问的机制,非对象类型的变量将被自动封装或者解封成对象,很多情况下会简化程序代码;

KVC的缺点:一旦使用 KVC 你的编译器无法检查出错误,即不会对设置的键、键路径进行错误检查,且执行效率要低于合成存取器方法和自定的 setter 和 getter 方法。因为使用 KVC 键值编码,它必须先解析字符串,然后在设置或者访问对象的实例变量。

键值观察KVO

键值观察机制是一种能使得对象获取到其他对象属性变化的通知 ,极大的简化了代码。

实现 KVO 键值观察模式,被观察的对象必须使用 KVC 键值编码来修 改它的实例变量,这样才能被观察者观察到。因此,KVC是KVO的基础。


KVO中谁要监听谁注册,然后对响应进行处理,使得观察者与被观察者完全解耦。KVO只检测类中的属性,并且属性名都是通过NSString来查找,编译器不会检错和补全,全部取决于自己。


4、NSNotification、Block、Delegate和KVO的区别。

代理是一种回调机制,且是一对一的关系,通知是一对多的关系,一个对向所有的观察者提供变更通知;

效率:Delegate比NSNOtification高;

Delegate和Block一般是一对一的通信;

Delegate需要定义协议方法,代理对象实现协议方法,并且需要建立代理关系才可以实现通信;

Block:Block更加简洁,不需要定义繁琐的协议方法,但通信事件比较多的话,建议使用Delegate;



5、当我们调用一个静态方法时,需要对对象进行 release 吗?

不需要,静态方法(类方法)创建一个对象时,对象已被放入自动释放池。在自动释放池被释放时,很有可能被销毁。


6、#include与#import的区别,#import 与@class 的区别

#include 和#import其效果相同,都是查询类中定义的行为(方法);

#import不会引起交叉编译,确保头文件只会被导入一次;

@class 的表明,只定 义了类的名称,而具体类的行为是未知的,一般用于.h 文件;

@class 比#import 编译效率更高。

此外@class 和#import 的主要区别在于解决引用死锁的问题。


7、@public、@protected、@private 它们的含义与作用

@public:对象的实例变量的作用域在任意地方都可以被访问 ;

@protected:对象的实例变量作用域在本类和子类都可以被访问 ;

@private:实例变量的作用域只能在本类(自身)中访问 .


8、自动释放池工作原理

自动释放池是NSAutorelease类的一个实例,当向一个对象发送autorelease消息时,该对象会自动入池,待池销毁时,将会向池中所有对象发送一条release消息,释放对象。

[pool release]、 [pool drain]表示的是池本身不会销毁,而是池子中的临时对象都被发送release,从而将对象销毁。


9、UITableViewCell上有个UILabel,显示NSTimer实现的秒表时间,手指滚动cell过程中,label是否刷新,为什么?

这是否刷新取决于timer加入到Run Loop中的Mode是什么。Mode主要是用来指定事件在运行循环中的优先级的,分为:

NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态

UITrackingRunLoopMode:ScrollView滑动时会切换到该Mode

UIInitializationRunLoopMode:run loop启动时,会切换到该mode

NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合

苹果公开提供的Mode有两个:

NSDefaultRunLoopMode(kCFRunLoopDefaultMode)

NSRunLoopCommonModes(kCFRunLoopCommonModes)

在编程中:如果我们把一个NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环中的时候, ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。当我们滚动的时候,也希望不调度,那就应该使用默认模式。但是,如果希望在滚动时,定时器也要回调,那就应该使用common mode。


10、解决cell重用的问题

UITableView通过重用单元格来达到节省内存的目的,通过为每个单元格指定一个重用标示(reuseidentifier),即指定了单元格的种类,以及当单元格滚出屏幕时,允许恢复单元格以便复用。对于不同种类的单元格使用不同的ID,对于简单的表格,一个标示符就够了。

如一个TableView中有10个单元格,但屏幕最多显示4个,实际上iPhone只为其分配4个单元格的内存,没有分配10个,当滚动单元格时,屏幕内显示的单元格重复使用这4个内存。实际上分配的cell的个数为屏幕最大显示数,当有新的cell进入屏幕时,会随机调用已经滚出屏幕的Cell所占的内存,这就是Cell的重用。

对于多变的自定义Cell,这种重用机制会导致内容出错,为解决这种出错的方法,把原来的

1

2

UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:defineString]

修改为:UITableViewCell *cell = [tableview cellForRowAtIndexPath:indexPath];

这样就解决掉cell重用机制导致的问题。


11、有a、b、c、d 4个异步请求,如何判断a、b、c、d都完成执行?如果需要a、b、c、d顺序执行,该如何实现?

对于这四个异步请求,要判断都执行完成最简单的方式就是通过GCD的group来实现:

1

2

3

4

5

6

7

8

9

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{ /*任务a */ });

dispatch_group_async(group, queue, ^{ /*任务b */ });

dispatch_group_async(group, queue, ^{ /*任务c */ });

dispatch_group_async(group, queue, ^{ /*任务d */ });

dispatch_group_notify(group,dispatch_get_main_queue(), ^{

// 在a、b、c、d异步执行完成后,会回调这里

});

当然,我们还可以使用非常老套的方法来处理,通过四个变量来标识a、b、c、d四个任务是否完成,然后在runloop中让其等待,当完成时才退出runloop。但是这样做会让后面的代码得不到执行,直到Run loop执行完毕。

解释:要求顺序执行,那么可以将任务放到串行队列中,自然就是按顺序来异步执行了。


12、使用block有什么好处?使用NSTimer写出一个使用block显示(在UILabel上)秒表的代码。

代码紧凑,传值、回调都很方便,省去了写代理的很多代码。

NSTimer封装成的block,具体实现。

实现方法:

1

2

3

4

5

6

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0

repeats:YES

callback:^() {

weakSelf.secondsLabel.text = ...

}

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];



13、定时器与线程的区别

定时器;可以执行多次,默认在主线程中。

线程:只能执行一次。


14、TCP和UDP的区别于联系

TCP为传输控制层协议,为面向连接、可靠的、点到点的通信;

UDP为用户数据报协议,非连接的不可靠的点到多点的通信;

TCP侧重可靠传输,UDP侧重快速传输。


15、如何进行真机调试?

1.首先需要用钥匙串创建一个钥匙(key);

2.将钥匙串上传到官网,获取iOS Development证书;

3.创建App ID即我们应用程序中的Boundle ID;

4.添加Device ID即UDID;

5.通过勾选前面所创建的证书:App ID、Device ID;

6.生成mobileprovision文件;

7.先决条件:申请开发者账号 99美刀

APP发布的上架流程

1.登录应用发布网站添加应用信息;

2.下载安装发布证书;

3.选择发布证书,使用Archive编译发布包,用Xcode将代码(发布包)上传到服务器;

4.等待审核通过;

5.生成IPA:菜单栏->Product->Archive.


16、对NSUserDefaults的理解

NSUserDefaults:系统提供的一种存储数据的方式,主要用于保存少量的数据,默认存储到library下的Preferences文件夹。


17、SDWebImage原理

调用类别的方法:

内存中(字典)找图片(当这个图片在本次程序加载过),找到直接使用;

沙盒中找,找到直接使用,缓存到内存。

网络上获取,使用,缓存到内存,缓存到沙盒。


18、LayoutSubViews在什么时候被调用?

当View本身的frame改变时,会调用这个方法。


19、自定义实现UITabbarController的原理

运用字典,点击五个按钮的一个可以从字典里选择一个控制器对象,将其View显示到主控制器视图上。


20、View和View之间传值方式

对象的property属性传值;

方法参数传值;

NSUserDefault传值;(单例)

块传值。


21、对于Run Loop的理解

RunLoop,是多线程的法宝,即一个线程一次只能执行一个任务,执行完任务后就会退出线程。主线程执行完即时任务时会继续等待接收事件而不退出。非主线程通常来说就是为了执行某一任务的,执行完毕就需要归还资源,因此默认是不运行RunLoop的;

每一个线程都有其对应的RunLoop,只是默认只有主线程的RunLoop是启动的,其它子线程的RunLoop默认是不启动的,若要启动则需要手动启动;

在一个单独的线程中,如果需要在处理完某个任务后不退出,继续等待接收事件,则需要启用RunLoop;

NSRunLoop提供了一个添加NSTimer的方法,可以指定Mode,如果要让任何情况下都回调,则需要设置Mode为Common模式;

实质上,对于子线程的runloop默认是不存在的,因为苹果采用了懒加载的方式。如果我们没有手动调用[NSRunLoop currentRunLoop]的话,就不会去查询是否存在当前线程的RunLoop,也就不会去加载,更不会创建。


22、SQLite中常用的SQL语句

创建表:creat table 表名 (字段名 字段数据类型 是否为主键, 字段名 字段数据类型, 字段名 字段数据类型...);

增: insert into 表名 (字段1, 字段2...) values (值1, 值2...);

删: delete from 表名 where 字段 = 值;


23、内存的使用和优化的注意事项

重用问题:如UITableViewCells、UICollectionViewCells、UITableViewHeaderFooterViews设置正确的reuseIdentifier,充分重用;

尽量把views设置为不透明:当opque为NO的时候,图层的半透明取决于图片和其本身合成的图层为结果,可提高性能;

不要使用太复杂的XIB/Storyboard:载入时就会将XIB/storyboard需要的所有资源,包括图片全部载入内存,即使未来很久才会使用。那些相比纯代码写的延迟加载,性能及内存就差了很多;

选择正确的数据结构:学会选择对业务场景最合适的数组结构是写出高效代码的基础。比如,数组: 有序的一组值。使用索引来查询很快,使用值查询很慢,插入/删除很慢。字典: 存储键值对,用键来查找比较快。集合: 无序的一组值,用值来查找很快,插入/删除很快。

gzip/zip压缩:当从服务端下载相关附件时,可以通过gzip/zip压缩后再下载,使得内存更小,下载速度也更快。

延迟加载:对于不应该使用的数据,使用延迟加载方式。对于不需要马上显示的视图,使用延迟加载方式。比如,网络请求失败时显示的提示界面,可能一直都不会使用到,因此应该使用延迟加载。

数据缓存:对于cell的行高要缓存起来,使得reload数据时,效率也极高。而对于那些网络数据,不需要每次都请求的,应该缓存起来,可以写入数据库,也可以通过plist文件存储。

处理内存警告:一般在基类统一处理内存警告,将相关不用资源立即释放掉

重用大开销对象:一些objects的初始化很慢,比如NSDateFormatter和NSCalendar,但又不可避免地需要使用它们。通常是作为属性存储起来,防止反复创建。

避免反复处理数据:许多应用需要从服务器加载功能所需的常为JSON或者XML格式的数据。在服务器端和客户端使用相同的数据结构很重要;

使用Autorelease Pool:在某些循环创建临时变量处理数据时,自动释放池以保证能及时释放内存;

正确选择图片加载方式:详情阅读细读UIImage加载方式


24、UIViewController的完整生命周期

-[ViewController initWithNibName:bundle:];

-[ViewController init];

-[ViewController loadView];

-[ViewController viewDidLoad];

-[ViewController viewWillDisappear:];

-[ViewController viewWillAppear:];

-[ViewController viewDidAppear:];

-[ViewController viewDidDisappear:];


25、UIImageView添加圆角

最直接的方法就是使用如下属性设置:

imgView.layer.cornerRadius = 10;

// 这一行代码是很消耗性能的

imgView.clipsToBounds = YES;

**这是离屏渲染(off-screen-rendering),消耗性能的**

给UIImage添加生成圆角图片的扩展API:这是on-screen-rendering

- (UIImage *)imageWithCornerRadius:(CGFloat)radius {

CGRect rect = (CGRect){0.f, 0.f, self.size};

UIGraphicsBeginImageContextWithOptions(self.size, NO, UIScreen.mainScreen.scale);

CGContextAddPath(UIGraphicsGetCurrentContext(),

[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius].CGPath);

CGContextClip(UIGraphicsGetCurrentContext());

[self drawInRect:rect];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return image;

}

你可能感兴趣的:(理解!理解!!理解!!!)