iOS面试题(上) - Go语言中文社区

iOS面试题(上)


面试题1

  1. 定义属性时, 什么情况使用copy, assignretain?

property关键字:readonly, readwrite, assign, retain, copy, nonatomic, strong, weak, unsafe_unretained

readwrite此标记说明属性会被当成读写的,这也是默认属性。设置器和读取器都需要在@implementation中实现。如果使用@synthesize关键字,读取器和设置器都会被解析。

readonly此标记说明属性是只读的,默认的标记是读写,如果你指定了只读,在@implementation中只需要一个读取器。或者如果你使用@synthesize关键字,也是有读取器方法被解析。而且如果你试图使用点操作符为属性赋值,你将得到一个编译错误。

assign: 赋值特性=(仅设置变量时, setter方法将传入参数赋值给实例变量), 一般常用于基本数据类型, 常见委托设计模式, 以此来防止循环引用.
assigin 可以用非 OC 对象,而 weak 必须用于 OC 对象

retain: 持有特性, 保留计数, 获得到对象的所有权, 引用计数(reference counting)在原有的基础上+1
例如当使用malloc分配了一块内存,并把它的地址赋值给了指针a,后来如果希望指针b也共享这块内存,于是讲a赋值给(assgin)b。这时就用到了assgin,此时a和b指向同一块内存。但是现在问题出现了,当a不再需要这块内存时,能都直接释放呢?肯定是不能的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块内存的时候引起程序crash

copy:是你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。(引申出深拷贝, 浅拷贝)

NSString属性什么时候用copy,什么时候用strong?
iOS 集合的深复制与浅复制
对于字符串,通常都是使用copy的方式。虽然使用strong似乎也没有没有问题,但是事实上在开发中都会使用copy。为什么这么做?因为对于字符串,我们希望是一次内容的拷贝,外部修改也不会影响我们的原来的值,而且NSString类遵守了NSCopying, NSMutableCopying, NSSecureCoding协议。
下面是使用copy的方式,验证如下:

NSString *hahaString = @"哈哈"; 
NSString *heheString = [hahaString copy]; 
// 哈哈, 哈哈 
NSLog(@"%@, %@", hahaString, heheString); 
heheString = @"呵呵"; 
// 哈哈, 呵呵 
NSLog(@"%@, %@", hahaString, heheString);

我们修改了heheString,并不会影响到原来的hahaStringcopy一个对象变成新的对象(新内存地址) 引用计数+1 原对象计数不变。

nonatomic:非原子性访问,对属性赋值的时候不加锁,多线程并发访问会提高性能。如果不加此属性,则默认是两个访问方法都为原子性访问。
atomicObjc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择

strong, weak, unsafe_unretainedARC引入的

strong:相当于retain,但是对于有的类型,例如NSString,则使用strong相当于使用copy这样直接用strong就可以直接处理retainstrong的情况了。

weak:相当于assign,但是比后者多一点:对象被销毁时会将weak引用设为nil,而对nil发送消息都不会导致崩溃否则weak引用为野指针,会出现问题.

unsafe_unretained:用unsafe_unretained声明的指针,指针指向的对象一旦被释放,这些指针将成为野指针。

使用@property配合@synthesize可以让编译器自动实现getter/setter方法,使用的时候也很方便,可以直接使用“对象.属性”的方法调用;如果我们想要”对象.方法“的方式来调用一个方法并获取到方法的返回值,那就需要使用@property配合@dynamic
使用@dynamic关键字是告诉编译器由我们自己来实现访问方法。如果使用的是@synthesize,那么这个工作编译器就会帮你实现了

2.怎样启动一个新线程, 子线程怎样刷新UI?

刷新UI
方法1:

[self performSelectorOnMainThread:@selector(updateUI:) withObject:nil waitUntilDone:YES];

方法2:

dispatch_async(dispatch_get_global_queue(0, 0), ^{ 
// 处理耗时操作的代码块... 

  //通知主线程刷新  
  dispatch_async(dispatch_get_main_queue(), ^{ 
  //回调或者说是通知主线程刷新,  

  }); 
});

3.KVO是什么? �内部是怎样实现的?

