The Swift Programming Language 2.1 Examples

源码在 GitHub:https://github.com/gewill/The-Swift-Programming-Language-2.1-Examples

Xcode集成了git,还是非常简单方便的diff/add/commit/push

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
//: Playground - noun: a place where people can play

import UIKit

//: 枚举语法,成员类型为CompassPoint,而非1.2.3.4
enum CompassPoint {
case North
case South
case East
case West
}

enum Something {
case One, Two
}

var directionToHead = CompassPoint.West

//: 相关值(Associated Values)存储相关信息如何条形码和二维码相关信息

enum BarCode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}

var productBarcode = BarCode.UPCA(8, 21212, 3223, 3)
productBarcode = BarCode.QRCode("AAAAAAAAA")

//: Switch 可以定义相关值的变量或常量的名称
switch productBarcode {
case .UPCA(let a, let b, let c, let d):
print("\(a + b + c + d)")
case .QRCode(let e):
print(e)
}

//: 原始值(Raw Values)
enum ASCIIControlCharacter: Character {
case Tab = "\t"
case LineFeed = "\n"
case CarriageReturn = "\r"
}
print(ASCIIControlCharacter.Tab)
print(ASCIIControlCharacter.Tab.rawValue)

//: 隐式赋值0...n,但仅仅是原始值
enum Planet: Int {
case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Nepture
}

print(Planet.Earth)
print(Planet.Earth.rawValue)
let possiblePlanet = Planet(rawValue: 4)
let possiblePlanet1 = Planet(rawValue: 9)


//: 递归枚举(Recursive Enumerations)
indirect enum AE {
case Number(Int)
case Addition(AE, AE)
case Multiplicaiton(AE, AE)
}

//: 函数也是一个递归函数
func evaluate(expression: AE) -> Int {
switch expression {
case .Number(let value):
return value
case .Addition(let left, let right):
return evaluate(left) + evaluate(right)
case .Multiplicaiton(let left, let right):
return evaluate(left) * evaluate(right)
}
}

//: 计算 5 + (4 * 7)
let exp = AE.Addition(AE.Number(5), AE.Multiplicaiton(AE.Number(4), AE.Number(7)))
print(evaluate(exp))


综合实现对比了一下委托和通知,Target-Action是更直接的方式。
check phone number

1. 委托

UITextFieldDelegate,只能判断开始编辑那一刻的状态。
optional public func textFieldDidBeginEditing(textField: UITextField)

// became first responder

或者试试这个,下面这个委托实现起来有些啰嗦:正常输入需要加一个字符判断,但是用户按下删除键时 string为””,需要减一个字符来判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//MARK: - phoneNumberTextField delegate
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
//TODO: - 检测电话号码注册与非
if textField.text != nil && string != ""{
let newString = textField.text! + string
if isPhoneNumberAvailable(newString) {
sendVerificationCodeButton.enabled = true
} else {
sendVerificationCodeButton.enabled = false
sendVerificationCodeButton.setTitleColor(UIColor ( red: 0.4, green: 0.4, blue: 0.4, alpha: 1.0 ), forState: UIControlState.Disabled)

}
} else if textField.text != nil && string == "" {
let newString = String(textField.text!.characters.dropLast())
if isPhoneNumberAvailable(newString) {
sendVerificationCodeButton.enabled = true
} else {
sendVerificationCodeButton.enabled = false
}
}
return true

}

但是如此还不行,如果光标移到不在尾部,上面的代码逻辑就不对。还要利用好range。但是这里还是将textField.text!转化为NSString,因为public mutating func replaceRange(subRange: Range<Index>, with newElements: String)这里的 Range<Index>没有搞明白,所以就是去了Unicode 的支持。这里是电话号码也就不影响使用。

