Swift 面试总结 (上)

1.Swift 到底是面向对象还是函数式的编程语言?

Swift 既是面向对象的,又是函数式的编程语言。
说 Swift 是 Object-oriented,是因为 Swift 支持类的封装、继承、和多态,从这点上来看与 Java 这类纯面向对象的语言几乎毫无差别。
说 Swift 是函数式编程语言,是因为 Swift 支持 map, reduce, filter, flatmap 这类去除中间状态、数学函数式的方法,更加强调运算结果而不是中间过程。
1.map、filter、reduce 的作用

  • map 是Array类的一个方法,我们可以使用它来对数组的每个元素进行转换
let intArray = [1, 3, 5]
let stringArr = intArray.map {
          return "\($0)"
      }
// ["1", "3", "5"]
  • filter 用于选择数组元素中满足某种条件的元素
let filterArr = intArray.filter {
  return $0 > 1
}
//[3, 5]
  • reduce 把数组元素组合计算为一个值
let result = intArray.reduce(0) {
  return $0 + $1
}
//9

1.map 与 flatmap 的区别

  • map 可以对一个集合类型的所有元素做一个映射操作
  • 对数组进行flatmap操作,和map是没有区别的
  • 和map 不同,flatmap 有两个定义,分别是:
func flatMap(transform: (Self.Generator.Element) throws -> T?) -> [T]
func flatMap(transform: (Self.Generator.Element) -> S) -> [S.Generator.Element]

1)第一种情况返回值类型是 T?, 实际应用中,可以用来过滤元素为nil的情况,(内部使用了 if-let 来对nil值进行了过滤) 例如:

let optionalArray: [String?] = ["AA", nil, "BB", "CC"];
var optionalResult = optionalArray.flatMap{ $0 }
// ["AA", "BB", "CC"]
操作前是[String?], 操作后会变成[String]

2)第二种情况会自动去重处理

let numbersCompound = [[1,2,3],[4,5,6]];
var res = numbersCompound.map { $0.map{ $0 + 2 } }
// [[3, 4, 5], [6, 7, 8]]
var flatRes = numbersCompound.flatMap { $0.map{ $0 + 2 } }
// [3, 4, 5, 6, 7, 8]

$0.map{ $0 + 2 } 会得到[3, 4, 5], [6, 7, 8], 然后遍历这两个数组,将遍历的元素拼接到一个新的数组内,最终并返回就得到了[3, 4, 5, 6, 7, 8]

2.Swift 中 struct 和 class 什么区别?举个应用中的实例

  • struct没有继承的功能,而class是可以继承的,这是面向对象语言的核心能力,class当然会有这个能力。
  • struct 是值类型,class 是引用类型。体现在内存使用上,struct是通过值传递,而class是通过引用传递的。
    看过WWDC的人都知道,struct 是苹果推荐的,原因在于它在小数据模型传递和拷贝时比 class 要更安全,在多线程和网络请求时尤其好用。我们来看一个简单的例子:
class A {
   var val = 1
}
var a = A()
var b = a
b.val = 2

此时 a 的 val 也被改成了 2,因为 a 和 b 都是引用类型,本质上它们指向同一内存。解决这个问题的方法就是使用 struct:

struct A {
  var val = 1
}
var a = A()
var b = a
b.val = 2

此时 A 是struct,值类型,b 和 a 是不同的东西,改变 b 对于 a 没有影响。

3. Swift 中定义常量和 Objective-C 中定义常量有什么区别?

OC是这样定义常量的:
const int number = 0;
Swift 是这样定义常量的:
let number = 0

  • OC中用 const 来表示常量,而 Swift 中用 let 来判断是不是常量。
  • OC中 const 表明的常量类型和数值是在 compilation time (编译阶段)时确定的;而 Swift 中 let 只是表明常量(只能赋值一次),其类型和值既可以是静态的,也可以是一个动态的计算方法,它们在 runtime 时确定的。

4.Swift 中的泛型

泛型是为Swift编程灵活性的一种语法,在函数、枚举、结构体、类中都得到充分的应用,它的引入可以起到占位符的作用,当类型暂时不确定的,只有等到调用函数时才能确定具体类型的时候可以引入泛型。
我们之前实际上已经使用过泛型,例如:Swift的Array和Dictionary类型都是泛型集。
详细介绍点我

5.给一个数组,要求写一个函数,交换数组中的两个元素

func swap(_ nums: inout [T], _ p: Int, _ q: Int) {
    (nums[p], nums[q]) = (nums[q], nums[p])
}

6.实现一个 min 函数,返回两个元素较小的元素

func min(_ a: T, _ b: T) -> T {
    return a < b ? a: b
}
//这里一定要遵守 Comparable 协议,因为并不是所有的类型都具有“可比性”

7.guard 使用场景

  • 使用 guard 来表达 “提前退出”的意图,有以下 使用场景 :
  • 在验证入口条件时
  • 在成功路径上提前退出
  • 在可选值解包时(拍扁 if let..else 金字塔)
  • return 和 throw 中
  • 日志、崩溃和断言中

而下面则是尽量 避免使用 的场景:

  • 不要用 guard :替代琐碎的 if..else 语句
  • 不要用 guard :作为 if 的相反情况
  • 不要:在 guard 的 else 语句中放入复杂代码
    具体介绍点这里

8.defer 使用场景

defer 语句用于在退出当前作用域之前执行代码.例如:
手动管理资源时,比如 关闭文件描述符,或者即使抛出了错误也需要执行一些操作时,就可以使用 defer 语句。
如果多个 defer 语句出现在同一作用域内,那么它们执行的顺序与出现的顺序相反

func f() {
    defer { print("First") }
    defer { print("Second") }
    defer { print("Third") }
}
f()
// 打印 “Third”
// 打印 “Second”
// 打印 “First”

9.String 与 NSString 的关系与区别

  • String 是 struct,值类型。NSString 是类,引用类型。

10.Swift 访问关键字

从高到低得权限控制顺序如下

open > public > interal > fileprivate > private

private
swift3.0 private访问级别所修饰的属性或者方法只能在当前类里访问。

class A {
    private func test() {
        print("this is private function!")
    }
}

class B: A {
    func show() {
        test()
    }
}

上面代码在swift3.0以前,可以顺利编译成功,但是在swift3.0中会编译失败,提示class B中test()方法不可用。
fileprivate
fileprivate是Swift3.0后新加的权限修饰符,fileprivate访问级别所修饰的属性或者方法在当前的Swift源文件里可以访问。(比如上面例子中把private改成fileprivate就不会报错了)。
internal
internal为默认访问级别,可默认不写。internal访问级别所修饰的属性或方法在源代码所在的整个模块都可以访问。如果是框架或者库代码,则在整个框架内部都可以访问,框架由外部代码所引用时,则不可以访问。如果是App代码,也是在整个App代码,也是在整个App内部可以访问。
public
可以被任何人访问。但其他module中不可以被override和继承,而在module内可以被override和继承。
open
open为swift3.0后新加权限关键字,可以被任何人使用,包括override和继承。
详细的点这里

11.柯里化函数

详细介绍

你可能感兴趣的:(Swift 面试总结 (上))