KVO是实现Cocoa Bindings的基础, 它提供了一种方法, 当某个属性改变时, 相应的objects会被通知到. 在其他语言中, 这种观察者模式通常需要单独实现, 而在OC中, 通常无须增加额外代码即可使用.

实现: 通过Objective-C强大的运行时(runtime)实现的. 当你第一次观察某个object时, runtime会创建一个新的继承原先class的subclass, 在这个新的class中, 它重写了所有被观察的key, 然后将object的isa指针指向新创建的class(这个指针告诉Objective-C运行时某个object到底是哪种类型的object). 所以object神奇的变成了新的子类的实例.

这些被重写的方法实现了如何通知观察者们。当改变一个key时,会触发setKey方法,但这个方法被重写了,并且在内部添加了发送通知机制。(当然也可以不走setXXX方法,比如直接修改iVar,但不推荐这么做)。

有意思的是:苹果不希望这个机制暴露在外部。除了setters,这个动态生成的子类同时也重写了-class方法,依旧返回原先的class!如果不仔细看的话,被KVO过的object看起来和原先的object没什么两样。

KVO依赖于NSObject 的两个方法: willChangeValueForKey: 和didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey: 一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey: 会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。
原博客链接

4.写出对所有类进行扩展的几种方式.
类目, 延展, 协议, 继承

5.利用 NSOperationNSOperationQueue 处理多线程时, 有3个 NSOperation 分别为A, B, C, 要求A, B执行完之后, 才执行 C, 如何做?

// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
// 创建3个操作
// 同步执行一个操作
NSOperation *a = [NSBlockOperation blockOperationWithBlock:^{
  NSLog(@"a");
}];
NSOperation *b = [NSBlockOperation blockOperationWithBlock:^{
  NSLog(@"b");
}];
NSOperation *c = [NSBlockOperation blockOperationWithBlock:^{
  NSLog(@"c");
}];
    
[b addDependency:a];
[c addDependency:b];
    
[queue addOperation:a];
[queue addOperation:b];
[queue addOperation:c];

6.构造5个 string 对象, 并添加到数组中, 对 array 中的元素按字母排序, 遍历 array 输出 string 内容



NSMutableArray *arr = @[@"qda", @"adsg", @"rwf", @"wrwev", @"vbwer"].mutableCopy;
    arr = [arr sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)].mutableCopy;
    for (NSString *str in arr) {
        NSLog(@"%@", str);
    }

面试题2

1.该函数输出是什么?

main()
{
  int a[5] = {1, 2, 3, 4, 5};
  int *ptr = (int *)(&a + 1);
  printf("%d, %d", *(a+1), *(ptr - 1));
}

输出:2, 5

2.有一个1G大小的一个文件, 里面每一行是一个词, 词的大小不超过16字节.
内存限制大小是1M, 返回频数里面最高的100个词.

3.HTTP 协议 1xx, 2xx, 3xx, 4xx, 5xx的含义. 204, 304的含义

HTTP状态码是五个不同的类别:

  • 1XX临时/信息响应
  • 2XX成功
  • 3XX重定向
  • 4XX客户端/请求错误
  • 5XX服务器错误

204(无内容): 服务器成功处理了请求,但没有返回任何内容。
304(未修改): 自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
如果网页自请求者上次请求后再也没有更改过,您应将服务器配置为返回此响应(称为 If-Modified-Since HTTP 标头)。服务器可以告诉 Googlebot 自从上次抓取后网页没有变更,进而节省带宽和开销。
4.给出 cocoa touch 框架

Cocoa Touch框架
除 UIKit 之外,Cocoa Touch 包含创建世界一流 iOS 应用程序所需的所有框架,从 3D 图形、专业音频到网络,甚至提供特殊设备访问 API 以控制摄像机或从 GPS 硬件获取位置。Cocoa Touch 既包含只需要几行代码就可以完成全部任务的强大的 Objective-C 框架,也在需要时提供基础的 C 语言 API 来直接访问系统。这些框架示例包括:

  • 通过 Core Animation,您就可以通过基于组合独立图层的简单编程模型来创建丰富的用户体验。
  • Core Audio 是播放、处理和录制音频的专业级技术,能够轻松为您的应用程序添加强大的音频功能。
  • Core Data 提供面向对象的数据管理解决方案,该方案易于使用和理解,甚至可处理任何应用或大或小的数据模型。

拓展:
iphone 技术层
Cocoa Touch 层由多个框架组成,他们为应用程序提供了核心功能。
UIKit 负责启动和结束应用程序,控制界面和多触点事件
Map Kit 提供地图的相关服务,定位或者区域检测等
Game Kit 创建和使用网络机制
Message UI/Address Book UI 提供操作电子邮件和联系人的信息

5.用OC, 自己实现一个 AutoReleasePool.

6.NSThread, NSOperation, GCD, 各有什么特点, 使用需要注意什么?

NSThread.
每个NSThread对象对应一个线程,量级较轻(真正的多线程)
NSThree是官方推荐的线程处理方式,它在处理机制上,需要开发者负责手动管理Thread的生命周期,包括子线程与主线程之间的同步等。线程共享同一应用程序的部分内存空间,它们拥有对数据相同的访问权限。你得协调多个线程 对同一数据的访问,一般做法是在访问之前加锁,这会导致一定的性能开销。在 iOS 中我们可以使用多种形式的 thread。 比其他两个轻量级 需要自己管理线程的生命周期,线程同步。 线程同步对数据的加锁会有一定的系统开销.

NSOperation/NSOperationQueue 面向对象的线程技术
如果需要让线程同时并行运行多个,可以将线程加入队列(Queue)中,NSOperationQueue类就是一个线程队列管理类,他提供了线程并行、队列的管理。可以认为NSOperationQueue就是一个线程管理器,通过addOperations方法,我们可以一次性把多个(数组形式)线程添加到队列中。同时,NSOperationQueue允许通过setMaxConcurrentOperationCount方法设置队列的并行(同一时间)运行数量

Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。该方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术,它看起来象就其它语言的闭包(Closure)一样,但苹果把它叫做blocks。
GCD —— Grand Central Dispatch(大调度中心) 是基于C语言的框架,可以充分利用多核,是苹果推荐使用的多线程技术
以上这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的,在项目中很多框架技术分别使用了不同多线程技术。

三种多线程技术的对比                          
NSThread:–优点:NSThread 比其他两个轻量级,使用简单–缺点:需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有一定的系统开销

NSOperation:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上–NSOperation是面向对象的

  • 优点: 提供了一些在GCD中不容易实现的特性,如:限制最大并发数量,操作之间的依赖关系.

GCD:NSOperation的高效和强大的技术–GCD是基于C语言的

  • 优点1:用Block定义任务,使用起来非常灵活便捷;(要注意:也可能出现循环引用)
  • 优点2:提供了更多的控制能力以及操作队列中所不能使用的底层函数.

7.分别介绍下 KVO, KVC, NOtification, Delegate 使用场景.

iOS 如何选择delegate、notification、KVO?

KVC,即是指 NSKeyValueCoding,一个非正式的Protocol,提供一种机制来间接访问对象的属性。而不是通过调用Setter、Getter方法访问。KVO 就是基于 KVC 实现的关键技术之一。
尽量使用KVC可以大大地减少我们的代码量,当遇到property的时候,可以多想想是否可以KVC来帮助我,是否可以用KVC来重构代码, 当需要加入observer模式时,可以考虑下KVO, 在高性能的observer里面,KVO会给我们很好的帮助。

8.在 - (void)scrollViewDidScroll:(UIScrollView *)scrollView 如何判断滚动是用户手动引发的.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (UIGestureRecognizerStateBegan == scrollView.panGestureRecognizer.state) {
        NSLog(@"手动发出");
    }
}

面试题3

1.下面的代码循环了几次?

int i = 0;
while(i < 6) {
if(i == 5) {
  continue;
  }  
  i++;
}

死循环

2.UITextFieldUITextView 有什么区别?

UITextField:
1.UITextField只能单行输入
2.有placehoder属性设置占位文字
3.继承自UIControl
4.监听行为包括:

  • 1> 设置代理
  • 2> addTarget:action:forControlEvents:
  • 3> 通知:UITextFieldTextDidChangeNotification

