Swift面试资料 (一) —— Questions 和 Ans
版本记录
版本号 | 时间 |
---|---|
V1.0 | 2019.04.23 星期二 |
前言
Swift作为一门开发语言,它到目前为止也四岁了,接下来这个专题主要收集一下Swift面试相关的问题。
开始
首先看下写作环境
Swift 5, iOS 12, Xcode 10
Swift只有四年的时间,但它已经成为iOS开发的默认语言。随着Swift逐渐发展到5.0版本,它变成了一种复杂而强大的语言,包含面向对象和函数范例。每个版本都带来了更多的演变和变化
但你真的有多了解Swift语音?在本文中,您将找到一些示例Swift面试问题。
您可以使用这些问题来对候选人进行面试,以测试他们的Swift知识。或者你可以自己测试一下!如果您不知道答案,请不要担心:每个问题都有一个解决方案,您可以学习。
您会发现问题分为三个级别:
- Beginner - 初学者:适合Swift初学者。你已经阅读了一两本关于这个主题的书,并且在你自己的应用程序中使用过Swift。
- Intermediate - 中级:适合对语言有浓厚兴趣的人士。您已经阅读了很多关于Swift并进一步尝试的内容。
- Advanced - 高级:适合最有经验的开发人员 - 喜欢彻底探索语言和使用尖端技术的人。
在每个级别,您都会发现两种类型的问题:
- Written questions - 书面问题:适用于电子邮件编程测试,因为这些测试可能涉及编写代码。
- Verbal questions - 口头问题:通过电话或面对面交谈很好,因为您的潜在客户可以口头回答。
当您解决这些问题和答案时,请保持playground
开放,以便在回答之前可以针对问题进行代码测试。我们测试了针对Xcode 10.2
和Swift 5
的所有答案。
Beginner Written Questions
1. Question #1
考虑下面问题
struct Tutorial {
var difficulty: Int = 1
}
var tutorial1 = Tutorial()
var tutorial2 = tutorial1
tutorial2.difficulty = 2
tutorial1.difficulty
和tutorial2.difficulty
的值是什么? 如果Tutorial
是一个类,这会有什么不同吗? 为什么或者为什么不?
tutorial1.difficulty
是1,而tutorial2.difficulty
是2。
Swift
中的结构是值类型。 您可以按值而不是引用来复制值类型。 以下代码创建tutorial1
的副本并将其分配给tutorial2
:var tutorial2 = tutorial1
更改
tutorial2
不会反映到tutorial 1
中。如果
Tutorial
是一个类,那么tutorial1.difficulty
和tutorial2.difficulty
都是2
。Swift中的类是引用类型。 当你更改tutorial1
的属性时,你会看到它反映在tutorial2
中,反之亦然。
2. Question #2
您已使用var
声明了view1
,并且已使用let
声明了view2
。 有什么区别,最后一行会编译吗?
import UIKit
var view1 = UIView()
view1.alpha = 0.5
let view2 = UIView()
view2.alpha = 0.5 // Will this line compile?
是的,最后一行将编译。
view1
是一个变量,您可以将其重新分配给UIView
的新实例。 使用let
,您只能分配一次值,因此以下代码无法编译:view2 = view1 // Error: view2 is immutable
但是,
UIView
是一个带引用语义的类,所以你可以改变view2
的属性 - 这意味着最后一行将编译:let view2 = UIView() view2.alpha = 0.5 // Yes!
3. Question #3
这个复杂的代码按字母顺序对一组名称进行排序。 尽可能简化closure
。
var animals = ["fish", "cat", "chicken", "dog"]
animals.sort { (one: String, two: String) -> Bool in
return one < two
}
print(animals)
类型推断系统自动计算闭包中的参数类型和返回类型,因此您可以删除它们:
animals.sort { (one, two) in return one < two }
您可以用
$ i
表示法替换参数名称:animals.sort { return $0 < $1 }
在单个语句闭包中,您可以省略
return
关键字。 最后一个语句的值成为闭包的返回值:animals.sort { $0 < $1 }
最后,由于
Swift
知道数组的元素符合Equatable
,你可以简单地写:animals.sort(by: <)
4. Question #4
此代码创建两个类:Address
和Person
。 然后它创建两个Person
实例来表示Ray
和Brian
。
class Address {
var fullAddress: String
var city: String
init(fullAddress: String, city: String) {
self.fullAddress = fullAddress
self.city = city
}
}
class Person {
var name: String
var address: Address
init(name: String, address: Address) {
self.name = name
self.address = address
}
}
var headquarters = Address(fullAddress: "123 Tutorial Street", city: "Appletown")
var ray = Person(name: "Ray", address: headquarters)
var brian = Person(name: "Brian", address: headquarters)
假设Brian
搬到了街对面的新建筑物,你会想要像这样更新他的记录:
brian.address.fullAddress = "148 Tutorial Street"
这编译并运行没有错误。 如果您现在查看Ray
的地址,他也会搬到新大楼。
print (ray.address.fullAddress)
这里发生了什么? 你怎么解决这个问题?
Address
是一个类,并且具有引用语义,因此无论您是通过ray
还是brian
访问,headquarters
都是相同的实例。 更改headquarters
地址将改变它们。 你能想象如果Brian
收到Ray
的邮件会怎么样,反之亦然?解决方案是创建一个新的
Address
以分配给Brian
,或者将Address
声明为结构体而不是类。
你很好,您将如何处理更多关于理论和实践的开放式问题?
要回答其中一些问题,您可能需要在playground
上玩代码。
Beginner Verbal Questions
1. Question #1
什么是可选项以及可选项解决哪些问题?
一个可选项允许任何类型的变量表示缺少值。 在
Objective-C
中,缺省值仅在使用nil
特殊值的引用类型中可用。 值类型(如int或float)不具备此功能。Swift通过选项将缺少值概念扩展到参考和值类型。 可选变量可以包含值或nil,表示缺少值。
2. Question #2
总结结构和类之间的主要区别。
您可以将差异总结为:
- 类支持继承,结构体没有。
- 类是引用类型,结构体是值类型。
3. Question #3
什么是泛型(generics)
,他们解决了哪些问题?
在Swift中,您可以在函数和数据类型中使用泛型,例如 在类,结构或枚举中。
泛型解决了代码重复的问题。 当你有一个采用一种类型参数的方法时,通常会复制它以适应不同类型的参数。
例如,在下面的代码中,第二个函数是第一个函数的“克隆”,除了它接受字符串而不是整数。
func areIntEqual(_ x: Int, _ y: Int) -> Bool { return x == y } func areStringsEqual(_ x: String, _ y: String) -> Bool { return x == y } areStringsEqual("ray", "ray") // true areIntEqual(1, 1) // true
通过采用泛型,您可以将两个函数合二为一,同时保持类型安全。 这是泛型的实现:
func areTheyEqual<T: Equatable>(_ x: T, _ y: T) -> Bool { return x == y } areTheyEqual("ray", "ray") areTheyEqual(1, 1)
由于您在这种情况下测试相等性,因此将参数限制为实现
Equatable
协议的任何类型。 此代码实现了预期的结果,并防止传递不同类型的参数。
4. Question #4
在某些情况下,您无法避免使用隐式展开的选项(implicitly unwrapped optional)
。 什么时候? 为什么?
使用隐式展开选项的最常见原因是:
1) 如果在实例化时无法初始化非nil的属性。 一个典型的例子是
Interface Builder outlet
,它总是在它的所有者owner
之后初始化。 在这种特定情况下 - 假设它在Interface Builder
中正确配置 - 您在使用它之前保证outlet
是非nil
的。
2) 解决强引用循环问题,即两个实例相互引用并需要对另一个实例进行非零引用。 在这种情况下,您将引用的一侧标记为无主,而另一侧使用隐式未包装的可选项。
5. Question #5
打开可选项(unwrap an optional)
的各种方法有哪些? 他们如何评价安全性?
var x : String? = "Test"
提示:有七种方法。
Forced unwrapping - 强制解包 — 不安全
let a: String = x!
Implicitly unwrapped variable declaration - 隐式解包变量声明 - 在许多情况下不安全
var a = x!
Optional binding - 可选绑定 - 安全
if let a = x { print("x was successfully unwrapped and is = \(a)") }
Optional chaining - 可选链 - 安全
let a = x?.count
Nil coalescing operator - Nil并运算符 - 安全
let a = x ?? ""
Guard statement - Guard声明 - 安全
guard let a = x else { return }
Optional pattern - 可选样式 - 安全
if case let a? = x { print(a) }
后记
本篇主要讲述了Swift面试资料的Questions 和 Answers,感兴趣的给个赞或者关注~~~