参考文档

我的总结

上面的文档都已经讲的问清楚了,也就几个属性可调。参考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
//: 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

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

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

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,平时用的有哪些体验特别好的?这个问题我应该拿出手机好好谈谈的,就像纯银的产品分享会一样。
  • 问我有没有准备的内容,没有被问到的。这个确实我没有做好的地方,主动展示自己亮点或水平。

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

我的表现:

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

1. Difference Segue Excute in Container View to AVPlayerViewController

Demo on GitHub

Objective-C this method won’t be execute.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// In Swift should check the method, even user don't tap the cantainer view.
// But in Objective-C, *** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException',
// reason: 'Could not instantiate class named AVPlayerViewController'
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

// set up the player
if ([segue.identifier isEqual: @"videoSegue"]) {

NSString *path = [[NSBundle mainBundle] pathForResource:@"yishengsuoai" ofType:@"mp4"];
NSURL *url = [[NSURL alloc] initFileURLWithPath:path];

AVPlayerViewController *vc = segue.destinationViewController;
vc.player = [AVPlayer playerWithURL:url];
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// BEGIN avkit_ios_config
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "videoSegue"
{
// set up the player
let videoURL = NSBundle.mainBundle().URLForResource("TestVideo",
withExtension: "m4v")
let videoViewController =
segue.destinationViewController as! AVPlayerViewController
videoViewController.player = AVPlayer(URL: videoURL)
}
}
// END avkit_ios_config

2. Conclusion

  • Swift + Container View(In IB)
  • Objective-C + AVPlayerLayer (In Code)

3. Definiton

- prepareForSegue:sender:

Notifies the view controller that a segue is about to be performed.

###Discussion

The default implementation of this method does nothing. Your view controller overrides this method when it needs to pass relevant data to the new view controller. The segue object describes the transition and includes references to both view controllers involved in the segue.

Because segues can be triggered from multiple sources, you can use the information in the segue and sender parameters to disambiguate between different logical paths in your app. For example, if the segue originated from a table view, the sender parameter would identify the table view cell that the user tapped. You could use that information to set the data on the destination view controller.

“Delete” the extra separator of UITableView with pain style

ios - Eliminate Extra separators below UITableView - in iphone sdk? - Stack Overflow

Solution 1

1
2
3
4
5
// "Delete" the extra separator of UITableView and the last one Separator in ecah Section
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

return 0.01f;
}

height=0.01f

Solution 2

1
2
3
- (void)viewDidLoad {
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
}

CGRectZero

Table View Style

UITableViewStylePlain

A plain table view. Any section headers or footers are displayed as inline separators and float when the table view is scrolled.

UITableViewStyleGrouped

A table view whose sections present distinct groups of rows. The section headers and footers do not float.