swift
的tip
- lazy的使用
lazy 几经更改,最终固定在最简单的形式,加上关键字lazy
就行了,还要注意只有变量var
才能拥有懒惰特性,因为只有let
在实例化调用super.init()
之前已经初始化好了,而var
是在其后才被索引的,当我们的初始化需要复杂和高昂的代价时,在需要时赋值,就能看出lazy
的意义了
同时,lazy
并非是线程安全的,如果同时被多个线程同时调用,就不能保证只初始化一次
1 | //MARK: lazy |
switch
其实在最开始接触编程时,学习到switch
语句,虽说理解起来很简单,但是写起来和编码过程总有种“做的不够”的感觉,绝大多数的语言中switch
语句都是跟C中的一样,过了这么多年终于在swift中看到了我所希望的样子- 首先是不要一个一个的break了
- 其次,大大增强
Matching
类型,事实上可以匹配any data
,还可以组合匹配,附加匹配 - 最后,永远牢记
switch
必须是完备的1
2
3
4
5
6
7
8
9
10
11
12switch someValueToConsider {
case value1:
statements
case value2,value3:
statements
case value4..<valu5:
statements
case (x, y) where x > y:
statements
default:
statements
}
Access Control
访问控制权限
2种级别:* 模块区分,如不同的`Framework`之间,而`App bundle`也是一个模块
源文件级别,就是各个class的属性和方法级别
3种访问级别:
Public
,Internal
和Private
Public
: 跨模块级别,如Framework
中开放的方法和属性- 默认访问权限是
Internal
- 即为同模块,例如iOS开发通常就一个boundle Private
: 本源文件级别
1 | // 修饰class - 模块级别修饰 |
image 和 color 是可以相互转换的
通常在设置background 时:1
2
3if let patternImage = UIImage(named: "pattern-grey") {
view.backgroundColor = UIColor(patternImage: patternImage)
}swift中网络框架
Alamofir
的使用
Alamofir
的基本使用参照gitHub,已经说的很详细了,这里借助几个开源项目,探求一种最合适的使用方式,先是简单的罗列,最后在分析一种较为典型的使用,url处理是
mattt
大神给出的,本身对框架并没有任何变动,只是将API请求和URl做了规范统一,将所有相关统一在一起,并使用枚举增强可读性,eg: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
26class ServiceApi: NSObject {
// API 部分,统一方法一个class中,使用累方法返回完整url
static var host:String = "http://www.swiftmi.com"
internal class func getTopicUrl(maxId:Int,count:Int) -> String {
return "\(host)/api/topic/list2/\(maxId)/\(count)"
}
}
// 所谓的Router枚举, 遵循URLRequestConvertible 协议
enum Router: URLRequestConvertible {
}
```
其中的`URLRequestConvertible`协议也是框架中自带的,可见是一种推荐的做法
```swift
// MARK: - URLRequestConvertible
/**
Types adopting the `URLRequestConvertible` protocol can be used to construct URL requests.
*/
public protocol URLRequestConvertible {
/// The URL request.
var URLRequest: NSMutableURLRequest { get }
}
枚举
swift中的枚举早已不是C中那个边缘的小tip而已,而是
first class
类型,强大到令人发质,首先是枚举类型的扩充,从简单的基本类型到元组Tuple
都是可以的,可以拥有计算型属性,可以有方法,可以嵌套子枚举,可以嵌套到class和struct中,总之枚举的概念已经被扩展到:枚举,用以声明可能状态的有限集,且可以具有附加值。可以通过内嵌(nesting),方法(method),关联值(associated values)和模式匹配(pattern matching),甚至可以遵循协议(protocal),从而让枚举可以分层次地定义任何有组织的数据。
下面一次性使用
Playground
的展示其使用: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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174// 1. basic Enum
enum Movement {
case Left
case Right
case Top
case Bottom
}
let aMovement = Movement.Left
// - switch
switch aMovement {
case .Left: print("left")
default: ()
}
// - if
if case .Left = aMovement {
print("left")
}
if aMovement == .Left {
print("left")
}
/* 2. Enum Values - 不止是Int型,相比C语言大大的扩展了,对于String和Int你甚至可以使用简些
枚举中支持以下四种关联值类型:
整型(Integer)
浮点数(Float Point)
字符串(String)
布尔类型(Boolean)
*/
enum House: String {
case Baratheon = "Ours is the Fury"
case Greyjoy = "We Do Not Sow"
case Martell = "Unbowed, Unbent, Unbroken"
case Stark = "Winter is Coming"
case Tully = "Family, Duty, Honor"
case Tyrell = "Growing Strong"
}
// float double都可以(同时注意枚举中的花式unicode)
enum Constants: Double {
case π = 3.14159
case e = 2.71828
case φ = 1.61803398874
case λ = 1.30357
}
// swift2.0 的简写
// 相当于 North = "North", ... West = "West"
enum CompassPoint: String {
case Noth, South, East, West
}
// 3. 所谓的“读”和“写”
// - 读: 使用rawValue读取枚举值
let bestHouse = House.Stark
print(bestHouse.rawValue)
// - 写:
enum Movement002: Int {
case Left = 0
case Right = 1
case Top = 2
case Bottom = 3
}
let rightMovement = Movement002(rawValue: 1) // 创建一个movement.Right 用例,其raw value值为1
print(rightMovement)
// 3. Nesting Enums - 枚举中嵌套枚举
enum Character {
// 武器
enum Weapon {
case Bow
case Gun
}
// 头盔
enum Helmet {
case Wooden
case Iron
case Diamond
}
// 角色
case Thief
case Warrior
case Knight
}
let character = Character.Thief
let weapon = Character.Weapon.Gun
let helmet = Character.Helmet.Iron
// 4. Containing Enums - 就是在struct和class中的内嵌枚举
struct Characters {
enum CharacterType {
case Thief
case Warrior
case Knight
}
// 武器
enum Weapon {
case Bow
case Gun
}
let type: CharacterType
let weapon: Weapon
}
let warrior = Characters(type: .Warrior, weapon: .Gun)
// 5. Associated Value
// 前边基本都是enum的扩展,在swift中还有对case的扩展
enum Trade {
case Buy(stock: String, amount: Int)
case Sell(stock: String, amount: Int)
// 可以简写为
case Steel(String, Int)
}
func trade(type: Trade) { }
// “读”: Pattern Mathching
let trade = Trade.Buy(stock: "APPLE", amount: 500)
if case let Trade.Buy(stock, amount) = trade {
print("buy \(amount) of \(stock)")
}
// -- 以下都是大招 --
// 6. case 可以放元祖
// 枚举可以有属性property - 不过是计算型属性
// 可以有方法func
enum Device {
case iPad, iPhone
case AppleWatch
case Off, On
// 计算型属性-- Int year
var year: Int {
switch self {
case .iPhone: return 2007
case .iPad: return 2010
default: return 0
}
}
// Static Methods - 自动转换规范用语
static func transSlang(term: String) -> Device? {
if term == "iWatch" {
return AppleWatch
}
return nil
}
// mutating Methods - 可变方法:允许修改case的值
mutating func screenSwitch() {
switch self {
case .On:
self = Off
default:
self = On
}
}
}
var phoneScreenSwitch = Device.On
phoneScreenSwitch.screenSwitch()
phoneScreenSwitch.screenSwitch()swift中JSON解析转Model的实践
第三方框架网络响应返回的,往往是序列化之后的数据,我们需要做的就是根据不同的key
进行分割数据,找到合适的数据放到Model 中,但蛋疼的事儿就来了,如何优雅的将数据[往往都是字典]转化为对应的Model呢?
在OC中我们的做法基本上都按照一个流程:通过Model的工厂方法+ modelInitWithDict:(NSDictionay *)dict;
,结合KVC
实现转化。
在Swift
中,就不那么方便了,当前的做法是生写,特别的再用到CoreData
时,更是只能一个一个的加到模版文件中,而使用ObjectMapper
,Argo
等第三方框架虽说也行,但在数据处理方面我是一贯持保留意见的,自己想着写一个自己用的脚本,就是根据JSON按格式输出小段重复就行了,这个留待以后再说
- 属性Property
swift中的Property与OC相比,不单单只是类和实例与value的关联,它还负责枚举和结构体,换言之凡是first class
的都是可以有属性的,所以看起来会复杂很多,但同时也做足够细化的分类
* __Stored Properties__: 仅仅存在类与结构体之中
* __Computed Properties__ :存在于类,结构体和枚举,功能上不仅仅只是Sotre还要Compute
当属性value发生变化时,可以定义`属性观察者`,来做出反应