参考:http://stackoverflow.com/questions/25138339/nsrange-to-rangestring-index

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//MARK: - phoneNumberTextField delegate
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
//TODO: - 检测电话号码注册与非
if textField.text != nil {

let newString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
if isPhoneNumberAvailable(newString) {
sendVerificationCodeButton.enabled = true
} else {
sendVerificationCodeButton.enabled = false
self.sendVerificationCodeButton.setTitle("发送验证码", forState: UIControlState.Disabled)
}
}
return true
}

2. 注册通知

最为方便,因为我们并不关心 UITextFieldDelegate中新字符string的值

1
public let UITextFieldTextDidChangeNotification: String
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
override func viewDidLoad() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "phoneNumberDidChange:", name: UITextFieldTextDidChangeNotification, object: nil)
}

override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self)
}


//MARK: - 检测电话号码是否正确更改发送验证码状态
func phoneNumberDidChange(aNotification: NSNotification) {
if phoneNumberTextField.isFirstResponder() {
if isPhoneNumberAvailable() {
sendVerificationCodeButton.enabled = true
sendVerificationCodeButton.backgroundColor = Color.colorWithHex("#15C76D")
} else {
sendVerificationCodeButton.enabled = false
self.sendVerificationCodeButton.backgroundColor = UIColor.lightGrayColor()
self.sendVerificationCodeButton.titleLabel?.text = "发送验证码"
}
}
}

3. UIControl 的 Target-Action

由于public class UITextField : UIControl, UITextInput, NSCoding之前没有注意,这里有个最简单直接方法:

- addTarget:action:forControlEvents:或者 IB 添加 Action
EditingChanged: UIControlEvents

1
2
3
4
5
6
7
8
9
10
11
//MARK: - 检测电话号码是否正确更改发送验证码状态
@IBAction func phoneNumberDidChange(sender: UITextField) {
if isPhoneNumberAvailable() {
sendVerificationCodeButton.enabled = true
sendVerificationCodeButton.backgroundColor = Color.colorWithHex("#15C76D")
} else {
sendVerificationCodeButton.enabled = false
self.sendVerificationCodeButton.backgroundColor = UIColor.lightGrayColor()
self.sendVerificationCodeButton.titleLabel?.text = "发送验证码"
}
}

附UIControlEvents:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct UIControlEvents : OptionSetType {
init(rawValue rawValue: UInt)
static var TouchDown: UIControlEvents { get }
static var TouchDownRepeat: UIControlEvents { get }
static var TouchDragInside: UIControlEvents { get }
static var TouchDragOutside: UIControlEvents { get }
static var TouchDragEnter: UIControlEvents { get }
static var TouchDragExit: UIControlEvents { get }
static var TouchUpInside: UIControlEvents { get }
static var TouchUpOutside: UIControlEvents { get }
static var TouchCancel: UIControlEvents { get }
static var ValueChanged: UIControlEvents { get }
static var PrimaryActionTriggered: UIControlEvents { get }
static var EditingDidBegin: UIControlEvents { get }
static var EditingChanged: UIControlEvents { get }
static var EditingDidEnd: UIControlEvents { get }
static var EditingDidEndOnExit: UIControlEvents { get }
static var AllTouchEvents: UIControlEvents { get }
static var AllEditingEvents: UIControlEvents { get }
static var ApplicationReserved: UIControlEvents { get }
static var SystemReserved: UIControlEvents { get }
static var AllEvents: UIControlEvents { get }
}

4. 计时器实现延迟发送验证码

延迟60秒后,可重发发送验证码。使用NSTimer来实现,有个小小的 bug,就是第一次按下发送键,界面卡顿,从59秒起算,以后是60秒起算。以下是完整的代码。

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

import UIKit

class SignupViewController: BaseViewController {

var count = 60
var myTimer: NSTimer?

@IBOutlet weak var userNameTextField: UITextField!
@IBOutlet weak var phoneNumberTextField: UITextField!
@IBOutlet weak var VerificationCodeTextField: UITextField!
@IBOutlet weak var password0TextField: UITextField!
@IBOutlet weak var password1TextField: UITextField!

@IBOutlet weak var signupButton: UIButton!
@IBOutlet weak var sendVerificationCodeButton: UIButton!

@IBAction func signupButtonClick(sender: AnyObject) {

}

@IBAction func sendVerificationCodeButtonClick(sender: AnyObject) {
//TODO: - 添加发送验证码模块
sendVerificationCodeButton.enabled = false

myTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "countDownTick", userInfo: nil, repeats: true)
count = 60

}

