interview-Swift

516 阅读6分钟

写时拷贝 copy-on-write

swift中Array,Dictionary和Set集合类型运用了此技术。 原理:当一个集合在被修改时,会先检查其引用是否唯一。是,那就那就直接变更。如果还有其他引用,那么就会新复制一份,再进行变更。

filter reduce map&compactMap

filter

使用闭包中的规则去删选元素,返回一个集合

let packages = [
    Package(name: "Swift高阶函数编程", number: 1, price: 80.0, address: "中关村"),
    Package(name: "Swift面向协议编程", number: 2, price: 80.0, address: "西二旗"),
    Package(name: "Swift基础", number: 3, price: 35.0, address: "798"),
    Package(name: "Swift进阶", number: 4, price: 50.0, address: "望京soho")
]

//filter :使用闭包中的规则去删选元素,返回一个集合
let packages_filter = packages.filter {(package)-> Bool in
    return package.price == 80.0
}

//简化版
//let packages_filter = packages.filter {$0.price == 80.0}

print(packages_filter)

打印

Package(name: "Swift高阶函数编程", number: 1, price: 80.0, address: "中关村")
Package(name: "Swift面向协议编程", number: 2, price: 80.0, address: "西二旗")

reduce

接受一个初始值,并使用闭包中的规则合并遍历的元素

let reduceName = packages.reduce("xxx前缀xxx") {$0 + $1.name}
print(reduceName)

打印

xxx前缀xxxSwift高阶函数编程Swift面向协议编程Swift基础Swift进阶

map

通过闭包中的规则返回一个新的集合

let packages_map = packages.map{ $0.name + "riceFun" }
print(packages_map)

打印

["Swift高阶函数编程riceFun", "Swift面向协议编程riceFun", "riceFun", "Swift进阶riceFun"]

compactMap

和map相似,但是它能自动去掉空值

let numbers = ["1", "2", "three", "///5///", "5"]
let numbers_map = numbers.map { (number) -> Int? in
    return Int(number)
}
print(numbers_map)
//[Optional(1), Optional(2), nil, nil, Optional(5)]

let numbers_compactMap = numbers.compactMap { (number) -> Int? in
    return Int(number)
}
print(numbers_compactMap)
//[1, 2, 5]

Swift & OC

Swift & OC-共同点

  • 相同概念:引用计数、ARC(自动引用计数)、属性、协议、接口、初始化、扩展类、命名参数、匿名函数等
  • 公用一套运行时环境Swift的类型可以桥接到OC,反之亦然

Swift & OC-区别

  • Swift:可选类型,注重安全,相比于OC中的nil更加安全和简明
  • Swift:面向协议、函数式编程、面向对象;OC:面向对象
  • Swift:注重值类型;OC:注重指针和引用
  • Swift:语法简洁;OC:语法冗杂
  • Swift:支持泛型:OC:只有集合类型才支持泛型
  • Swift:有各种方便快捷的高阶函数(函数式编程) eg: (Swift的标准数组支持三个高阶函数:mapfilterreduce,以及map的扩展flatMap);OC:不支持
  • Swift: 支持元组类型,把多个值组合成复合值;OC:不支持

面向协议 & 面向对象

1. 对抽象数据的使用方式

  1. 面向对象采用的是继承
  2. 面向协议采用的是遵守协议

eg:

面向对象:飞机、火车、汽车继承于交通工具类,马、老虎继承于动物类,但是马也有作为交通工具的能力,这样就能难划分了整理了。但是面向协议就只要抽离出交通工具的能力作为一个协议,只要遵守协议就具备这个能力。

2. 协议可以被类、结构体和枚举遵守,而类层级约束为类类型

3. 总结:

面向协议相对于面向对象来说更具有可伸缩性可重用性,并且在编程的过程中更加模块化通过协议以及协议扩展替代一个庞大的基类,这在大规模系统编程中会有很大的便捷之处。

unowned weak

unowned(无主引用)

  • 无主引用不能设置为nil,因为非可选类型的变量不允许被赋值为nil
  • 用于一个是可选类型,一个是非可选类型
