Swift面试题及答案整理
前言
Swift语言至今诞生有一年多的时间了,已经成为当前最流行语言之一。虽然它的语法简单好用,但实际上Swift是一门非常复杂的语言。因为它不仅是面向对象的同时又是函数式编程语言。本文主要介绍Swift常见的一些面试问题,你可以用这些问题向面试者提问,也可以用来测试你自己目前所掌握的Swift知识,如果你不清楚问题答案的话也不用太担心,因为每个问题下面都有相应的答案。
一、给一个数组,要求写一个函数,交换数组中的两个元素
二X程序员:
好简单啊,直接写出以下结果
funcswap(_nums:inout[Int],_p:Int,_q:Int){ lettemp=nums[p] nums[p]=nums[q] nums[q]=temp }
普通程序员:
首先跟面试官沟通,是什么类型的数组?面试官会说,任意。普通程序员微微一笑,写出以下代码
funcswap<T>(_nums:inout[T],_p:Int,_q:Int){ lettemp=nums[p] nums[p]=nums[q] nums[q]=temp }
文艺程序员:
与面试官沟通,是什么类型的数组?有什么其他要求和限制?面试官会说,这是一个Swift面试题。文艺程序员心领神会,于是写出以下答案
funcswap<T>(_nums:inout[T],_p:Int,_q:Int){ (nums[p],nums[q])=(nums[q],nums[p]) }
同时对以上代码写上相应测试,检测各种边界情况,再确认无误后,才会说,这道题目我完成了。
这道题目看似简单,实际上考察了程序员的审题、交流、以及测试的意识。技术上考察了Swift的泛型和Tuple的性质。
二、下面代码有什么问题
publicclassNode{ publicvarvalue:Int publicvarprev:Node? publicvarpost:Node? publicinit(_value:Int){ self.value=value } }
答案:应该在varprev或者varpost前面加上weak。
原因:表面上看,以上代码毫无问题。但是我这样一写,问题就来了:
lethead=Node(0) lettail=Node(1) head.post=tail tail.prev=head
此时,head和tail互相指向,形成循环引用(retaincycle)。
三、实现一个函数,输入是任一整数,输出要返回输入的整数+2
这道题很多人上来就这样写:
funcaddTwo(_num:Int)->Int{ returnnum+2 }
接下来面试官会说,那假如我要实现+4呢?程序员想了一想,又定义了另一个方法:
funcaddFour(_num:Int)->Int{ returnnum+4 }
这时面试官会问,假如我要实现返回+6,+8的操作呢?能不能只定义一次方法呢?正确的写法是利用Swift的柯西特性:
funcadd(_num:Int)->(Int)->Int{ return{valin returnnum+val } } letaddTwo=add(2),addFour=add(4),addSix=add(6),addEight=add(8)
四、 精简以下代码
funcdivide(dividend:Double?,bydivisor:Double?)->Double?{ ifdividend==nil{ returnnil } ifdivisor==nil{ returnnil } ifdivisor==0{ returnnil } returndividend!/divisor! }
这题考察的是guardlet语句以及optionalchaining,最佳答案是
funcdivide(dividend:Double?,bydivisor:Double?)->Double?{ guardletdividend=dividend,letdivisor=divisor,divisor!=0else{ returnnil } returndividend/divisor }
五、以下函数会打印出什么?
varcar="Benz" letclosure={[car]in print("Idrive\(car)") } car="Tesla" closure()
因为clousre已经申明将car复制进去了([car]),此时clousre里的car是个局部变量,不再与外面的car有关,所以会打印出"IdriveBenz"。
此时面试官微微一笑,将题目略作修改如下:
varcar="Benz" letclosure={ print("Idrive\(car)") } car="Tesla" closure()
此时closure没有申明复制拷贝car,所以clousre用的还是全局的car变量,此时将会打印出"IdriveTesla"
六、以下代码会打印出什么?
protocolPizzeria{ funcmakePizza(_ingredients:[String]) funcmakeMargherita() } extensionPizzeria{ funcmakeMargherita(){ returnmakePizza(["tomato","mozzarella"]) } } structLombardis:Pizzeria{ funcmakePizza(_ingredients:[String]){ print(ingredients) } funcmakeMargherita(){ returnmakePizza(["tomato","basil","mozzarella"]) } } letlombardis1:Pizzeria=Lombardis() letlombardis2:Lombardis=Lombardis() lombardis1.makeMargherita() lombardis2.makeMargherita()
答案:打印出如下两行
["tomato","basil","mozzarella"] ["tomato","basil","mozzarella"]
在Lombardis的代码中,重写了makeMargherita的代码,所以永远调用的是Lombardis中的makeMargherita。
再进一步,我们把protocolPizzeria中的funcmakeMargherita()删掉,代码变为
protocolPizzeria{ funcmakePizza(_ingredients:[String]) } extensionPizzeria{ funcmakeMargherita(){ returnmakePizza(["tomato","mozzarella"]) } } structLombardis:Pizzeria{ funcmakePizza(_ingredients:[String]){ print(ingredients) } funcmakeMargherita(){ returnmakePizza(["tomato","basil","mozzarella"]) } } letlombardis1:Pizzeria=Lombardis() letlombardis2:Lombardis=Lombardis() lombardis1.makeMargherita() lombardis2.makeMargherita()
这时候打印出如下结果:
["tomato","mozzarella"] ["tomato","basil","mozzarella"]
因为lombardis1是Pizzeria,而makeMargherita()有默认实现,这时候我们调用默认实现。
七、Swift中定义常量和Objective-C中定义常量有什么区别?
一般人会觉得没有差别,因为写出来好像也确实没差别。
OC是这样定义常量的:
constintnumber=0;
Swift是这样定义常量的:
letnumber=0
首先第一个区别,OC中用const来表示常量,而Swift中用let来判断是不是常量。
上面的区别更进一步说,OC中const表明的常量类型和数值是在compilationtime时确定的;而Swift中let只是表明常量(只能赋值一次),其类型和值既可以是静态的,也可以是一个动态的计算方法,它们在runtime时确定的。
八、Swift中struct和class什么区别?举个应用中的实例
struct是值类型,class是引用类型。
看过WWDC的人都知道,struct是苹果推荐的,原因在于它在小数据模型传递和拷贝时比class要更安全,在多线程和网络请求时尤其好用。
我们来看一个简单的例子:
classA{ varval=1 } vara=A() varb=a b.val=2
此时a的val也被改成了2,因为a和b都是引用类型,本质上它们指向同一内存。解决这个问题的方法就是使用struct:
structA{ varval=1 } vara=A() varb=a b.val=2
此时A是struct,值类型,b和a是不同的东西,改变b对于a没有影响。
九、Swift到底是面向对象还是函数式的编程语言?
Swift既是面向对象的,又是函数式的编程语言。
说Swift是Object-oriented,是因为Swift支持类的封装、继承、和多态,从这点上来看与Java这类纯面向对象的语言几乎毫无差别。
说Swift是函数式编程语言,是因为Swift支持map,reduce,filter,flatmap这类去除中间状态、数学函数式的方法,更加强调运算结果而不是中间过程。
总结
以上就是关于Swift面试题的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。