override func viewDidLoad() {
super.viewDidLoad()

self.navigationItem.title = "注册"
self.setupBackButton()

self.automaticallyAdjustsScrollViewInsets = false

signupButton.layer.cornerRadius = 35.0 / 2
signupButton.backgroundColor = Color.colorWithHex("#15C76D")


NSNotificationCenter.defaultCenter().addObserver(self, selector: "phoneNumberDidChange:", name: UITextFieldTextDidChangeNotification, object: nil)

sendVerificationCodeButton.enabled = false
sendVerificationCodeButton.setTitleColor(UIColor ( red: 0.4, green: 0.4, blue: 0.4, alpha: 1.0 ), forState: UIControlState.Disabled)
}

override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

//MARK: - 检测电话号码格式是非正确
func isPhoneNumberAvailable() -> Bool {
let phoneNumber = phoneNumberTextField.text
let mobile = "^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$"
let CM = "^1(34[0-8]|(3[5-9]|5[017-9]|8[278])\\d)\\d{7}$"
let CU = "^1(3[0-2]|5[256]|8[56])\\d{8}$"
let CT = "^1((33|53|8[09])[0-9]|349)\\d{7}$"
let regextestmobile = NSPredicate(format: "SELF MATCHES %@",mobile)
let regextestcm = NSPredicate(format: "SELF MATCHES %@",CM )
let regextestcu = NSPredicate(format: "SELF MATCHES %@" ,CU)
let regextestct = NSPredicate(format: "SELF MATCHES %@" ,CT)
if ((regextestmobile.evaluateWithObject(phoneNumber) == true)
|| (regextestcm.evaluateWithObject(phoneNumber) == true)
|| (regextestct.evaluateWithObject(phoneNumber) == true)
|| (regextestcu.evaluateWithObject(phoneNumber) == true))
{
return true
}
else
{
return false
}
}



//MARK: - 检测电话号码是否正确更改发送验证码状态
func phoneNumberDidChange(aNotification: NSNotification) {
if phoneNumberTextField.isFirstResponder() {
if isPhoneNumberAvailable() {
sendVerificationCodeButton.enabled = true
sendVerificationCodeButton.backgroundColor = Color.colorWithHex("#15C76D")
} else {
sendVerificationCodeButton.enabled = false
self.sendVerificationCodeButton.backgroundColor = UIColor.lightGrayColor()
self.sendVerificationCodeButton.titleLabel?.text = "发送验证码"
}
}
}

//MARK: -
func countDownTick() {

if count == 1 {
myTimer?.invalidate()
self.sendVerificationCodeButton.enabled = true
self.sendVerificationCodeButton.setTitle("发送验证码", forState: UIControlState.Normal)
count = 61
}

count--
self.sendVerificationCodeButton.setTitle("\(count)秒后重发", forState: UIControlState.Disabled)
}

}

参考文档

我的总结

上面的文档都已经讲的问清楚了,也就几个属性可调。参考Android上的线性布局,更容易理解其含义。但是iOS9才支持有点坑,个人项目可以用一用。

iOS9 Day-by-Day :: Day 4 :: UIStack View 里面的Demo非常直观的调试 UIStackView 的相关属性。更换图片为不同形状,效果会更好一些,代码在:https://github.com/gewill/iOS9-day-by-day

步骤为:先设置 UIStack View 的位置,后设置 Auto Layout的大小,基本上就能固定控件布局了。

The Swift Programming Language 2.1 Examples

源码在 GitHub:https://github.com/gewill/The-Swift-Programming-Language-2.1-Examples

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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
//: Playground - noun: a place where people can play

import UIKit

