网站加了一个 hexo-filter-auto-spacing 插件,中英文之间自动加空格😊

2.1 类和对象

  • 类和对象。对象通过实例变量保存属性的值。

  • 类有方法,类似函数,调用对象的方法一般叫发消息。

    1
    2
    [ partyInstance addAttendee: somePerson
    withDish: deviledEggs]
  • 方法的唯一性取决方法名。

  • 实例变量的存取方法:get 和 set

  • 发消息的三种语法:

    • 发消息[]:调用方法
    • 点语法.:存取实例变量
    • 下标语法[]:访问数组
  • 类方法和实例方法区别:

    • 类方法通常用来创建对象,或者获取类的全局变量
    • 实例变量则是用来操作类的对象(对象就是类的实例),如存取方法
  • 类方法的初始化

    必须选一个指定初始化方法,其他初始化方法可以调用指定初始化方法,形成一个初始化方法链
    初始化方法链

2.5 NSArray与 NSMultableArray

数组对象只能保存指向 Objective-C 对象的指针,不能保存基本类型和 C 结构加入数组对象。当然包装成 Objective-C 对象,就可以了,如 NSNumber、NSValue 和 NSDate。nil 包装成 NSNull 才能加入数组。

项目代码保存在我的 GitHub: iOSProgramming4edSolutions

1. Split View Controllers & Navigation Controllers & Tab Bar Controllers

Slide 中图太多就不一一贴在这里了

UINavigationController 比喻成一堆卡片,只能看到一张卡片。新的 MVC 出来,旧的就被丢弃。

2. Segues

Segue 总是引导到一个新建的 MVC,旧的同样被丢弃。

Storyboard 总是通过名字连接代码的:UIView 的 Class、View Controller 的 Class、Outlet 的名字、IBAction 的名字,这是一种松散耦合,能够这个两件东西连接起来。

3. Demo: Psychologist

最好的理解就是做实践(Demo)。

我们将会新建一个 Psychologist MVC

Psychologist 将会披露他的诊断,通过 segue Happiness MVC。

我们会把 MVCs 放进 navigation controllers 内部 split view controllers,它将兼容 iPad 和 iPhone 设备。

Autolayout 另一个技巧是使用 Reset to Suggested Constraints,配合 Size Inspector 面板里 Descendant Constraints。

4. Popovers

Popover 对应的是 popoverPresentationController

由于 Popover 出来的 MVC 每次的新建的,History 相关信息可以存储到 NSUserDefaults 中。

iPad 是小的弹窗,iPhone 默认 Modal,可以改回 Popover。

可以UIPopoverPresentationControllerDelegate协议,重写 UIViewController 中的 preferredContentSize 自定义大小。

源码保存在我的 GitHub: CS193P-2015

网站添加 Tags,方便分类查找文章。 Medium 非常简洁优雅,可以借鉴。网站改版和文章排版比较耗费时间,以后要以内容输出优先。

关于课程中 Swift 语言的知识我只是简单浏览一遍,毕竟他说的也不详细,真正搞懂还是要系统学习。复习一下《疯狂 Swift 讲义》或者 Google 都是可行的。重要是 Demo 实践。今天微博看到的玩笑:Computer Programming To Be Officially Renamed “Googling Stackoverflow”

1. Interface Builder

Demo: 自定义 UIViews in your storyboard (FaceView)

如何在iOS 8中使用Swift和Xcode 6制作精美的UI组件 有个例子:苹果在Xcode 6中加入了两个新的Interface Builder(下文用IB简称)属性声明:IBInspectable和IBDesignable。IBInspectable在IB的Attribute Inspector(属性检查器)中查看类的属性,而IBDesignable能实时更新视图,很厉害吧!

2. The Happiness MVC’s Model

是寄于 HappinessViewController 里的 happiness,不同于 smiliness。

3. Protocols and Delegation

扩展

协议也是一种数据类型

代理是一种非常重要的协议的应用。
代理是我们完成视图和控制器盲沟通的方式。

Delegation

通过代理模式 UIViews 可以控制 Model,虽然并不是真的拥有 Model。

如何实现:

  1. 视图中创建一个代理协议 (定义具体视图想要控制器关心的内容)
  2. 视图中创建一个代理的属性,其类型是代理协议
  3. 视图中使用代理的属性去得到并不用的事,或做并不能控制的事
  4. 控制器声明并完成代理协议
  5. 控制器把自己作为视图的代理,通过设置设置代理的属性(上面2提到的)
  6. 控制器实施协议