UITextView:
1.支持多行输入并且可以滚动显示浏览全文
2.不能设置占位文字
3.继承自UIScollView
4.监听行为包括:

  • 1> 设置代理
  • 2> 通知:UITextViewTextDidChangeNotification

3.把一段文本用你已知的控件显示两种颜色? 尽可能说出你的方法.

方法1:NSAttributedString/NSMutableAttributedString

NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:@"我们结婚吧"];
    [str addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, 2)];
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];
    [self.view addSubview:label];
    label.attributedText = str;

4.objc 中向一个 nil 对象发送消息将会发生什么?

在 Objective-C 中向 nil 发送消息是完全有效的——只是在运行时不会有任何作用:
如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)。例如:

Person * motherInlaw = [[aPerson spouse] mother];

如果 spouse 对象为 nil,那么发送给 nil 的消息 mother 也将返回 nil。

如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,long double 或者 long long 的整型标量,发送给 nil 的消息将返回0。
如果方法返回值为结构体,发送给 nil 的消息将返回0。结构体中各个字段的值将都是0。
如果方法的返回值不是上述提到的几种情况,那么发送给 nil 的消息的返回值将是未定义的。

5.有这样一段 json 数据: {"title":null}, 转成字典之后将 title 对应的 value 赋值在一个
label.text, 会出现什么问题?
将该数据解析之后数据变为

title = <null>

这个数据类型不是nil 也不是 String。 解析成对象之后,如果直接向这个对象发送消息(eg:length,count 等等)就会直接崩溃。提示错误为:


-[NSNull length]: unrecognized selector sent to instance 0x388a4a70

解决方案

6.一个列表有足够多的显示区域, 滑动了一下, 如何判断向上滑动还是向下滑动了? 请详细说明.

int _lastPosition;  //临时值
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    int currentPostion = scrollView.contentOffset.y;
    
    if (currentPostion - _lastPosition > 0) {
        _lastPosition = currentPostion;
        NSLog(@"ScrollUp now");
    }
    else if (_lastPosition - currentPostion > 0)
    {
        _lastPosition = currentPostion;
        NSLog(@"ScrollDown now");
    }
}

7.有两个字符串 @"hello", @"world", 你有几种方法将它们拼接在一起?

NSString* string1, string2; //已存在的字符串,需要将string1和string2连接起来
//方法1.
string = [NSString initWithFormat:@"%@,%@", string1, string2 ];

//方法2.
string = [string1 stringByAppendingString:string2];

//方法3 .
string = [string stringByAppendingFormat:@"%@,%@",string1, string2];

面试题4

1.现在有一个数组, 数组里面是整数, 用你认为最优的算法找出里面第 k 大的元素.

2.一个理发店有一个入口和一个出口. 理发店内有一个5人沙发, 1个理发师. 新来的顾客坐在沙发上等待. 理发师可从事理发和休息两种活动. 理发店的活动满足下列条件:

    1. 休息的理发师是坐在自己专用的理发椅上, 不会占用顾客的沙发;
    1. 处理休息状态的理发师可为在沙发上等待时间最长的顾客理发;
    1. 理发时间长短由理发师决定;

适用信号量机制或管程机制实现理发师进程和顾客进程, 可以用语言表述.

3.如果现在需要让 UILabel 进行交互(可以点击响应事件), 有哪些方式?

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(60, 0, self.view.frame.size.width - 60, self.view.frame.size.height)];
    
    label.userInteractionEnabled= YES;
    UITapGestureRecognizer *labelTapGestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(labelTouchUpInside:)];

    [label addGestureRecognizer:labelTapGestureRecognizer];
} 

-(void) labelTouchUpInside:(UITapGestureRecognizer *)recognizer{
    NSLog(@"被点击了");
}

UILabel 也是一个UIView,同样继承自UIResponder,所以只要扩展UILabel,并覆盖相关方法就可以了,如:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
// 点击该label的时候, 来个高亮显示
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self setTextColor:[UIColor whiteColor]];
}

