标签:条目 模式 计算 调用 targe 设计模式 net 接受 ddl
继续上一话中的计算器Demo。上一话讲到类必须被初始化。类中的属性也必须被初始化,所以你不能仅仅声明而不给它一个处置,那么问题来了,我们从storyboard中拖拽的@IBOutlet为什么仅仅有声明而不须要初始化呢,这是由于它的类型依然是一个optional,在你初始化之前已经被赋值为nil了,这也就是为什么你不须要再初始化它的原因。
@IBOutlet weak var display: UILabel!
我们当然能够给display加入一个。来解包
display!.text = digit由于拖拽生成的原因。左边的xib界面初始化之后和右边的viewcontroller关联,那么这些@IBOutlet就已经被初始化了而且是永久初始化,假设我们每次用的时候都要加一个“!
”。那实在太耽误事了。所以拖拽生成的变量类型后面是自己主动添加的“。”表达了这个变量尽管是一个optional,可是它已经被解包了,我们在使用这个变量的时候就能够不加。
如今我们须要一个returnbutton,用来表示输入完了一个待操作的数,我们复制一个button,改变它的值。
凡是Unicode的字符都能够被我们使用,包含汉字和表情。
把这个button与vc相关联,它不须要传參数,所以參数类型能够是AnyObject的,方法取名enter
@IBAction func enter() { }
代码中该怎样写呢?点击了回车键,那么我们之后的输入将是一个新的数,所以须要把标志位改动:
@IBAction func enter() { userIsInTheMiddleOfTypingANumber = false }
它清除显示屏的功能实现了可是为什么回车会出如今label中呢。相信你已经猜到了由于我们之前复制button的关系。回车键依然关联在appendDigit方法中,我们仅仅须要右键点击button在弹出的菜单中点“X”取消这个关联就OK了:
如今我们创建一个数组来存储运算的值。你能够看到怎样定义以及初始化一个数组
var appendStack:Array<Double> = Array<Double>()由于Swift语言是强语言类型。所以我们能够不声明类型:
var appendStack = Array<Double>()
appendStack.append(display.text!)你会发现报错。由于appendStack是Double类型的,而display.text即便拆封之后依然是个String类型的,那么怎么办呢。
这里要引入一个新的东西,我们叫它计算属性:
var displayValue:Double { get{ } set{ } }
var displayValue:Double { get{ return NSNumberFormatter().numberFromString(display.text!)!.doubleValue } set{ display.text = "\(newValue)" userIsInTheMiddleOfTypingANumber = false } }
@IBAction func enter() { userIsInTheMiddleOfTypingANumber = false appendStack.append(displayValue) println("appendStack = \(appendStack)") }
按回车已经不再显示了,中控台信息:
如今我们来添加运算符button。它们依然公用一个action方法:
和回车一样。我们依然能够在特殊符号中找到数学运算符:
拖拽定义一个新方法operate,记得sender类型写UIButton,获取一下button的值:
@IBAction func operate(sender: UIButton) { let operation = sender.currentTitle! }
接下来展示swift中的操作流,老头说swift的操作流是很强大的,比其它语言强大太多,这一点我深有体会,我敲swift代码已经上万行了。控制流的确很好用和高效。并且很直观。
首先展示一下乘法运算:
@IBAction func operate(sender: UIButton) { let operation = sender.currentTitle! switch operation{ case "×": if appendStack.count >= 2 { displayValue = appendStack.removeLast() * appendStack.removeLast() enter() } // case "÷": // case "+": // case "?": default: break } }
switch operation{ case "×": if appendStack.count >= 2 { displayValue = appendStack.removeLast() * appendStack.removeLast() enter() } case "÷": if appendStack.count >= 2 { displayValue = appendStack.removeLast() * appendStack.removeLast() enter() } case "+": if appendStack.count >= 2 { displayValue = appendStack.removeLast() * appendStack.removeLast() enter() } case "?": if appendStack.count >= 2 { displayValue = appendStack.removeLast() * appendStack.removeLast() enter() } default: break }
func performOperation(operation:(Double,Double)-> Double) { if appendStack.count >= 2 { displayValue = operation(appendStack.removeLast() , appendStack.removeLast()) enter() } }
case "×": performOperation({ $0 * $1 })
还有更酷的!假设你有一个类似于performOperation的方法,那么在调用时方法中的最后一个參数能够写到括号外面,比方:
case "×": performOperation( ){$0 * $1}
performOperation {$0 * $1}完整的方法代码:
@IBAction func operate(sender: UIButton) { let operation = sender.currentTitle! switch operation{ case "×": performOperation {$0 * $1} case "÷": performOperation {$1 / $0} case "+": performOperation {$0 + $1} case "?": performOperation {$1 - $0} default: break } }
如今我们新增一排button,首先是平方根:
我们仅仅须要在控制流中添加一个case就好了,例如以下:
case "√": performOperation {sqrt($0)}
func performOperation(operation:Double-> Double) { if appendStack.count >= 1 { displayValue = operation(appendStack.removeLast() ) enter() } }
实现了。就是这么简单。
如今还对界面做一些优化,你会发如今竖屏状态屏幕浪费了太多的空间。而你不可能拖动每个button去设置相互之间的间距,这样太浪费时间。
首先左下角有点空。我们新增一个空button来占位。而且保证它不触发不论什么action
我们希望这些button能依据屏幕的大小自己主动稀疏布局,保持button群到各边框的距离相等。我们应用布局button。这排button在屏幕下方:
点开第一个button我们能够看到一些选项:
我们能够选择左对齐、上对齐、居中等等,可是这不是我们想要的选项,我们点开第二个button:
我们选中这两项标示全部button都有同样的宽和高:
如今来设置间距:
还记得我们对齐时候看到的蓝线么,这个8像素点得间距就是蓝线对齐的默认像素点间距,另外要保证红线是亮的状态而不是虚线状态,这样约束才干被加上。加上约束的界面:
哇偶。是不是眼花了。点开视图大纲,能够看到这里的小黄圈,假设它是红色的证明我们加入的约束有冲突的地方。
还记得我们上一话中介绍的么?这里的黄色标示有些约束和我们预想的不同,那么点开黄色小圆圈。随便点击一个条目。作例如以下设置:
记得勾选以下的Apply to all views in container。这样全部的警告都会被施以同样的操作。
如今警告没有了。看起来非常不错呦。执行一下看看:
在Iphone6上显得非常修长。
切换到横屏:
非常赞对不正确?
假设要清除约束使用第三个button:
上面部分是清除所选项的约束。以下部分是清除全部的约束。
可是实际我们的计算器是有问题的。由于我们的处理引擎这部分是独立的,这就牵涉到了MVC设计模式的问题,之后我们全部的代码都要满足MVC设计模式,如今来了解一下MVC:
MVC是一个基本机制,用于分类。左边的Model(模型层)包含我们的模型,在计算当中,计算是模型。
控制层控制视图怎样显示,而视图是控制要用到的模型,在view中用到的时相当常规的界面元素。我们用道路上的指示线来作比:
控制器和模型之间是虚线说明同意暂时跨越。可是过去之前你须要观察一下。控制器(C)必须全然掌握模型(M),由于控制器的职责就是展示模型给用户。所以控制器拥有全然的訪问权限,这是个单向的箭头
相同的控制器(C)也能够到达视图(V),由于控制器要向视图发送命令,由于控制器设计视图,我们在单向箭头上加了一行绿色小字,outlet。由于当我们在控制器中有一个属性指向视图,这个属性的名字就是Outlet。
那么模型(M)和视图(V)之间呢?答案是永远不能!
由于模型是全然独立于UI的。这也是为什么他们之间採用了双黄线隔开。
那么视图(V)向控制器(C)发送信息么?它们之间是一种盲通信。并非随意的通信,他们之间的建立通信的方式是控制器生成一个Target。然后视图使用action向控制器反馈信息。比方我们点击了一个button或者其它页面上的操作。页面并不知道控制器是一个什么样的控制器,它仅仅知道页面上产生了动作。并反馈给控制器,这是一种盲目的、简单的、结构化的通信方式。
那么有一些复杂的操作怎么办呢。比方should、will和did。我拖动屏幕这是一个did的动作,我按住了屏幕准备拖动它的时候这是一个will的动作,遇到这样复杂的动作时怎么办呢。视图的做法是它把这些问题抛给了它的代理,代理依然是控制器中的东西,这些代理来回答will、did、should怎么做这种问题。
另外一个非常重要的点是:视图不应该持有它所展示的数据。数据不能作为它的属性。比方你的iphone中有一万首歌。你不能期望它持有一万首歌展示给你看。第一,这样做非常低效,第二,这一万首歌应该在模型层。一些控制器来负责选择展示哪些歌曲。然后从模型中取到并在视图层中展示。
那么当我们滑动屏幕期望能获取很多其它歌曲的时候我们须要怎么做呢?这是第二种代理,我们叫它数据源DataSource。数据源并不去处理诸如will、should这种处理,他回答有多少歌曲并把数量返回给视图这种工作。此时视图为这一万首歌开辟空间。所以控制器(C)的作用就是给视图(V)解释并格式化这些模型(M)提供的数据。
那么问题又来了,模型能够和控制器通信么?显然不行。可是假设数据改变了怎样通知我们的控制器呢?它依然使用了这样的盲通信的方法。我们把模型想象成一个电台,它通过广播的方式告知别人自己的变化,IOS把这样的技术叫做Notification和Key Value Observing(KVO)。一旦控制器接收到了模型变化的消息,它会通过那个绿箭头向模型索取它的变化信息。
那么视图能接受模型的广播么?或许能够但不要这么做,这违背了MVC模式。
我们能够利用这些知识做些小应用,假设project非常复杂呢?我们须要多个MVC。多个MVC的叠加能够实现复杂功能。
【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记3 Xcode、Auto Layout及MVC
标签:条目 模式 计算 调用 targe 设计模式 net 接受 ddl
原文地址:http://www.cnblogs.com/jzssuanfa/p/6925931.html