class Customer {
    let name: String
    var card: CreditCard?//人不一定有卡
    init(name: String) {
        self.name = name
    }
    deinit { print("\(name) is being deinitialized") }
}
########
class CreditCard {
    let number: UInt64
    unowned let customer: Customer//卡一定有持有人
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("Card #\(number) is being deinitialized") }
}

weak

  • 用于两个都是可选类型
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?  //公寓的房客可能为空所以声明为weak
    deinit { print("Apartment \(unit) is being deinitialized") }
}

闭包中使用

//weak 防止循环引用
student?.giveAnswerClosure = { [weak self] answer in
    self?.isRight = answer == 1 ? true : false
}

optional

Optional 是一个泛型枚举,大致定义如下:

enum Optional<Wrapped> {
  case none
  case some(Wrapped)
}

可选值,专门用来处理数据可能为空的情况。在类型后添加一个问号来标识这个数据是可选值类型,表明这个变量盒子包含了两种可能性:有值或者为空。

var errorCode : Int?
errorCode = 100
errorCode = nil

Unwarpping optionals(解包)

var errorCode : Int? = 30
print(result)

打印: Optional(30)

Force unwrapping (强制解包 !):有危险

var authorName: String? = "Mike"
var unwrappedAuthorName = authorName!
print("Author is \(unwrappedAuthorName)")

打印:Author is Mike

Optional binding(可选值绑定):更安全的访问可选值的内容,

if let unwrappedAuthorName = authorName {
  print("Author is \(unwrappedAuthorName)")
} else {
  print("No author.")
}

可选值绑定一般搭配guard

func maybePrintSides(shape: String) {
  guard let sides = calculateNumberOfSides(shape: shape) else {
    print("I don't know the number of sides for \(shape).")
    return
  }

  print("A \(shape) has \(sides) sides.")
}

空值合并 ??:swift有一种更好用的方式去解包可选值。不管可选值有没有值,如果没有值就使用默认值,这种方式就是空值合并。

var optionalInt: Int? = 10
var mustHaveResult = optionalInt ?? 0

class和struct 的区别

  • class 为类, struct 为结构体, 类是引用类型, 结构体为值类型
  • struct定义结构体类型时其成员可以没有初始值,class不可以,会报错
  • struct自动生成构造器,class需要手动生成
  • mutating functionstruct的方法修改property值时要加上mutating,class,不需要
  • struct不能继承,class可以继承。
  • structclass更“轻量级”,struct分配在栈中,class分配在堆中。

Struct 作为数据模型的注意事项

优点:

  • 内存: Struct 是用值类型传递的,它们没有引用计数
  • 安全:由于他们没有引用数,他们不会因为循环引用导致内存泄漏
  • 速度: 值类型通常来说是以栈的形式分配的,而不是用堆。因此他们比 Class 要快很多!
  • 拷贝:Objective-C 里拷贝一个对象,你必须选用正确的拷贝类型(深拷贝、浅拷贝),而值类型的拷贝则非常轻松!
  • 线程安全 :值类型是自动线程安全的。无论你从哪个线程去访问你的 Struct ,都非常简单。

缺点:

  • 混合开发时,oc无法调用swift中的struct
  • Struct 不能相互继承。
  • Struct 不能被序列化成 NSData 对象。不能使用NSUserDefaults

所以:如果模型较小,并且无需继承、无需储存到 NSUserDefault 或者无需 Objective-C 使用时,建议使用 Struct

guard和if

guardif 类似, 不同的是, guard 总是有一个else语句, 如果表达式是假或者值绑定失败的时候, 会执行 else 语句, 且在 else 语句中一定要停止函数调用

open > public > internal > fileprivate > private

  • private:只有当前类可以访问。
  • fileprivate:当前文件内可以访问
  • internal :默认访问级别,一般不写,可以在整个模块中访问:eg:如果在框架/库外,那就不能访问,内部能访问
  • public :都能访问,但不能被override和继承
  • open :都能访问,包括override和继承