// 还原label颜色,获取手指离开屏幕时的坐标点, 在label范围内的话就可以触发自定义的操作
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self setTextColor:COLOR(59,136,195,1.0)];
    UITouch *touch = [touches anyObject];
    CGPoint points = [touch locationInView:self];
    if (points.x >= self.frame.origin.x && points.y >= self.frame.origin.x && points.x <= self.frame.size.width && points.y <= self.frame.size.height)
    {
        [delegate myLabel:self touchesWtihTag:self.tag];
    }
}

4.UILabel 是否可以显示 html 文本? 如果可以怎么显示?

NSString * htmlString = @"<html><body> Some html string n <font size="13" color="red">This is some text!</font> </body></html>";

NSAttributedString * attrStr = [[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];

UILabel * myLabel = [[UILabel alloc] initWithFrame:self.view.bounds];

myLabel.attributedText = attrStr;

[self.view addSubview:myLabel];

5.你在工作中最经常使用什么来进行布局和屏幕适配? 简单描述一下你遇到的问题?
masonry(本质上是界面约束的语法糖), xib

6.简单描述 UITableView 的重用机制
链接
7.ViewControllerloadView, viewDidLoad, viewDidUnload 分别是什么时候调用的, 在使用 ViewController 时在这几个函数中应该做什么工作?
链接


面试题5

1.声明 @propertyNSString 属性用 copystrong 修饰的区别?
同面试题1
2.请说明一下参数区别: assign, weak, unsafe_unretain, __block__weak
同面试题1
3.@synthesize@dynamic 分别有什么作用?
同面试题1
4.在 ARC 的项目中, 会出现内存泄露问题吗? 请举例说明.
链接
5.描述一个 Block 里循环引用的实例.

链接
对象有一个Block属性,然而这个Block属性中又引用了对象的其他成员变量,那么就会对这个变量本身产生强应用,那么变量本身和他自己的Block属性就形成了循环引用

6.NSNotificationKVO 区别, 各举例一个应用场景.
面试题2

7.loadView 是干嘛用的?
面试题4

8.描述 viewWillLayouSubView 的执行过程

9.setNeedsLayout, layoutNeeded, setNeedsDisplay, 它们的作用是什么?

  • setNeedsDisplay调用drawRect方法来实现view的绘制
  • setNeedsLayout则调用layoutSubView来实现view中subView的重新布局

10.如何高性能的给 UIImageView 加个圆角? (不推荐layer.cornerRadius!)
方法一:最简单的方法, 但是会严重损耗性能

self.imageView=[[UIImageView alloc] initWithFrame:CGRectMake(100,200, 100, 100)];
    [self.imageView setImage:[UIImage imageNamed:@"918BB156-1FBA-47B7-89D6-4F53518BBEED.jpg"]];
    self.imageView.layer.cornerRadius = 50;
    self.imageView.layer.masksToBounds = YES;
    [self.view addSubview:self.imageView];

方法二:设置 Rasterize栅格化处理, 会将图片放在缓存区,不会不断的进行图片渲染

    self.imageView =  [[UIImageView alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
    [self.view addSubview:self.imageView];
    [self.imageView setImage:[UIImage imageNamed:@"918BB156-1FBA-47B7-89D6-4F53518BBEED.jpg"]];
    self.imageView.layer.cornerRadius = 100;
    self.imageView.layer.shouldRasterize = YES;
    self.imageView.clipsToBounds = YES;
    //不设置会模糊,不相信可以自己尝试
    self.imageView.layer.rasterizationScale = [UIScreen mainScreen].scale;

方法三:贝塞尔曲线

    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
    
    UIImage *image = [UIImage imageNamed:@"918BB156-1FBA-47B7-89D6-4F53518BBEED.jpg"];
    
    // 设置绘制环境
    UIGraphicsBeginImageContextWithOptions(self.imageView.bounds.size, NO, 1);
    
    // 在绘制之前先剪出一个圆形
    [[UIBezierPath bezierPathWithRoundedRect:self.imageView.bounds cornerRadius:100] addClip];
    
    // 图片在设置的圆形里面绘制
    [image drawInRect:self.imageView.bounds];
    
    // 获取照片
    self.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
    
    // 结束绘制
    UIGraphicsEndImageContext();
    
    [self.view addSubview:self.imageView];

11.BAD_ACCESS 在什么情况下出现? 如何调试?

如何调试BAD_ACCESS错误

12.什么叫做符号化(Symbolication)?
链接

13.什么是运行时(Runtime)? Method Swizzling 呢?
Runtime:Objective-C的动态特性
Method Swizzling:方法交换

14.什么是 Runloop ? Runloop 和线程有什么关系?
深入理解RunLoop
15.MD5Base64 的区别, 各自场景是什么?

参考答案:
做过加密相关的功能的,几乎都会使用到MD5和Base64,它们两者在实际开发中是最常用的。

MD5:是一种不可逆的摘要算法,用于生成摘要,无法逆着破解得到原文。常用的是生成32位摘要,用于验证数据的有效性。比如,在网络请求接口中,通过将所有的参数生成摘要,客户端和服务端采用同样的规则生成摘要,这样可以防篡改。又如,下载文件时,通过生成文件的摘要,用于验证文件是否损坏。

Base64:属于加密算法,是可逆的,经过encode后,可以decode得到原文。在开发中,有的公司上传图片采用的是将图片转换成base64字符串,再上传。在做加密相关的功能时,通常会将数据进行base64加密/解密。

  1. 写出以下代码的输出结果
dispatch_queue_t queue = dispatch_queue_create("my.label", DISPATCH_QUEUE_SERIAL);
    
    NSLog(@"1");
    
    dispatch_async(queue, ^{
        
        NSLog(@"2");
        
        dispatch_sync(queue, ^{
            
            NSLog(@"3");
            
        });
        
        NSLog(@"4");
        
    });
    
    NSLog(@"5");

输出结果:

1
5
2

17.根据你之前做过的项目, 描述一个缓存模型或者框架(例如图片内存缓存器)

--

面试题6

  1. 用伪代码实现递归的快速排序算法.
  2. 简述一下 UITableView 的框架和使用方法.
    比较详细的介绍了UITableView
  3. 简述 ASIHTTPRequest 的使用方法
    该作者已经停止更新 没使用过
    链接
  4. 简述 iOS 的单元测试方法.
    链接
  5. abcde 入栈, 不可能的出栈顺序.
    不可能的出栈顺序: 1.ECDBA 2.DCEAB
    1.在E先出栈的情况下(说明此时abcde均已入栈),不可能出现C在D之前出栈
    2.AB均入栈的情况下, A不可能在B之前出栈
  6. int find(int *a, int n, int count)count 为 a 数组长度; n 为要查找的数, 假设 a 为有序的数组.
  7. 为什么很多内置的类, 如 Table ViewControllerdelegate 的属性是 assign 不是 retain ?
    防止在ARC情况下出现循环引用
  8. 由于 UDID 这些无法被调用了, 有什么方法可以确定 iOS 设备的唯一性
    链接
  9. 列举一下自己遇到过的 iOS App 审核被拒的解决经历

面试题7

1.简述OC中内存管理机制。与 retain 配对使用的方法是 dealloc 还是 release ,为什么?需要与 alloc 配对使用的方法是 dealloc 还是 release ,为什么? readwritereadonlyassignretaincopynonatomicatomicstrongweak 属性的作用?
面试题1
2.类变量的 @protected , @private , @public , @package ,声明各有什么含义?

  • @private 实例变量只能被声明它的类访问
  • @protected 实例变量能被声明它的类和子类访问, 如果没有自定义关键字, 是默认的选项
  • @public 实例变量可以被在任何地方访问
  • @package Objective-C中的@package与C语言中变量和函数的private_extern类似。任何在实现类的镜像之外的代码想使用这个实例变量都会引发link error(作用域:只能在声明的文件中使用)

3.线程是什么?进程是什么?二者有什么区别和联系?
进程与线程的一个简单解释
进程和线程的区别?

4.谈谈你对多线程开发的理解?iOS中有几种实现多线程的方法?
关于iOS多线程,你看我就够了

5.线程同步和异步的区别?IOS中如何实现多线程的同步?
关于iOS多线程,你看我就够了

6.假设有一个字符串aabcad,请写一段程序,去掉字符串中不相邻的重复字符串,即上述字符串处理之后的输出结果为:aabcd

NSMutableString *str = @"aabcad".mutableCopy;
    NSMutableArray *marry = [[NSMutableArray alloc]init];
    for (int i = 0; i < str.length - 1; i++) {
        unsigned char a = [str characterAtIndex:i];
        for (int j = i + 1; j < str.length; j++) {
            unsigned char b = [str characterAtIndex:j];
            if (a == b) {
                if (j == i + 1) {
                    
                } else {
                    [marry addObject:[NSString stringWithFormat:@"%d",j]];
                }
            }
        }
    }
    for (int i = (int)marry.count - 1; i > 0; i--) {
        
        NSInteger num = [[marry objectAtIndex:i]intValue];
        
        [str deleteCharactersInRange:NSMakeRange(num, 1)];
    }
    
    NSLog(@"%@", str);

7.获取一台设备唯一标识的方法有哪些?
链接

8.iOS类是否可以多继承?如果没有,那可以用其他方法实现吗?简述实现过程。
没有 用 类目延展 可以实现

9.堆和栈的区别?
栈区(stack):由编译器自动分配释放,存放函数的参数值、局部变量的值。先进后出
堆区(heap):一般由程序员分配释放。先进先出
全局区(静态区)(static):全局变量和静态变量。程序结束后由系统释放。
常量区:常量字符串存放在这里。程序结束后由系统释放。
代码区:存放函数体的二进制文件。

10.iOS本地数据存储都有哪几种方式?

  • 1.plist文件存储
  • 2.NSUserDefaults
  • 3.NSKeyedArchiver:(归档)采用归档的形式来保存数据,该数据对象需要遵守NSCoding协议,并且该对象对应的类必须提供encodeWithCoder:和initWithCoder:方法。
  • 4.Write写入方式:永久保存在磁盘中。但是只支持NSString、 NSData、NSArray、NSDictionary
  • 5.SQLite(FMDB):注意FMDB不是数据库, 而是一个SQLite管理框架.
  • 6.CoreData:切记CoreData不是数据库, 他的存储核心思想是托管对象, 只是咱们经常用的存储文件为SQLite.还可以用XML, 二进制等方式. CoreData入门

11.iOS动态类型和动态绑定、动态载入

  • 1.动态类型:如id类型。实际上静态类型因为其固定性和可预知性而使用得更加广泛。静态类型是强类型,而动态类型属于弱类型。运行时决定接收者。
  • 2.动态绑定:让代码在运行时判断需要调用什么方法,而不是在编译时。与其他面向对象语言一样,方法调用和代码并没有在编译时连接在一起,而是在消息发送时才进行连接。运行时决定调用哪个方法。
  • 3.动态载入:让程序在运行时添加代码模块以及其他资源, 用户可以根据需要加载一些可执行代码和资源,而不是在启动时就加载所有组件。可执行代码中可以含有和程序运行时整合的新类。

Objective-C多态:动态类型识别+动态绑定+动态加载


面试题8

1.写出方法获取iOS内存使用情况。

// 获取当前设备可用内存及所占内存的头文件
#import <sys/sysctl.h>
#import <mach/mach.h>
// 获取当前设备可用内存(单位:MB)
- (double)availableMemory
{
  vm_statistics_data_t vmStats;
  mach_msg_type_number_t infoCount = HOST_VM_INFO_COUNT;
  kern_return_t kernReturn = host_statistics(mach_host_self(), 
                                             HOST_VM_INFO, 
                                             (host_info_t)&vmStats, 
                                             &infoCount);
  
  if (kernReturn != KERN_SUCCESS) {
  return NSNotFound;
  }
  return ((vm_page_size *vmStats.free_count) / 1024.0) / 1024.0;
}
// 获取当前任务所占用的内存(单位:MB)
- (double)usedMemory
{
  task_basic_info_data_t taskInfo;
  mach_msg_type_number_t infoCount = TASK_BASIC_INFO_COUNT;
  kern_return_t kernReturn = task_info(mach_task_self(), 
                                       TASK_BASIC_INFO, 
                                       (task_info_t)&taskInfo, 
                                       &infoCount);

  if (kernReturn != KERN_SUCCESS) {
  return NSNotFound;
  }
  return taskInfo.resident_size / 1024.0 / 1024.0;}

2.深拷贝和浅拷贝的理解?
见上面题

3.怎样实现一个singleton的类。

+ (Singleton *) sharedInstance {
    static Singleton *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[Singleton alloc] init];
    });
    
    return sharedInstance;
}

