@李建忠:课程安排

startup:账号系统,登陆系统,setting,有时间的组员可以多做一点

项目变化,很正常,确定人员分配,推动项目往前走。

@袁店明:探讨产品

我们小组的项目“一秒”:需求真实性,目的在哪里,目标用户为什么会用,解决什么问题。

添加一个主题:亲子成长,空气环境变化。

分享带有主题的视频,类似 iMovie 的手机版

很多时候需求都是你自己猜想的,产品的使用场景,都是需要验证的!

言语表达要求很高。

语言描述要准确,不一定要非常简练华丽。

@李建忠: A good thinker is a good talker.

例子:上班很远,并不是所有人都是问题,并不是所有人都一样的界定。所以提供的解决方案都不一样,用户真实的上班方式开车自行车走路,又该如何解决?要面对面访谈用户,电话次之。

产品探索过程中,要抛弃自己的创意和解决方法,重点在用户的需求和相应的解决方案,最后收敛(投票和排序重要性)成一个产品。

所有人:销售运营开发测试产品经理坐在一起产品的逻辑推理,然后才能进行用户访谈。

用户细分,不然找错人浪费了时间经理。

这一套做产品思维,可以用工作中,如正在培训的创业公司敏捷开发。

不要让天使用户看到你的访谈的问题。

热点事件来分析,提高逻辑推理。推荐《系统化思维导论》

最近在看《精益数据分析》

用户群不要混合现有用户群来定义你的用户群,如:色影无忌和蜂鸟网

用户发现问题->寻找解决方案->找到产品->愿意付费

我是 iOS 学员,关于产品方面听来挺过瘾。多谢 Tele Deng 的笔记:【极客班-精益产品探索】第一周课堂笔记

@段松:iOS 大纲的梳理

说话真心快

创业中:健美乐

过去培训经验:5小时 * 12天完成培训,走向职场。

不是看了多少书,死记硬背了多少知识点,更多是写代码的能力,写的多了自然会用了。

学习过程中类比现实生活中的东西,可能比较容易理解。

代理就是委托,力有不逮时,联系朋友去完成。

学习方法:就是梳理大纲知识点,掌握要点,理清楚后,自己写代码自然就会了。

先学习整体框架,后学习细节。

UITabBarViewController 90%使用的框架。

UITableView

实战中的两种应用框架(后续课程)

查看开源项目,删除多余的部分,只看自己关注的部分。最基本也要会用开源框架。

iOS 数据结构用的不多。

分享易庆晟的笔记:GeekBand第二周线下课堂,总结的非常好。

@李建忠:C++ 辅导

分享 X-Lion 的 C++ 笔记:极客班GeekBand - C++第一次课程辅导 - 李建忠,和于航的笔记:GeekBank极客班C++线下班学习心得(二)

@李建忠:确定项目

均衡组员分配,iOS/C++/PM,考虑到产品上线审核产生的延迟,要提前两周就要完成项目,约9月12日。

基于 MVP,产品原型图和技术要点分解同步进行,快速迭代,让真实项目催促你前进。

一天下来,我们小组项目最终打磨为:“一秒变大人”,张诚 PM、我和易庆晟iOS 方面、郭意亮 C++ 技术、还有新加入的沈秋艳 PM,希望尽快下周末前出第一个版本。

我负责项目图片视频处理方面,TODO:

-阅读图片视频相关的文档
-objc.io 关于图片视频的小节
-找几个相关开源的项目

Swift or Objective-C?虽然两门课都有,但是我还是❤️Swift,并不仅仅因为❤️Taylor。

3.1 栈

栈对应方法或函数的帧,堆则是包含大量 iOS 应用创建的对象

3.3 指针变量与对象所有权

引用计数就是社保局,调查每个人有几份工作,一个正式工作,或兼职几份工作,或失业。失业,内存就会被释放,就会给你这个 free man 推荐新工作。

那些情况会使对象失去拥有者:

  • 修改指针指向另一个变量(跳槽)
  • 设为 nil(辞职)
  • 对象拥有者被释放(公司倒闭)
  • 从 collection 对象中删除对象(裁员)

当对象没有拥有者时,指针变量的内存就该被释放。

3.4 强引用与弱引用

解决强引用循环问题后的RandomItems
大部分强引用循环可以确定一个父子关系,子对象改为弱引用即可。

Xcode 的 Leaks 工具可以帮忙找出强引用循环问题。

3.5 属性

声明属性,等于隐式地声明和创建相应名称的实例变量,声明一对存取方法。当然我们还可以自定义存取方法。

属性的特性(attribute):

  • 多线程:nonatomic/atomic
  • 读写:readwrite/readonly
  • 内存管理:strong/weak/copy/unsafe_unretained

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

网站加了一个 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 的工作。

0%