现在视图就勾住了控制器。不过视图仍不晓得控制器的内容,所以视图仍是通用/可重复使用的。

Demo: Happiness MVC’s Model using generic FaceView in its View

Cmd + Shift + O 快速打开文档,有种 Xcode 内置 spotlight 的即视感。

FaceView.swift 为自定义 UIView 的类,是 View。
HappinessViewController.swift 是继承自 UIViewController,是 Controller。

View 中 dataSource 是 protocol FaceViewDataSource 的属性(代理或数据源),作为 dataSource?.smilinessForFaceView(self) 的形参。

Controller 实现了该协议,并将自己作为代理的对象,并通过 happiness 变量来改变协议中

Controller 中的 faceView 通过 Outlet 监控 dataSource 值的改变(didSet),来控制 View 笑脸的变化(smiliness)。

Happiness MVC

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

// FaceView.swift 部分代码


import UIKit

protocol FaceViewDataSource: class {
func smilinessForFaceView(sender: FaceView) -> Double?
}

@IBDesignable
class FaceView: UIView
{
@IBInspectable
var lineWidth: CGFloat = 3 { didSet { setNeedsDisplay() } }
@IBInspectable
var color: UIColor = UIColor.blueColor() { didSet { setNeedsDisplay() } }
@IBInspectable
var scale: CGFloat = 0.90 { didSet { setNeedsDisplay() } }

var faceCenter: CGPoint {
return convertPoint(center, fromView: superview)
}
var faceRadius: CGFloat {
return min(bounds.size.width, bounds.size.height) / 2 * scale
}

weak var dataSource: FaceViewDataSource?


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
//  HappinessViewController.swift


import UIKit

class HappinessViewController: UIViewController, FaceViewDataSource
{

@IBOutlet weak var faceView: FaceView! {
didSet {
faceView.dataSource = self
}
}
var happiness: Int = 99 { // 0 = very sad, 100 = ecstatic
didSet {
happiness = min(max(happiness, 0), 100)
print("happiness = \(happiness)")
updateUI()
}
}

func updateUI() {
faceView.setNeedsDisplay()
}

func smilinessForFaceView(sender: FaceView) -> Double? {
return Double(happiness - 50) / 50
}
}

4. Gestures

手势识别分两步走:

  1. Adding a gesture recognizer to a UIView (asking the UIView to “recognize” that gesture)
  2. Providing a method to “handle” that gesture (not necessarily handled by the UIView)

Usually the first is done by a Controller
Though occasionally a UIView will do this itself if the gesture is integral to its existence

The second is provided either by the UIView or a Controller Depending on the situation. We’ll see an example of both in our demo.

第一步:Adding a gesture recognizer to a UIView

Imagine we wanted a UIView in our Controller’s View to recognize a “pan” gesture …

pannableView

上面的代码造成排版错误,估计代码高亮产生的,先换成图片。

This is just a normal outlet to the UIView we want to recognize the gesture

We use its property observer to get involved when the outlet gets hooked up by iOS

Here we are creating an instance of a concrete subclass of UIGestureRecognizer (for pans)

The target gets notified when the gesture is recognized (in this case, the Controller itself)

The action is the method invoked on recognition (the : means it has an argument)

Here we ask the UIView to actually start trying to recognize this gesture in its bounds

Let’s talk about how we implement the handler …

第二步:A handler for a gesture needs gesture-specific information

So each concrete subclass provides special methods for handling that type of gesture

For example, UIPanGestureRecognizer provides 3 methods

func translationInView(view: UIView) -> CGPoint // cumulative since start of recognition

func velocityInView(view: UIView) -> CGPoint // how fast the finger is moving (points/s)

func setTranslation(translation: CGPoint, inView: UIView)

This last one is interesting because it allows you to reset the translation so far

By resetting the translation to zero all the time, you end up getting “incremental” translation

The abstract superclass also provides state information

var state: UIGestureRecognizerState { get }
This sits around in .Possible until recognition starts
For a discrete gesture (e.g. a Swipe), it changes to .Recognized (Tap is not a normal discrete) For a continues gesture (e.g. a Pan), it moves from .Began thru repeated .Changed to .Ended
It can go to .Failed or .Cancelled too, so watch out for those!

So, given this information, what would the pan handler look like?

