swift面试题及答案

1   MVVM

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

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中使用分号,比如在循环语句中。

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值