swift面试题及答案

it2022-05-05  116

1   MVVM

给MVC解耦 解重 双向绑定 详情解答 https://blog.csdn.net/sun6223508/article/details/95453167

2 Alamofire怎么实现的

使用线程池 文件图片上传代码基于TCP/IP 网络提交基于URLSession.dataTask URLRequest

3 frame 和 bounds 有什么不同?

frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父view的坐标系统) bounds指的是:该view在本身坐标系统中的位置和大小。(参照点是屏幕坐标系统)

4 runtime是怎么实现的 ,那些地方用到了

obj_msgsend     黑魔法  tableview没数据时  添加一个view 字典转模型 模型转字典 class_propertyList   property_getName 自定义KVO   isa指针  NSKVONotifying_B 详情 https://blog.csdn.net/sun6223508/article/details/96101302

5 runloop流程

6  浅拷贝和深拷贝的区别? 

浅拷贝:只复制指向对象的指针,而不复制引用对象本身。 深拷贝:复制引用对象本身。内存中存在了两份独立对象本身,当修改A时,A_copy不变。

7 怎么定义数组

var  arry:[String] = []  或  var arr:Array<String> = Array<String>()

8 switf 2.0增加了一个新的关键字来实现递归枚举。enum List{ case Node(T,List)}什么关键字可以实现递归枚举?

indirect关键值可以允许递归枚举,代码如下:   enum List{ indirect case Cons{T,List)}

9 Category(类别)、 Extension(扩展)和继承的区别

区别: 1. 分类有名字,类扩展没有分类名字,是一种特殊的分类。 2. 分类只能扩展方法(属性仅仅是声明,并没真正实现),类扩展可以扩展属性、成员变量和方法。 3. 继承可以增加,修改或者删除方法,并且可以增加属性。

10 oc 系统对象的 copy 与 mutableCopy 方法

一、非集合类对象的copy与mutableCopy 在非集合类对象中,对不可变对象进行copy操作,是指针复制,mutableCopy操作是内容复制; 对可变对象进行copy和mutableCopy都是内容复制。用代码简单表示如下: NSString *str = @"hello word!"; NSString *strCopy = [str copy] // 指针复制,strCopy与str的地址一样 NSMutableString *strMCopy = [str mutableCopy] // 内容复制,strMCopy与str的地址不一样 NSMutableString *mutableStr = [NSMutableString stringWithString: @"hello word!"]; NSString *strCopy = [mutableStr copy] // 内容复制 NSMutableString *strMCopy = [mutableStr mutableCopy] // 内容复制 二、集合类对象的copy与mutableCopy (同上) 在集合类对象中,对不可变对象进行copy操作,是指针复制,mutableCopy操作是内容复制; 对可变对象进行copy和mutableCopy都是内容复制。但是:集合对象的内容复制仅限于对象本身,对集合内的对象元素仍然是指针复制。(即单层内容复制) NSArray *arr = @[@[@"a", @"b"], @[@"c", @"d"]; NSArray *copyArr = [arr copy]; // 指针复制 NSMutableArray *mCopyArr = [arr mutableCopy]; //单层内容复制 NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil]; NSArray *copyArr = [mutableArr copy]; // 单层内容复制 NSMutableArray *mCopyArr = [mutableArr mutableCopy]; // 单层内容复制 【总结一句话】: 只有对不可变对象进行copy操作是指针复制(浅复制),其它情况都是内容复制(深复制)!

11 ViewController生命周期

按照执行顺序排列: 1. initWithCoder:通过nib文件初始化时触发。 2. awakeFromNib:nib文件被加载的时候,会发生一个awakeFromNib的消息到nib文件中的每个对象。 3. loadView:开始加载视图控制器自带的view。 4. viewDidLoad:视图控制器的view被加载完成。 5. viewWillAppear:视图控制器的view将要显示在window上。 6. updateViewConstraints:视图控制器的view开始更新AutoLayout约束。 7. viewWillLayoutSubviews:视图控制器的view将要更新内容视图的位置。 8. viewDidLayoutSubviews:视图控制器的view已经更新视图的位置。 9. viewDidAppear:视图控制器的view已经展示到window上。 10. viewWillDisappear:视图控制器的view将要从window上消失。 11. viewDidDisappear:视图控制器的view已经从window上消失。

12 如何对iOS设备进行性能测试?

Profile-> Instruments ->Time Profiler

13  开发项目时你是怎么检查内存泄露?

1). 静态分析 analyze。 2). instruments工具里面有个leak可以动态分析。

14 delegate 和 notification 的区别

1). 二者都用于传递消息,不同之处主要在于一个是一对一的,另一个是一对多的。 2). notification通过维护一个array,实现一对多消息的转发。 3). delegate需要两者之间必须建立联系,不然没法调用代理的方法;notification不需要两者之间有联系。