  func pan(gesture: UIPanGestureRecognizer) {
      switch gesture.state {
          case .Changed: fallthrough
          case .Ended:
              let translation = gesture.translationInView(pannableView)
// update anything that depends on the pan gesture using translation.x and .y
            gesture.setTranslation(CGPointZero, inView: pannableView)
        default: break
     }
}
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

Remember that the action was “pan:” (if no colon, we would not get the gesture argument)

We are only going to do anything when the finger moves or lifts up off the device’s surface

fallthrough means “execute the code for the next case down” Here we get the location of the pan in the pannableView’s coordinate system Now we do whatever we want with that information By resetting the translation, the next one we get will be how much it moved since this one ### 常用手势:
- UIPinchGestureRecognizer
var scale: CGFloat // not read-only (can reset)

var velocity: CGFloat { get } // scale factor per second
- UIRotationGestureRecognizer
var rotation: CGFloat // not read-only (can reset); in radians

var velocity: CGFloat { get } // radians per second
- UISwipeGestureRecognizer Set up the direction and number of fingers you want, then look for .Recognized

var direction: UISwipeGestureRecoginzerDirection // which swipes you want

var numberOfTouchesRequired: Int // finger count
- UITapGestureRecognizer
Set up the number of taps and fingers you want, then look for .Ended

var numberOfTapsRequired: Int // single tap, double tap, etc.

var numberOfTouchesRequired: Int // finger count