链接

4.什么是安全释放?
把对象指着置为nil,再对其释放

5.RunLoop是什么?
一个RunLoop就是一个事件处理的循环,用来不停的调度工作以及处理输入时间。使用runloop的目的是让你的线程在有工作的时候忙于工作,而没工作的时候处于休眠状态。runloop的设计是为了减少cpu无谓的空转。每个开辟的线程都有一个Runloop, 主线程的Runloop时默认开启的, 咱们手动开辟的子线程Runloop是默认不开启的, 如果需要开启, 需要调用

API[[NSRunloop   currentRunloop] run]

开启.最常见的需要开启Runloop的是在子线程里面调用计时器(NSTimer), 如果不开启 runloop循环方法就不能正常执行.

深入理解RunLoop

6.什么是序列化和反序列化,可以用来做什么?如何在OC中实现复杂对象的存储?

如果你需要存储一个复杂的对象的话,经常要以二进制的方法序列化这个对象,这个过程叫Archiving。如果一个对象需要进行序列化,那么需要遵循NScoding协议,主要有两个方法: -(id)initWithCoder:(NSCoder)coder;//从coder中读取数据,保存到相应变量中,即反序列化数据。 -(void)encodeWithCoder:(NSCoder)coder;//读取实例变量,并把这些数据写到coder中去,即序列化数据。
主要用于存储对象状态为另一种通用格式,比如存储为二进制、xml、json等等