15 lldb(gdb)常用的控制台调试命令?

1). p 输出基本类型。是打印命令,需要指定类型。是print的简写 p (int)[[[self view] subviews] count] 2). po 打印对象,会调用对象description方法。是print-object的简写 po [self view] 3). expr 可以在调试时动态执行指定表达式,并将结果打印出来。常用于在调试过程中修改变量的值。 4). bt:打印调用堆栈,是thread backtrace的简写,加all可打印所有thread的堆栈 5). br l:是breakpoint list的简写

16 你一般是怎么用Instruments的? 

Instruments里面工具很多,常用: 1). Time Profiler: 性能分析 2). Zombies:检查是否访问了僵尸对象,但是这个工具只能从上往下检查,不智能。 3). Allocations:用来检查内存,写算法的那批人也用这个来检查。 4). Leaks:检查内存,看是否有内存泄露。

17  iOS的沙盒目录结构是怎样的?

沙盒结构: 1). Application:存放程序源文件,上架前经过数字签名,上架后不可修改。 2). Documents:常用目录,iCloud备份目录,存放数据。(这里不能存缓存文件,否则上架不被通过) 3). Library: Caches:存放体积大又不需要备份的数据。(常用的缓存路径) Preference:设置目录,iCloud会备份设置信息。 4). tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能。

18 什么是 TCP / UDP ? 

TCP:传输控制协议。 UDP:用户数据协议。 TCP 是面向连接的,建立连接需要经历三次握手,是可靠的传输层协议。 UDP 是面向无连接的,数据传输是不可靠的,它只管发,不管收不收得到。 简单的说,TCP注重数据安全,而UDP数据传输快点,但安全性一般。

19 通信底层原理(OSI七层模型)  

OSI采用了分层的结构化技术,共分七层: 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。

20 tableView的重用机制?

UITableView 通过重用单元格来达到节省内存的目的: 通过为每个单元格指定一个重用标识符,即指定了单元格的种类,当屏幕上的单元格滑出屏幕时,系统会把这个单元格添加到重用队列中,等待被重用,当有新单元格从屏幕外滑入屏幕内时,从重用队列中找看有没有可以重用的单元格,如果有,就拿过来用,如果没有就创建一个来使用。

21不用中间变量,用两种方法交换A和B的值

// 1.中间变量 void swap(int a, int b) { int temp = a; a = b; b = temp; } // 2.加法 void swap(int a, int b) { a = a + b; b = a - b; a = a - b; } // 3.异或(相同为0,不同为1. 可以理解为不进位加法) void swap(int a, int b) { a = a ^ b; b = a ^ b; a = a ^ b; }

22 排序算法  选择排序、冒泡排序、插入排序三种排序算法