//数组
var array1 = [Double](count: 3, repeatedValue: 4.3)
print(array1)

var array2 = array1 + array1

if array1.isEmpty {
print("array1 is empty.")
} else {
print("array1 is not empty, have \(array1.count) numbers.")}

array1.insert(3.2, atIndex: 0)

print(array1)

for item in array1 {
print(item)
}

//集合
var letters = Set<Character>()
letters.insert("a")
letters = []
var set1: Set<String> = ["aaa", "b"]
var set2: Set = ["aaa", "b"]
set2.count
set2.insert("33")
set2.remove("b")
set2
for genre in set2.sort() {
print(genre)
}

set1.union(set2)
set1.subtract(set2)
set1.exclusiveOr(set2)
set1.intersect(set2)

let set3: Set<String> = ["33"]

set3.isDisjointWith(set2)
set3.isStrictSubsetOf(set2)
set3.isSubsetOf(set2)


//字典
var dict = [Int: String]()
dict[12] = "12222"
dict = [:]
dict = [12: "1222", 23: "232423", 322: "23dsfsaf"]
for (num, value) in dict {
print("\(num) is \(value)")
}
dict[12] = "tw"

for value in dict.values {
print(value)
}

//控制流
var i = 3
while i < 0 {
print(1)
}

//元组
let somePoint = (0, 1)

switch somePoint {
case (0, 0):
print("0")
case (_, 0):
print("is on the x-axis")
case (0, _):
print("is on the y-axis")
default:
print("is outside of the box")
}


//检测API是否可用
if #available(iOS 9, *) {
print(2)
} else {
print(1)
}

//if
var temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
} else {
print("It's not that cold. Wear a t-shirt.")
}
//


//switch 默认遇到符合case,立即终止
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) is not a vowel or a consonant")
}
//

//where
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
//

//Continue
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
for character in puzzleInput.characters {
switch character {
case "a", "e", "i", "o", "u", " ":
continue
default:
puzzleOutput.append(character)
}
}
print(puzzleOutput)
// prints "grtmndsthnklk”

//break
let numberSymbol: Character = "二" // Simplified Chinese for the number 3
var possibleIntegerValue: Int?
switch numberSymbol {
case "1", "١", "一", "๑":
possibleIntegerValue = 1
case "2", "٢", "二", "๒":
possibleIntegerValue = 2
print("test")
break
case "3", "٣", "三", "๓":
possibleIntegerValue = 3
case "4", "٤", "四", "๔":
possibleIntegerValue = 4
default:
break
}
if let integerValue = possibleIntegerValue {
print("The integer value of \(numberSymbol) is \(integerValue).")
} else {
print("An integer value could not be found for \(numberSymbol).")
}
// prints "The integer value of 三 is 3."

//Fallthrough
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"

default:
description += " an integer."
}
print(description)
//

//提前退出
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)")

guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(["name": "John"])
// prints "Hello John!"
// prints "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
// prints "Hello Jane!"
// prints "I hope the weather is nice in Cupertino."

The Swift Programming Language 2.1 Examples

源码在 GitHub:https://github.com/gewill/The-Swift-Programming-Language-2.1-Examples

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
//: Playground - noun: a place where people can play

import UIKit

//: 闭包是自包含的函数代码块

//: Swift 的闭包表达式有简洁的风格,带来很多便利:利用上下文类型推断/隐式返回单表达式/参数名缩写/尾随

//: 闭包表达式(Closure Expressions)
//: { (parameters) -> returnType in statements }

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
var reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 > s2 } )
print(reversed)

//: 根据上下文推断类型(Inferring Type From Context)
reversed = names.sort( { s1, s2 in return s1 > s2 } )
print(reversed)

//: 单表达式闭包隐式返回(Implicit Return From Single-Expression Closures),但是表达不够直接不建议
reversed = names.sort( { s1, s2 in s1 > s2 } )
print(reversed)

//: 参数名缩写(shorthand Argument Names),简洁到这种形式还叫闭包?
reversed = names.sort( { $0 > $1 } )
print(reversed)