7.写一个标准宏MIN,这个宏输入两个参数并返回较小的一个?

#define MIN_NUMBER(a, b) ((a)<(b))?(a):(b)

运算符优先级(不加括号可能会出现歧义)

8.iphone os有没有垃圾回收机制?简单阐述一下OC内存管理。
iphone os没有垃圾回收机制。
垃圾回收机制用于在空闲时间以不定时的方式动态的回收无任何引用的对象占据的内存空间

OC内存管理:
OC的内存管理机制是引用计数, 内存管理原则是谁开辟谁释放, 有retain就要有release.
.分为ARC(自动引用计数)和MRC(非自动引用计数), 在MRC下, 我们需要手动管理内存,需要使用到 retain/copy/release/autorelease等方法实现内存管理, ARC下一般不需要程序员手动管理内存, 系统会为程序添加自动释放池以实现内存管理, 当然, 咱们说的一般不需要不能理解为完全不需要考虑内存问题, 比如在解决block循环引用问题的时候, 就需要使用__weak修饰, 需要注意的是ARC和MRC下解决循环引用的方法还不一样,MRC下是__block, ARC下是__weak .

9.简述应用程序按Home键进入后台时的生命周期,以及从后台回到前台时的生命周期?
进入后台的生命周期:

- (void)applicationWillResignActive:(UIApplication *)application {   
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
}

回到前台的生命周期

- (void)applicationWillEnterForeground:(UIApplication *)application {
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
}

10.ViewControllerallocloadView, viewDidLoad,viewWillAppear, viewDidUnload, deallocinit分别是在什么时候调用的?在自定义ViewController的时候这几个函数里面应该做什么工作?

alloc初始化当前的ViewController
loadView:没有正在使用nib视图页面,子类将会创建自己的自定义视图层
viewDidLoad:试图被加载后调用
viewWillAppear:试图即将出现的时候调用
viewDidUnload:<iOS6之后废弃>当系统内存吃紧的时候会调用该方法,释放掉当前未在window中显示的试图和对应的控制器

版权声明:本文来源简书,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://www.jianshu.com/p/6a57c6e902e8
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-01-12 13:36:21
  • 阅读 ( 1152 )
  • 分类:面试题

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