/** * 【选择排序】:最值出现在起始端 * * 第1趟:在n个数中找到最小(大)数与第一个数交换位置 * 第2趟:在剩下n-1个数中找到最小(大)数与第二个数交换位置 * 重复这样的操作...依次与第三个、第四个...数交换位置 * 第n-1趟,最终可实现数据的升序(降序)排列。 * */ void selectSort(int *arr, int length) { for (int i = 0; i < length - 1; i++) { //趟数 for (int j = i + 1; j < length; j++) { //比较次数 if (arr[i] > arr[j]) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } } /** * 【冒泡排序】:相邻元素两两比较,比较完一趟,最值出现在末尾 * 第1趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第n个元素位置 * 第2趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第n-1个元素位置 * …… …… * 第n-1趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第2个元素位置 */ void bublleSort(int *arr, int length) { for(int i = 0; i < length - 1; i++) { //趟数 for(int j = 0; j < length - i - 1; j++) { //比较次数 if(arr[j] > arr[j+1]) { int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } } /** * 折半查找:优化查找时间(不用遍历全部数据) * * 折半查找的原理: * 1> 数组必须是有序的 * 2> 必须已知min和max(知道范围) * 3> 动态计算mid的值,取出mid对应的值进行比较 * 4> 如果mid对应的值大于要查找的值,那么max要变小为mid-1 * 5> 如果mid对应的值小于要查找的值,那么min要变大为mid+1 * */ // 已知一个有序数组, 和一个key, 要求从数组中找到key对应的索引位置 int findKey(int *arr, int length, int key) { int min = 0, max = length - 1, mid; while (min <= max) { mid = (min + max) / 2; //计算中间值 if (key > arr[mid]) { min = mid + 1; } else if (key < arr[mid]) { max = mid - 1; } else { return mid; } } return -1; }

23 求最大公约数

/** 1.直接遍历法 */ int maxCommonDivisor(int a, int b) { int max = 0; for (int i = 1; i <=b; i++) { if (a % i == 0 && b % i == 0) { max = i; } } return max; } /** 2.辗转相除法 */ int maxCommonDivisor(int a, int b) { int r; while(a % b > 0) { r = a % b; a = b; b = r; } return b; } // 扩展:最小公倍数 = (a * b)/最大公约数

24 描述一种在Swift中出现循环引用的情况,并说明怎么解决。

循环引用出现在当两个实例对象相互拥有强引用关系的时候,这会造成内存泄露,原因是这两个对象都不会被释放。只要一个对象被另一个对象强引用,   那么该对象就不能被释放,由于强引用的存在,每个对象都会保持对方的存在。   解决方式:用weak或者unowned引用代替其中一个的强引用,来打破循环引用。

25 闭包是引用类型吗? 

闭包是引用类型。如果一个闭包被分配给一个变量,这个变量复制给另一个变量,那么他们引用的是同一个闭包,他们的捕捉列表也会被复制。

26 你能通过extension(扩展)保存一个属性吗?请解释一下原因。

不能。扩展可以给当前的类型添加新的行为,但是不能改变本身的类型或者本身的接口。如果你添加一个新的可存储的属性,你需要额外的内存来存储新的值。扩展并不能实现这样的任务。

27 在Objective-C中,一个常量可以这样定义: const int number = 0   类似的Swift是这样定义的:

  let number = 0 两者之间有什么不同吗?如果有,请说明原因。

const常量是一个在编译时或者编译解析时被初始化的变量。通过let创建的是一个运行时常量,是不可变的。它可以使用stattic或者dynamic关键字来初始化。谨记它的值只能被分配一次。

28 对一个optional变量拆包有多少种方法?并在安全方面进行评价。

  答案:强制拆包 !操作符——不安全

     隐式拆包变量生命——大多数情况下不安全

     可选绑定——安全

     自判断链接(optional chaining)——安全

     nil coalescing运算符(空值合并运算符)——安全

     Swift2.0的新特性guard语句——安全

     Swift2.0的新特性optional pattern(可选模式)——安全

29 在Swift中,什么时候用结构体,什么时候用类?

  答案:在Swift中,类和结构体有许多不同的特性。下面是两者不同的总结:

  类支持继承,结构体不支持。

  类是引用类型,结构体是值类型

  并没有通用的规则决定结构体和类哪一个更好用。一般的建议是使用最小的工具来完成你的目标,但是有一个好的经验是多使用结构体,除非你用了继承和引用语义。

  注意:在运行时,结构体在性能方面更优于类,原因是结构体的方法调用是静态绑定,而类的方法调用是动态实现的。这就是尽可能得使用结构体代替类的又一个好的原因。

30  下面的代码输出是什么?并说明理由。

  var thing = "cars"    

  let clousure = {[thing] in print("I love (thing)")}

  thing = "airplanes"

  closure()

  答案:输出的是:I love cars。当闭包被声明的时候,捉捕列表就复制一份thing变量,所以被捕捉的值并没有改变,即使你给thing赋予了一个新值。

  如果你要忽视闭包中捕捉列表的值,那么编译器引用那个值而不是复制。这种情况下,被引用变量的值的变化将会反映到闭包中,正如下面的代码所示:

  var thing = "cars"

  let closure = { print("I love (thing)")}

  thing = "airplanes"

  Prints"I love airplanes"

31 思考下面的代码:

  代码:

  var optional1:String? = nil

  var optional2:String? = .None

  nil和.None有什么不同?optional1和optional2有什么不同?

  答案:两者没有什么不同。

  Optional.None(简称.None)是optional变量值初始化的标准方法,而nil只是.None语法的一种修饰。事实上下面语句输出是正确的:

  nil == .None//On Swift1.x this doesnt compile.You need Optional.None记住枚举类型的Optional下的None:

  enum Optional{ case None case Some(T)}

32  view1声明称var类型,view2声明let类型。这里有什么区别吗?下面的最后一行代能编译吗?

  代码:

  import UIKit

  var view1 = UIView()view1.alpha = 0.5

  let  view2 = UIView()view2.alpha = 0.5

  //最后一行代码能编译吗?

  答案:view1是个变量可以重新赋值给一个新的实例化的UIView对象。使用let你只赋值一次,所以下面的代码是不能编译的:

33 Swift中如何定义变量和常量?

  使用let来声明常量,使用var来声明变量

  view2 = view1//Error:view2 is immutable

  但是UIView是一个引用类型的类,所以你可以改变view2的属性,也就是说最后一行代码是可以编译的:

  let view2 = UIView()view2.alpha = 0.5//Yes!

34 分号去哪里了?

  答案:分号在Swift中是可选的,不过出于易读性的目的,苹果建议你不要再使用分号了。但有时候仍会在Swift中使用分号,比如在循环语句中。


最新回复(0)