//: 运算符函数(Operator Functions), 到这个时候就完全是Swift来推断或者来猜了,而作为代码给人看过于抽象化了
reversed = names.sort(>)

//: 尾随闭包(Trailing Closures),就是把闭包的大括号放在小括号外面,形式上更像一个函数,或者结构上大段的闭包放在后面更符合一般的书写习惯而已,这个用法是一个语法糖,避免头重脚轻。让懂的人看的舒服,不懂的人可能莫名其妙。记得Swfit调用 AFNetworking 就会智能补全成尾随闭包。
func someFunction(closure: () -> Void) {
// function do something
}

someFunction ( {
// closure do something
} )

// Magic Time
someFunction() {
// closure can alse do something at here
}

reversed = names.sort() { $0 > $1 }
print(reversed)


//: 捕获值(Capturing Values)
//: 闭包是引用类型(Closure Are Reference Types),函数和闭包都可以赋值给变量或常量

The Swift Programming Language 2.1 Examples

源码在 GitHub:https://github.com/gewill/The-Swift-Programming-Language-2.1-Examples

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
//: Playground - noun: a place where people can play

import UIKit

//: 函数参数名称(Function Parameter Names)
//: 一个参数可以有内部参数和外部参数的区别,就是外部调用时要不要写的那个参数,如上面的 arr:。默认情况下:第一个参数没有外部参数名,后面的内外一致。
//: 指定外部参数名(Specifying External Parameter Names)
//: 均可指定外部参数名:自定义或者可以用 _ 表示可以省略


func minMax(arr array: [Int], _ x: Int, t: Double) -> (min: Int, max: Int)? {
if array.isEmpty { return nil }

var currentMin = array[0]
var currentMax = array[0]

for value in array[1..<array.count]{
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}

minMax(arr: [1, -1, 2, 23, 934, -234], 3, t: 2.0)
minMax(arr: [], 2, t: 1.0)



//: 默认参数值(Default Parameter Values)
func someFunciton(x: Int = 11) {
print(x)
}

someFunciton()
someFunciton(22)

//: 可变参数(Variadic Parameters)
func arithmeticMean(numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}

return total
}

arithmeticMean(1, 2, 3, 32.232432, 32432.32423)
arithmeticMean(3)
arithmeticMean(1, 3)


//: 常量参数和变量参数(Constant and Variable Parameters)
func alignRight(var string: String, var totalLength: Int, pad: Character) -> String {
totalLength++

let amountToPad = totalLength - string.characters.count
if amountToPad < 1 {
return string
}
let padString = String(pad)

for _ in 1...amountToPad {
string = padString + string
}

return string
}

alignRight("fdsf", totalLength: 8, pad: "*")

//: 输入输出参数(In-Out Patameters)

func swapTwoInts(inout a: Int, inout _ b: Int) {
let tmporaryA = a
a = b
b = tmporaryA
}

var a = 3
var b = 5
swapTwoInts(&a, &b)
a - b


//: 函数类型(Funciton Types)
//: (Int, Int) -> Int
//: () -> Void

func addTwoInts(a: Int, _ b: Int) -> Int {
return a + b
}

func multiplyTwoInts(a: Int, _ b: Int) -> Int {
return a * b
}

func printHelloWorld() {
print("Hello world!")
}

//: 使用函数类型(Using Function Types)
var mathFunction: (Int, Int) -> Int = addTwoInts
print("Result: \(mathFunction(2, 4))")

mathFunction = multiplyTwoInts
mathFunction(2, 4)

//: 函数类型作为参数类型(Function Types as Parameter Types)
func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 7)

//: 函数类型作为返回类型(Function Types as Return Types)
func stepForward(input: Int) -> Int {
return input + 1
}

func stepBackward(input: Int) -> Int {
return input - 1
}

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
return backwards ? stepBackward : stepForward
}

var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0)

print("Counting to zero:")
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")


