首先我们带着几点疑问去看文章:

  • 值类型(结构体、枚举) 和 引用类型 class 在内存中是如何存储的?
  • 值类型和引用类型性能上有什么不同?
  • 如果两者混合,会发生什么?比如struct 包含了 class 对象。
  • 到底该使用哪个呢?

值类型的定义

  • 值类型直接存储到栈中。每个值类型的变量持有自己的数据,之间互不影响。
  • 引用类型通过指针引用数据(存储在堆中),多个变量可指向同一数据,当操作某一变量时会影响其他变量。

值类型涉及到值拷贝,引用类型涉及到内存分配,引用计数。接下来我们大致了解一下内存段。

UserDefaults可以存储一些基础数据类型,如:Data,String,Date,Bool,Int,Double,Float,Array,Dictionary,URL,等基础对象。也可以存储自定义对象(但需要实现编码成Data进行存储)。
尽管如此,我们还是不推荐使用UserDefaults来存储数据量大的数据。因为读写非常昂贵,userDefaults最终用.plist文件进行存储。存储大数据会使此文件变得臃肿。
对于自定义的对象,我们可以通过写文件方式将json写到沙盒文件中。或者存储到coreData. Sqlite等。UserDefaults一般用于存储一些简单的数据类型,存储用户的偏好设置等。在写少读多的情况下,性能才会高。底层是通过读写xml文件方式都数据进行读写。

SUT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
extension URLRequest {
static func search(term: String) -> URLRequest {
var components = URLComponents(string: "https://itunes.apple.com/search")
components?.queryItems = [
.init(name: "media", value: "music"),
.init(name: "entity", value: "song"),
.init(name: "term", value: "\(term)")
]

return URLRequest(url: components!.url!)
}
}

struct MusicService {

func search(_ term: String, completion: @escaping (Result<[Track], Error>) -> Void) {
URLSession.shared.dataTask(with: .search(term: term)) { data, response, error in
DispatchQueue.main.async {
completion(self.parse(data: data, error: error))
}
}.resume()
}

func parse(data: Data?, error: Error?) -> Result<[Track], Error> {
if let data = data {
return Result { try JSONDecoder().decode(SearchMediaResponse.self, from: data).results }
} else {
return .failure(error ?? URLError(.badServerResponse))
}
}
}

视图测试关注点:

  • tableview的行数是否正确?
  • label的文本显示是否正确?
  • button 是否启用或禁用?
  • view的frame是否正确?

viewController如果可以从他们依赖项隔离出来,那么就可以测试。依赖注入是一种可以把视图控制器隔离出来的技术。在测试中,我们可以用假数据替换依赖项,模拟真实数据的行为。
viewController有两个职责:渲染数据、响应用户交互。在MVVM设计模式中,控制器不主动从model中拉数据,也不负责从model中取出数据来更新控制器。

iOS工程师都知道tableview 在开发中是用得最多的,大部分页面几乎都可以用列表来做。但有没发现大量工作其实是重复的比如cell的注册,delegate数据源的匹配,cell的类型转换。接下来,我们需要将这些代理方法为tableview提供数据封装成数据模型。
数据源:dataSource[section[ rows],section[ rows]]

封装DataSource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct Section<Item> {
var items: [Item]
}

struct DataSource<Item> {
var sections: [Section<Item>]

func numberOfSections() -> Int {
return sections.count
}

func numberOfItems(in section: Int) -> Int {
guard section < sections.count else { return 0 }
return sections[section].items.count
}

func item(at indexPath: IndexPath) -> Item {
return sections[indexPath.section].items[indexPath.row]
}
}

中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。
在MVC 框架中,其中C(控制器)就是 M(模型)和 V(视图)的中介者。我们接下来用一个搜索视图来展示中介者模式: