人在面试,都是套路!
1.iOS视图控制对象的生命周期(从init开始)
1、 alloc 创建对象,分配空间
2、 init (initWithNibName) 初始化对象,初始化数据
3、 loadView 从nib载入视图 ,除非你没有使用xib文件创建视图
4、 viewDidLoad 载入完成,可以进行自定义数据以及动态创建其他控件
5、 viewWillAppear视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了
6、 viewDidAppear 视图已在屏幕上渲染完成
7、viewWillDisappear 视图将被从屏幕上移除之前执行
8、viewDidDisappear 视图已经被从屏幕上移除,用户看不到这个视图了
9、dealloc 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放.
10、viewVillUnload- 当内存过低,即将释放时调用;
11、viewDidUnload-当内存过低,释放一些不需要的视图时调用。
2.UITabView的重用机制的理解,cell的赋值方法?
对于重用机制的理解
- 屏幕上滑出屏幕时,系统会把这个单元格添加到重用队列中,等待被重用,当有新单元从屏幕外滑入屏幕内时,从重用队列中找看有没有可以重用的单元格,若有,就直接用,没有就重新创建一个。
解决cell重用的问题
- 如一个TableView中有10个单元格,但屏幕最多显示5个,实际上iPhone只为其分配5个单元格的内存,没有分配10个,当滚动单元格时,屏幕内显示的单元格重复使用这5个内存。实际上分配的Cell的个数为屏幕最大显示数,当有新的Cell进入屏幕时,会随机调用已经滚出屏幕的Cell所占的内存,这就是Cell的重用。
Cell的赋值方法(不太明白问这道题几个意思)
cell.textLabel.text = [NSString stringWithFormat:@"%ld- %ld",indexPath.row,indexPath.section];
附加问题:是调用行高的方法先走还是调用内容的方法先走?
// 设置行高的
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
// 设置每行的内容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- 当tableView在确定了加载的行数之后,先调用一次设置行高的方法,然后调用设置行内容的方法。(面试时脑子短路(>_<))
3.多线程的几种类型使用,多线程的一般用法?
四种类型如图所示
多线程一般用法(如果说在网络请求中这天就聊不下去了!!!尽量扯在别处的用法,起码是其他去面试的不说的)
案例1:开发中常见情景,比如发送一条微博动态,用户可以在本地界面编辑好一条微博动态上传服务器,上传后要清除本机暂存档,这条微博包含文本JSON和一张图片,所以上传微博动态的工作就包含上传JSON文件和图片两个内容,并且在用户上传过程中可以随时取消,让用户继续编辑重新上传这个微博动态,这比较适合用NSOperation写。
1.首先我们要写一个NSOperation的子类,要重写掉main中的方法。
.h文件
@interface WeiboUploadOperation : NSOperation
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) NSString *JSON;
@end
.m文件
@implementation
WeiboUploadOperation
- (void)main
{
@autoreleasepool {
// 1. Upload image
// 2. Upload JSON
}
}
@end
在main里面,要建立自动释放池autorelease pool。
接下来的问题来了:上传照片和JSON文字时,我们会调用NSURLSession 的相应 API,但是这些API都是非同步的,但是在main中的这些方法里,如果不做特殊的处理,还没收到连续响应,main早就已经执行结束了。我们必须要停在main中,等待API响应。
2.要在operation的中途停下来的时候等待响应,大致有两种思路,一种是在operation当中执行NSRunloop,另外一种就是使用GCD的semaphore
3.在还没有GCD之前,如果希望一个operation可以在某一个地方停下来等候其他的事件发生,做法就是在这条线程中执行Runloop。Runloop就是那个之所以让图形化界面(GUI)的程序一直执行,而不会像某个function或者method从头到尾跑圈就结束的循环(也就是跑圈啦)。在iOS中,除了主线程会执行最主要的Runloop([ NSRunloop mainRunLoop])之外,每个线程也有属于自己的Run loop,只要调用 [NSRunloop currentRunLoop],调用的就是当前线程自己的Runloop,所以要注意,虽然在不同的线程,我们调用的都是[NSRunloop currentRunLoop],但是+currentRunLoop这个类方法回调的并不看做一个类。此外,NSRunloop并不可以手动建立,我们只能使用系统提供的Runloop类。(好像跑偏额(≧▽≦)/啦啦啦)
4.我们要做的是能够在这个operation 执行到一半时喊停,要取消一条operation,那就是要调用 NSOperation的cancel这个方法了,因为我们重写了NSOperation,改变operation里面做的事情,那顺带也重写了cancel,当我们的operation在跑Runloop时候,我们的cancel必须能够通知Runloop停止。当一条线程在跑自己的Runloop之后,如果不同线程之间想要互相通信,那我们就必须在当前的线程建立NSPort类,NSPort介个是个什么东东呢?请移步看苹果爸爸咋说吧。Runloop。将 NSPort 类注册到Runloop内,才可以把消息传到Runloop里面,所以当外部要求Port调用invalidate的时候,就会让Runloop收到消息,停止继续跑,继续执行-main这个方法接下来的方法。
NSPort 也有封装的 Core Foundation 实现,像CFMessagePort等,但是在iOS7之后就没有办法使用了CFMessagePort。iOS7之后之后,调用CFMessagePortCreateLocal或者CFMessagePortCreateRemote这些新建CFMessagePort的函数都无法建立类,只能回传NULL(可以参照CFMessagePort的文档),苹果不允许让我们使用CFMessagePort的原因是:CFMessagePort不但可以传递消息到其他线程的RunLoop上,甚至可以传到其他进程的Runloop上,而iOS 政策上是不允许进程之间相互连通的。
废话说完,上代码
.h文件
@interface WeiboUploadOperation : NSOperation
{
NSPort *port;
BOOL runloopRunning;
}
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) NSString *JSON;
@end
.m文件
@implementation
WeiboUploadOperation
- (void)main
{
“@autoreleasepool {
[someAPI uploadImageData:UIImagePNGRepresentation(self.image) callback:^ {
[self quitRunLoop];
}];
[self doRunloop];
if (self.isCancelled) {
return;
}
[someAPI uploadJSON:self.JSON callback:^ {
[self quitRunLoop];
}];
[self doRunloop];
}
}
- (void)doRunloop
{
runloopRunning = YES;
port = [[NSPort alloc] init];
[[NSRunLoop currentRunLoop] addPort:port forMode:NSRunLoopCommonModes];
while (runloopRunning && !self.isCancelled) {
@autoreleasepool {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
}
}
port = nil;
}
- (void)quitRunLoop
{
[port invalidate];
runloopRunning = NO;
}
- (void)cancel
{
[super cancel];
[self quitRunLoop];
}
@end
*注意:伪代码而已,说明思路,someAPI就是指自己程序里的自己封装网络请求
此外呢,其实还有一种方法啦,只是不常用-GCD Semaphores
有了GCD之后呢,很多事情就变得很简单了,当我们想要执行到一半的时候暂停下来,现在可以选择建立semaphore。接下来:
- 只要对semaphore调用dispatch_semaphore_wait,程序就会在该暂停的的地方暂停等候。
- 对于已经在等候中的semaphore,再调用dispatch_semaphore_signal,发送signal,程序就会往下面继续执行。
上代码
.h文件
@interface WeiboUploadOperation : NSOperation
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) NSString *JSON;
@property (nonatomic, strong) dispatch_semaphore_t semaphore;
@end
.m文件
@implementation
WeiboUploadOperation
- (void)main
{
@autoreleasepool {
self.semaphore = dispatch_semaphore_create(0);
[someAPI uploadImageData:UIImagePNGRepresentation(self.image) callback:^{
dispatch_semaphore_signal(self.semaphore);
}];
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
if (self.cancelled) {
return;
}
self.semaphore = dispatch_semaphore_create(0);
[someAPI uploadJSON:self.JSON callback:^
{
dispatch_semaphore_signal(self.semaphore);
}];
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
}
}
- (void)cancel
{
[super cancel];
dispatch_semaphore_signal(self.semaphore);
}
@end
*someAPI指的是请求网络的代码,很多种写法啦
4.如何优化页面的加载效率?
我表示丈二的和尚摸不到头脑,给我留那么点空,够写吗?
发现一篇文章不错:如何让iOS 保持界面流畅?这些技巧你知道吗?
好吧,我没那么牛逼,我当时只写的TableView的优化:
TableView表格性能优化
- 行高一定要缓存!!!
- 不要动态创建子视图,所有的子视图都预先创建,如果不需要显示可以设置为hidden
- 所有的子视图都应该添加到contentview上
- 所有的子视图必须指定背景颜色
- 所有的颜色都不要使用alpha
- cell栅格化
- 异步绘制
//将 cell 的图层内容生成一张图像并且缓存,在滚动中,不再生成 cell 的内容
self.layer.shouldRasterize = true // 一定要设置分辨率
self.layer.rasterizationScale = UIScreen.mainScreen().scale
//异步绘制
cell.layer.drawsAsynchronously = true
5.代理和block的区别?
服,不服不行,应聘的也不是初级岗,还问
详细文章写得比我好的多得是,请移步
谈Objective-C block的实现
我当时就简单写得
- 代理(delegate):约定好的协议,调用方法实现协议的方法,接受在需要的时候,通知delegate执行这个方法。
- block:是提前准备好的代码,传递给接收方,至于什么时候被执行,调用方并不知道。
6.UIImagePickerController和AVCaptureSession对比?
我表示并不知道,当时没写空着。
网上的资料也都好老,先空着这,以后更新
7.内存过高和CPU负载过高引起的原因和解决办法?
这是个永久的命题啊!!!!!
iOS 界面构建中的各种性能问题以及对应的解决思路
8.不同尺寸的iphone应用的适配都有几种办法,优缺点?
我表示就用过三种
-** AutoLayout**
直接建立约束条
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeLeft multiplier:1 constant:0]];
VFL
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button=[[UIButton alloc]init];
[button setTitle:@"点击一下" forState:UIControlStateNormal]; button.translatesAutoresizingMaskIntoConstraints=NO;
[button setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:button];
NSArray *constraints1=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[button]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(button)];
NSArray *constraints2=[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[button(==30)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(button)];
[self.view addConstraints:constraints1];
[self.view addConstraints:constraints2];
}
这是一种痛苦的写法,但是比三方库要靠谱,也不会出现问题。
- Masonry
详细用法请移步Masonry github地址 - SDAutoLayout
详细用法请移步SDAutoLayout github地址
-Apple设备尺寸和编程尺寸
以下是面试问的问题(回忆一下也是醉了,绝对的大牛啊,我就是当时知道答案,也会被问蒙蔽的)
1 项目中加锁的场景以及加锁的用法?
我还是太菜,还是看别人的文章吧
深入理解 iOS 开发中的锁 作者 bestswifter