//: 嵌套函数(Nested Functions)
func chooseStepFunction1(backwards: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backwards ? stepBackward : stepForward
}

var currentValue1 = -4
let moveNearerToZero1 = chooseStepFunction1(currentValue > 0)

print("Counting to zero:")
while currentValue1 != 0 {
print("\(currentValue1)... ")
currentValue1 = moveNearerToZero1(currentValue1)
}
print("zero!")

The Swift Programming Language 2.1 Examples

源码在 GitHub:https://github.com/gewill/The-Swift-Programming-Language-2.1-Examples

大纲和都写着在注释里,废话不多说,咱们看代码 ->

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
//: Playground - noun: a place where people can play

import UIKit

//: 元组(Tuples)把多个值组合成一个复合值,类似数组加字典混合体
let http404Error = (404, "Not Found")

//: 可以分解取值
let (statusCode, statusMessage) = http404Error
//: 下标访问
http404Error.0
//: 单个元素命名
let http200Status = (statusCode: 200, description: "OK")
http200Status.description


//: nil
var serverResponseCode: Int? = 404
serverResponseCode = nil

//: 声明可选的变量或常量,没有赋值则自动设置nil
var surveyAnswer: String?

//: if语句和强制解析
let convertedNumber = Int("1")

if convertedNumber != nil {
print(convertedNumber!)
}

//: 可选绑定(Optional Binding)
if let actualNumber = Int("32431") {
print(actualNumber)
}

//: 隐式解析可选类型: 你可以把隐式解析可选类型当做一个可以自动解析的可选类型。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。
let possibleString: String? = "An apple"
let forcedString: String = possibleString!

let assumedString: String! = ""
let implicitString: String = assumedString

//: 错误处理(error handling)
func canThrowAnErrow() throws {

}

do {
try canThrowAnErrow()
} catch {

}

遇到的点

  • 参考微信朋友圈,发布新照片后,动态插入原有的朋友圈顶部, 我的理解是存入本地缓存数据库,后台异步上次到服务器.

源码见 GitHub:https://github.com/gewill/Mo-Ran

v0.1 b1

date: 2015.09.20

  • 发布照片按钮 和 发布照片页面
  • 复用先峰小组的 login.StoryBoard
  • AppDelegate 分别实现:跳转登陆和主界面方面

登陆按钮

使用 AFNetworking 的 AFHTTPRequestOperationManager
- POST:parameters:success:failure: 方法,提交 json
格式数据,收到成功或者失败的数据 json。具体格式参考文档。

主要是处理 AFHTTPRequestOperation 的 responseObject 的 json 数据。

遇到网络问题,直接想到 Google,但是搜索的不得要领,无果。最后想到 Charles 网络调试, Request 和 Response 一目了然。非常棒的工具。然后认真查看 API 相关参数的类型的:属性和方法。

成功

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"status": 1,
"data": {
"user_id": "2",
"user_name": "testProjectNew1",
"token": "cec5a0a5e7a1951c87099b96d16851bf6f9f0a21",
"avatar": "",
"project_id": "1",
"last_login": "2015-08-30 17:35:49",
"login_times": 3
},
"message": "Login success"
}

失败

1
2
3
4
5
{
"status": 0,
"error_code": 400,
"message": "No such user"
}