 ### Demo: Happiness pinch and pan

**FaceView Gestures**
Add a gesture recognizer (pinch) to the FaceView to zoom in and out (control its own scale)

Add a gesture recognizer (pan) to the FaceView to control happiness (Model) in the Controller ```

// FaceView.swift 部分代码


import UIKit

protocol FaceViewDataSource: class {
func smilinessForFaceView(sender: FaceView) -> Double?
}

// 2. handler
func scale(gestrue: UIPinchGestureRecognizer) {

if gestrue.state == .Changed {
scale *= gestrue.scale
gestrue.scale = 1
}
}


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
//  HappinessViewController.swift 部分代码


import UIKit

class HappinessViewController: UIViewController, FaceViewDataSource
{

@IBOutlet weak var faceView: FaceView! {
didSet {
faceView.dataSource = self

// 1. Adding a gesture recognizer
faceView.addGestureRecognizer(UIPinchGestureRecognizer(target: faceView, action: "scale:"))
// try in storyboard
// faceView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "changeHapponess:"))
}
}


// 通过 storyboard 添加 Pan Gesture Recognizer,然后 storyboard 添加 IBAction 到 Controller 中
private struct Constants {
static let HappinessGestureScale: CGFloat = 4
}

@IBAction func changeHappiness(gesture: UIPanGestureRecognizer) {
switch gesture.state {
case .Ended: fallthrough
case .Changed:
let translatrion = gesture.translationInView(faceView)
let happinessChange = -Int(translatrion.y / Constants.HappinessGestureScale)
if happinessChange != 0 {
happiness -= happinessChange
gesture.setTranslation(CGPointZero, inView: faceView)
}
default: break
}
}

var happiness: Int = 3 { // 0 = very sad, 100 = ecstatic
didSet {
happiness = min(max(happiness, 0), 100)
print("happiness = \(happiness)")
updateUI()
}
}

func updateUI() {
faceView.setNeedsDisplay()
}

func smilinessForFaceView(sender: FaceView) -> Double? {
return Double(happiness - 50) / 50
}
}

>有待翻译 ## 5. 拓展阅读 [UIGestureRecognizer Tutorial: Getting Started](http://www.raywenderlich.com/76020/using-uigesturerecognizer-with-swift-tutorial) ## 项目代码保存在我的 GitHub: [CS193P-2015](https://github.com/gewill/CS193P-2015)

还是@段松 老师,讲解了 Xcode 常用的设置。还有楼房设计和楼房建造对应软件设计框架和代码实现。

课程目标:

  • 会做 APP
  • APP 微架构、代码风格

课程大纲:

  • 熟悉 Xcode

  • 一个 iOS 应用的构成详解

  • iOS 应用的生命周期

  • 一款 iOS 应用是如何产生的?

    看了7遍需求文档,心中自然有了成了一个原型图,甚至找到需求中缺乏的组件。

    曾经辍学做过建筑,就有了下面比喻,很形象好理解:

楼房建造流程图
iOS 开发流程图

项目开发流程图:

项目开发流程图

@段松 老师有7年的iOS研发经验,一线大牛我喜欢,奇幻之旅就正式开始吧。

iOS 开发和盖房子差不多,那么我们就先学习一些基本建筑材料:数据类型与操作符。后面还有一些数组、运算符、流程控制语句、枚举、结构体和宏定义等。

虽然这些之前都有学过,也算温故知新吧。和 Swift 相比确实繁琐古老的一些。

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
NSInteger age = 18;
NSInteger testAge;
testAge = age >= 18 ? 1 : 0;


if (testAge) {
NSLog(@"你已经是个成年人了");
} else {
NSLog(@"你还是未成年人");
}

char name[] = "Will";
printf(name);

NSInteger price = 4;
switch (price) {
case 4: {
NSLog(@"four");
NSLog(@"more than one line.");
break;
}
case 3:
NSLog(@"three");
break;
case 2:
NSLog(@"two");
break;
default:
break;
}

bool isFemale = false;
BOOL isMale = YES;
if (isMale) {
if (!isFemale) {
NSLog(@"You are a ture man.");
}
}

// 循环
int sum = 0;
for (int i = 1; i <= 100; ++i) {
sum += i;
}
NSLog(@"%i", sum);

int sum1 = 0;
int j = 1;
for ( ; ; ) {
sum1 += j;
j++;
if (j > 100) {
break;
}
}
NSLog(@"%i", sum1);


// 枚举
enum Person {GoodGirl, GodBoy, BadGirl, BadBoy};
enum Person someone;
someone = GodBoy;
if (someone != BadBoy && someone != BadGirl) {
NSLog(@"Someone is a good person.");
}


// 结构体
typedef struct {CGFloat x; CGFloat y;} MyPoint;
MyPoint myPoint = {6, 8};
CGFloat result = myPoint.x + myPoint.y;
NSLog(@"result = %f", result);

// #define 宏:文本替换

#define PI 3.1415926
#define SQUARE(x) ((x)*(x))

NSLog(@"%f", PI * SQUARE(5 - 4)); // 3.141593
NSLog(@"%.7f", PI * SQUARE(5 - 4)); // 3.1415926
NSLog(@"%e", PI * SQUARE(5 - 4)); // 3.141593e+00

// #import 导入文件
// #import "example.h"

// 条件编译
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#endif

极客班线下翻转课堂第一周,坐标浦东软件园,时间7月19日。

一天下来学习不少关于开发和产品的干货,感觉获益匪浅,但是还是要以后的学习和项目中实践可能才会理解透彻。本来参加极客班,是因为一个人独自钻研太累进展缓慢,现在感觉豁然开朗,信心十足,最主要的是有了学习的精神头,希望这一份主动性能够持续下去。既然 iOS 是我兴趣爱好,完成线上课程的同时,完成自我管理自律,明天图书馆约起。

课程安排的是线上课堂和项目实践同时进行,我想也多少和 Tiny 老师提到的学习方法相通:先了解官方文档 Guidelines,Release note,Documentation,理清楚技术架构关系,项目实际使用技术重点学习突破,也就完成了项目(大意如此)。

今天最大缺憾是没有和老师同学很好的交流,无论是上台提创意,提问题,听课有疑问没有去请教。一则我一直性格害羞内向,二则因为一造成的缺乏想法表达能力和技巧。性格弱我早就知道,天天提醒自己最棒能做好,希望能一点点进步。

以下是课程安排:

自我介绍:

一部分同学是网络,开发,室内设计,摄影,大三,多是因为兴趣爱好报名的。但更多的都已经是几年的开发经验,还有几个是5-10年的,没有开发工作经验的我要努力了,不能落了后。

@李建忠

线下班推你下水,逼你学会游泳。真实做项目中学习技术。

推荐 iOS 样板项目供同学选择:

  • 移动的 Blog
  • 交互式白板
  • 多媒体相册

@Tinyfool

  • 全栈:建筑学-掌握全局

    实际项目需要技术和知识,如何组合运用到项目中,再去详细学习。培训目的,自主学习,遇到具体的难题可以提问。

  • 创业: Zero to One,先失败,项目火之前少有人认同,先做一个简版让客户评判

  • 项目管理:项目迭代去做,MVP,如:10行代码,成就感,

    PM 和程序员关系,需求优先级往往没说,程序员分功能评估时间。两者之间的如何协作好,进度表中的关键:细分技术评估时间,确定优先级。

  • 融资->招人->离职,半年才招齐人

  • 创业泥潭,产品不温不火,添加不靠谱功能

  • UX 优先级低于功能实现

  • 先站出来才有人认识你,占尽便宜

  • 以后课堂不说了,只接受提问交流

孔祥波

经历:Unix/SA->SP->Python->OC

写代码自我要求,优秀。不要用直接抄袭其他产品。

知识像产品迭代,每次看一个知识都会不一样的理解。能讲解一个知识或技术,说明真的懂了。例如:UIObject等的继承关系。

大家提创意项目:

  • 信贷员工具项目
  • 个人版历史上的今天
  • 局域网多屏互动
  • 摄影项目
  • 个人头像贴图

董飞

算法原理与实践 课程知识梳理。

投票分组选项目

互联网:UGC(User-generated content)、用户互动、公司基因创始人背景专业

组团学习重要性,学习是动词

证书不重要,重要的是真正学习成长

重分享:output 带动 input

TODO:第一周的功能列表,团队 GitHub账号

我选了信贷员工具项目。

1. Objective-C 兼容性

Bridging

Swift 可以无缝使用以前 Objective-C 的 API,但是一些特殊的数据类型需要桥接。桥接是指可以互换的使用。

NSString <-> String

NSArray <-> Array

NSDictionary <-> Dictionary<NSObject, AnyObject>

Int, Float, Double, Bool -> NSNumber (反之不行)

99%的桥接均是隐式完成的。

2. 属性列表

属性列表指 AnyObject 是一下六种类型的集合列表:
NSString, NSArray, NSDictionary, NSNumber, NSData, NSDate。

处理属性列表通常需要映射:如 is 和 as。

属性列表可以“盲”传递数据,也可以作为一种通用数据结构-类似泛型。

NSUserDefaults 作为一种使用属性列表的存储机制。本质上就是一个小的存储数据列表的数据库。通常用存储“设置”信息。
NSUserDefaults 可以通过名称或键来存储或检索整个属性列表。

以下用法摘自:NSUserDefaults — A Swift Introduction

存储 NSUserDefaults

1
2
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("Coding Explorer", forKey: "userNameKey")

NSUserDefaults 常用的写入方法:

  • func setBool(value: Bool, forKey defaultName: String)
  • func setInteger(value: Int, forKey defaultName: String)
  • func setFloat(value: Float, forKey defaultName: String)
  • func setDouble(value: Double, forKey defaultName: String)
  • func setObject(value: AnyObject?, forKey defaultName: String)
  • func setURL(url: NSURL, forKey defaultName: String)

iOS 8或更新版本不要使用 synchronize。

读取 NSUserDefaults

1
2
3
4
5
let defaults = NSUserDefaults.standardUserDefaults()
if let name = defaults.stringForKey("userNameKey")
{
println(name)
}

对应的常用读取 NSUserDefaults 的方法:

  • func boolForKey(defaultName: String) -> Bool
  • func integerForKey(defaultName: String) -> Int
  • func floatForKey(defaultName: String) -> Float
  • func doubleForKey(defaultName: String) -> Double
  • func objectForKey(defaultName: String) -> AnyObject?
  • func URLForKey(defaultName: String) -> NSURL?
  • func dataForKey(defaultName: String) -> NSData?
  • func stringForKey(defaultName: String) -> String?
  • func stringArrayForKey(defaultName: String) -> [AnyObject]?
  • func arrayForKey(defaultName: String) -> [AnyObject]?
  • func dictionaryForKey(defaultName: String) -> [NSObject : AnyObject]?

使用常量做键

方便在一处修改,容易理解编译报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let userNameKeyConstant = "userNameKey"

@IBAction func writeButton(sender: UIButton)
{
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("Coding Explorer", forKey: userNameKeyConstant)
}

@IBAction func readButton(sender: UIButton)
{
let defaults = NSUserDefaults.standardUserDefaults()
if let name = defaults.stringForKey(userNameKeyConstant)
{
print(name)
}
}

3. 视图

视图代表了一个长方形区域。

视图是等级,类似单继承:一个视图只可以有一个 superview,但可以有很多 subviews。

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
//
// FaceView.swift
// Happiness
//
// Created by Will Ge on 7/17/15.
// Copyright © 2015 gewill.org. All rights reserved.
//

import UIKit

class FaceView: UIView {

var lineWidth: CGFloat = 5 { didSet { setNeedsDisplay() } }
var color: UIColor = UIColor.blueColor() { didSet { setNeedsDisplay() } }
var scale: CGFloat = 0.9
var faceCenter: CGPoint {
return convertPoint(center, fromView: superview)
}

var faceRadius: CGFloat {
return min(bounds.size.width, bounds.size.height) / 2 * scale
}

// 覆写 drawRect,自定义视图
override func drawRect(rect: CGRect) {

// 画脸
let facePath = UIBezierPath(arcCenter: faceCenter, radius: faceRadius, startAngle: 0, endAngle: CGFloat(2 * M_PI), clockwise: true)
facePath.lineWidth = lineWidth
color.set()
facePath.stroke()

// 画眼
bezierPathForEye(.Left).stroke()
bezierPathForEye(.Right).stroke()

// 画嘴巴
let smiliness = 0.8
let smilePath = bezierPathForSmile(smiliness)
smilePath.stroke()
}


private struct Scaling {
static let FaceRadiusToEyeRadiusRatio: CGFloat = 10
static let FaceRadiusToEyeOffsetRatio: CGFloat = 3
static let FaceRadiusToEyeSeparationRatio: CGFloat = 1.5
static let FaceRadiusToMouthWidthRatio: CGFloat = 1
static let FaceRadiusToMouthHeightRatio: CGFloat = 3
static let FaceRadiusToMouthOffsetRatio: CGFloat = 3

}

// 定义枚举:左右眼
private enum Eye { case Left, Right }

// 定义函数:眼睛的路径
private func bezierPathForEye(whichEye: Eye) -> UIBezierPath {

let eyeRadius = faceRadius / Scaling.FaceRadiusToEyeRadiusRatio
let eyeVerticalOffset = faceRadius / Scaling.FaceRadiusToEyeOffsetRatio
let eyeHorizontalSeparation = faceRadius / Scaling.FaceRadiusToEyeSeparationRatio

var eyeCenter = faceCenter
eyeCenter.y -= eyeVerticalOffset
switch whichEye {
case .Left: eyeCenter.x -= eyeHorizontalSeparation / 2
case .Right: eyeCenter.x += eyeHorizontalSeparation / 2
}

let path = UIBezierPath(arcCenter: eyeCenter, radius: eyeRadius, startAngle: 0, endAngle: CGFloat(2 * M_PI), clockwise: true)
path.lineWidth = lineWidth
return path

}

// 定义函数:嘴巴的路径
private func bezierPathForSmile(fractionOfMaxSmile: Double) -> UIBezierPath {

let mouthWidth = faceRadius / Scaling.FaceRadiusToMouthWidthRatio
let mouthHeight = faceRadius / Scaling.FaceRadiusToMouthHeightRatio
let mouthVerticalOffset = faceRadius / Scaling.FaceRadiusToMouthOffsetRatio

let smileHeight = CGFloat(max(min(fractionOfMaxSmile, 1), -1)) * mouthHeight

let start = CGPoint(x: faceCenter.x - mouthWidth / 2, y: faceCenter.y + mouthVerticalOffset)
let end = CGPoint(x: start.x + mouthWidth, y: start.y)
let cp1 = CGPoint(x: start.x + mouthWidth / 3, y: start.y + smileHeight)
let cp2 = CGPoint(x: end.x - mouthWidth / 3, y: cp1.y)

let path = UIBezierPath()
path.moveToPoint(start)
path.addCurveToPoint(end, controlPoint1: cp1, controlPoint2: cp2)
path.lineWidth = lineWidth
return path
}


}

上个星期五正式从公司离职,做了一年整。为什么辞职不做 IT 技术支持,一个原因工资太低。

记得当初进公司是在家自学了3个月 iOS 无果,准备一边上班一边继续自学,现在看来多么傻的一个决定,既然不想做 IT 技术支持,就不要做。因为实际上很累,一天下来,偶尔还要加班,完全没有精力晚上在学习。当然只是一部分原因,最主要的阻碍是我自律很差,完全不适合自学。早早的应该3年前和老爸去咨询 IT 开发培训的时候,就该入学的。也不至于毕业3年,一事无成。

最近几天我在浦东图书馆学习,效率很高,完全能够投入其中。报了博览网的 iOS 极客班,希望能够一反面改变我自己:提高自我管理能力,另一方面也能得到系统的学习和大神的指导。

选择极客班不仅仅是价格比传统线下培训学校便宜,主要看中老师都是一线的大牛。最初最初也是通过@tinyfool 老师了解到极客班,相信性情中人不会错。期待周末开班,当然还有顺利结业并找到 iOS 的工作。

Swifter - 100 个 Swift 必备 tips,作者[王巍](SWifter - 100个 Swift 必备 tips)。书买了很久了,25元比实体书便宜不少,而且收入基本上都归作者。学习完疯狂 Swift 讲义,再看看这个补充一下。

章节顺序可能与书不一致,全凭兴趣随意浏览,尤其是不太懂得方面。

##操作符
infix 表示一个中位操作符,前后都有输入。类似的还有 prefix 和 postfix。

associativity 定义了结合律

precedence 运算的优先级,Swift 中乘法和除法的优先级是150,加法和减法是140,这里定义160,就是高于普通的四则运算。

操作符定义在全局,不可滥用。

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
//  main.swift
// Swift-test

import Foundation

struct Vector2D {
var x = 0.0
var y = 0.0
}

func +(left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}

let v1 = Vector2D(x: 2.0, y: 3.0)
let v2 = Vector2D(x: 1.0, y: 5.0)
print(v1 + v2) // Swift_test.Vector2D(x: 3.0, y: 8.0)

infix operator +* {
associativity none
precedence 160
}

func +*(left: Vector2D, right: Vector2D) -> Double {
return left.x * right.x + left.y * right.y
}

print(v1 +* v2) // 17.0

随机数生成

创建一个 Range 的随机数的方法,方便以后复用。

Swift 支持 // MARK: 、// TODO:、// FIXME:等编译标记,方便分段,将一标签的形式显示在导航栏中,让程序更易读。

1
2
3
4
5
6
7
8
9
10
// MARK: 实现方法
func randomInRange(range: Range<Int>) -> Int {
let count = UInt32(range.endIndex - range.startIndex)
return Int(arc4random_uniform(count)) + range.startIndex
}

// TODO: 测试是否有效
for _ in 0...100 {
print(randomInRange(1...6))
}

断言

对于判断输入是否满足某种条件的运用情景,使用断言比 if 更合适。且在 Debug 编译是才有效,运行时不被编译执行,不会消耗运行时的性能。是非常合适的调试判断。

1
2
3
4
5
6
7
8
9
10
import Foundation

func convertToKelvin( celsius: Double) -> Double {
let AbsoluteZeroInCelsius = -273.15
assert(celsius > AbsoluteZeroInCelsius, "输入的摄氏温度不能低于绝对零度。")
return celsius - AbsoluteZeroInCelsius
}

let roomTemperature = convertToKelvin(27)
print(roomTemperature) // 300.15

自省

程序设计和人类哲学所面临的同一个重大课程就是解决“我是谁”。

isKindOfClass、isMemberOfClass、is

1
2
3
4
5
6
7
8
9
class ClassA: NSObject { }
class ClassB: NSObject { }

let obj1: NSObject = ClassA()
let obj2: NSObject = ClassB()

print(obj1.isKindOfClass(ClassA.self)) // true
print(obj2.isMemberOfClass(ClassA.self)) // false

属性观察

属性观察可以对当前类型内监视其属性的设定,并作出响应。

1
2
3
4
5
6
class MyClass {
    var date: NSDate {
        willSet {
        print("即将将日期从 \(date) 设定至 \(newValue)")
        }
        didSet {
        print("已经将日期从 \(oldValue) 设定至 \(date)")
        }
} init() { date = NSDate() }
}
let foo = MyClass() foo.date = foo.date.dateByAddingTimeInterval(10086)
// 输出 // 即将将日期从 2015-07-16 16:01:49 +0000 设定至 2015-07-16 18:49:55 +0000
// 已经将日期从 2015-07-16 16:01:49 +0000 设定至 2015-07-16 18:49:55 +0000

本节介绍了一些 Swift 和 Foundation Framework,基本是要求自己搜索学习完成的,最好是参考 Swift 教材系统看看。说实话老师一节课只是把大纲列一下,好多根本没有展开详细系统的讲,当然时间上也不允许。

  • 可选值和枚举
  • 数组、字典、区间
  • 数据类型
  • 方法
  • 属性
  • 初始化
  • AnyObject
  • 常用的方法和函数
0%