登陆按钮

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
#pragma mark - 登陆按钮
- (IBAction)login:(UIButton *)sender {

NSString *url = @"http://moran.chinacloudapp.cn/moran/web/user/login";

NSDictionary *patameters = @{
@"email" : self.email.text,
@"password" : self.password.text,
@"gdid" : @"Ge Will"
};

AFHTTPRequestOperationManager *manager =
[AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];

[manager POST:url
parameters:patameters
success:^(AFHTTPRequestOperation *_Nonnull operation,
id _Nonnull responseObject) {
NSLog(@"Login success:%@, message:%@", responseObject,
[responseObject objectForKey:@"message"]);

if ([[responseObject objectForKey:@"status"] isEqual:@"1"]) {

// 1 - 获取用户信息
[GWUser shareUser].userID =
[[responseObject objectForKey:@"data"] objectForKey:@"user_id"];

// 2 - 保存用户相关信息到 NSUserDefaults
[[NSUserDefaults standardUserDefaults]
setObject:[GWUser shareUser].userID
forKey:@"userID"];
[[NSUserDefaults standardUserDefaults] synchronize];

// 3 - 视图跳转到 Main.storyboard 主界面
AppDelegate *appDelegate =
(AppDelegate *)[UIApplication sharedApplication].delegate;
[appDelegate loadMainView];
}

}
failure:^(AFHTTPRequestOperation *_Nonnull operation,
NSError *_Nonnull error) {
NSLog(@"Login error:%@", error);
NSLog(@"%@", operation.responseObject);

__unused NSString *status =
[operation.responseObject objectForKey:@"status"];
__unused NSString *errorCode =
[operation.responseObject objectForKey:@"error_code"];
NSString *message = [operation.responseObject objectForKey:@"message"];

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:message
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];

}];
}

if ([[responseObject objectForKey:@"status"] isEqual:@"1"])改为
if ([[responseObject objectForKey:@"status"] intValue] == 1)

v0.2 b2

date: 2015-10-11

Cocoapods改为本地添加,网络不稳定也是无奈。

@杨武老师全天辅导

1. 学习方法

  • 更新 iOS Map,最好每周更新,自己整理思路,每一个控件的用法。
  • 学习新的知识:写一组 Demo 把 API 都实现一边,不看文档就能做出来。至少熟悉 API 的名字和用途。

2. 问题辅导

2.1. KVC KVO

其实就是和点语法一样的,但是提供了一种访问便利,最简单的 KVC 能让我们通过以下的形式访问属性。

  • 键路径(Key Path)
  • 键值验证 (KVV)

2.2. Block

就是匿名函数

2.3. Multitasking

NSOperationQueue,立刻并行执行。

1
2
[queue addOperationWithBlock:^{}];

GCD 则是提供更多灵活性

3. 随堂练习

通过多任务,只看 API,做一个异步下载加载图片的 Demo

Demo 见 GitHub

  • test Block
  • test GCD
  • test NSOperation

谈到这次面试,还是在简书上看到我的博客联系到我的。这个我很高兴,花了一天时间跑去杭州参加面试。

具体面试也没有做题目,因为在之前电话面试时有介绍过公司的业务和 iOS 开发的工作。一开始就直入主题。

先是人事问了我的基本状况和工作经验:

  • 学校的成绩,没想到也问了。我是老实人,我成绩一般,挂了几门数学的课。
  • 我的简历上连籍贯和年龄都没有。
  • 还问到兴趣爱好,我是什么性格的人。朋友怎么评价我的,这个我真答不上,或许是我标签太少,我回头要问问他们。
  • 未来三五年规划,其实就是看我能否稳定的在公司发展。我的要好的朋友在哪里?
  • 学习新的知识的速度
  • 期望薪金,绩效奖和公司将要搬迁

技术方面:

  • 什么是好的程序员的特质
  • 最近的项目是否有主导的想法
  • 如何学习的知识
  • 有什么主动根据需求提出不同的方案?如果不通过,会不会回去自己偷偷做一套出来?
  • 开发学习有什么特别的方法或诀窍
  • 如何才算一个好 App,平时用的有哪些体验特别好的?这个问题我应该拿出手机好好谈谈的,就像纯银的产品分享会一样。
  • 问我有没有准备的内容,没有被问到的。这个确实我没有做好的地方,主动展示自己亮点或水平。

大概这个多,好多关键的问题我都没好好问答就跳过去了。回去还要好好整理一下,也算是整理一下自己对技术的一些思考。期待我更新吧。

我的表现:

  • 表达的还算正常,比起以前有进步
  • 好多话题我熟悉应该展开,是最好的
  • 好多以前没有想过的问题,及时反应还是很慢,不能够及时总结提炼观点
0%