村花的swift学习笔记2

2016/06/20 23:43
阅读数 31
今天接着上次的学习笔记往下写,主要是对mvc有个初步的了解,然后今天的代码主要是mvc里的m,即model,所以,我觉得这份笔记需要先看看mvc相关资料再来看,不然可能会有点一头雾水。我觉得可难了,毕竟我不从太聪明,我看了好多资料,把同一节公开课翻来覆去停停顿顿的看了好几遍才有点点感觉…… 就趁现在!我要把这份感觉记下来! 首先,要先import一个叫foundation的包,基本每个model都是要import这个包,然后给这个model类起个好听的名字比方说calculatorBrain(我是学老师起的……) import Foundation model需要一个东西来储存里面所有的数据,里面的数据有很多种类型,要分开储存才可以在controller问model要数据的时候才可以不会凌乱,这时候,就需要用到enum(枚举)用来分开这些凌乱的数据了。 [code lang="swift"] enum Op: CustomStringConvertible{ case Operand(Double) case UnaryOperand(String, Double -> Double) case BinaryOperand(String,(Double,Double) -> Double) var description:String{ get{ switch self{ case .Operand(let operand): return "\(operand)" case .UnaryOperand(let symbol, _): return symbol case .BinaryOperand(let symbol, _): return symbol } } } } [/code] 1.enum是基本类型,可以像class一样有实例,有函数,但是实例只能是计算类实例。 2.一般var数据类型里面都会有get方法和set方法,但是description是只读属性,所以只有get方法,没有set方法。 3.description的作用就是使op转化为一个string返回,由这个属性里的get方法实现。 4.使用自己作为switch的参数,目的是重复使用下面那个evaluate方法里的switch部分代码。 有了这个description属性还不够,还需要实现这个属性,所以要enum op后面implement一个printable,但是在swift2.0中,printable改成了CustomStringConvertale。这个不是继承,不是继承,不是继承,而是protocol,意思是要这个枚举自己实现这个protocol,而恰好这个protocol里面有个description属性可以返回一个string。 涌进来的数据分好之后,就需要一个用于储存数据的栈~ var opStack = [Op]() 有了栈就可以把数据压进栈了: [php]func pushOperand(operand:Double) -> Double?{ opStack.append(Op.Operand(operand)) return evaluate() } [/php] 当一个个数据传进来的时候,需要判断和了解一下在最新一个数据进来之前有没有别的数据,因为有可能进行的是一个长长的运算比方说3*(4+1),所以新建一个字典类型的实例变量来存储已知的运算,每次执行performOperation时会到knowsOps里去查找,当找到之后就把结果传入opStack里 字典类型有两种写法: 第一种: var knownOps = Dictionary() 第二种: var knownOps = [String:Op]() 处理好数据的分类和储存,就要开始动脑子计算了,controller和veiw可不管计算的,model就相当于这个设计里的脑子。因为计算的时候需要用到递归,所以我就弄个递归方法: [php]func evaluate(ops: [Op]) -> (results: Double?, remainingOps: [Op]){ if !ops.isEmpty{ var remainingOps = ops let op = remainingOps.removeLast(); switch op { case .Operand(let operand): return (operand, remainingOps) case .UnaryOperand(_,let operation): //开始递归 let operandEvaluation = evaluate(remainingOps) //if把let operand从optional double变成了double if let operand = operandEvaluation.results{ return(operation(operand),operandEvaluation.remainingOps) } case .BinaryOperand(_,let operation): //二次递归 let op1Evaluation = evaluate(remainingOps) if let operand1 = op1Evaluation.results{ let op2Evaluation = evaluate(op1Evaluation.remainingOps) if let operand2 = op2Evaluation.results{ return(operation(operand1,operand2),op2Evaluation.remainingOps) } } } } return (nil,ops) } //递归 func evaluate() -> Double?{ let (result, _) = evaluate(opStack) return result } [/php] 1.第一个递归的返回值很奇怪,没错,返回了一个像结构体一样的东西,在swift里叫tuple,tuple是一种mini数据结构,可以使函数返回多个值,语法简单,就是一对括号里面添加参数,参数之间用逗号隔开,参数名可写可不写。 2.因为递归的时候,想要一个不断变化的变量来储存仍未进行运算的数据,但是ops是不可变的,不可以通过直接改变ops来实现这个想法,所以这里有个老师提供的小 tips:ops是不可变的,但是现在需要一个可变的变量来储存ops,所以用一个var来对ops进行copy,就可以使用removeLast()了,任何变量前面默认都是let,可以创建一个var类型的copy来供本地使用。 3.这里用switch来关联变量取出枚举,这是一个没有default的switch,因为这个swift已经把所有可能的情况都列出来了,不需要default。 4.Operand前的小点是Op.Operand()的省略,swift会自己推测匹配,括号里的operand是个与枚举op里各种情况的关联。 5.处理unaryoperand时,因为不需要知道里面那个string,也就是不需要知道计算符号,只关心计算的函数,所以用下划线来忽略string。swift里“_”=忽略,这样就不用再往后使用这个结构的时候声明其他乱七八糟的变量。 6.如果let后面声明的是一个optional数据类型的变量,可以在let前面加个if就去掉optional了。 7.另一种调用可返回一个tuple值的函数的方法就是直接令一个tuple等于函数返回值,tuple里的参数名不一定要和所调用的函数返回的tuple里的参数名相同,如第二个evaluate函数所示。 上面递归算好了的结果,现在就需要一个东西把结果返回给controller,完成这一次与controller之间的“通话”了: 当CalculatorBrain里面有一定数量的运算的时候,这里就只需要输入运算符号 [php]func performOperation(symbol: String) -> Double?{ if let operation = knownOps[symbol]{ opStack.append(operation) } //将每次运算结果返回 return evaluate() } } [/php] 写到这里,这个计算机的model差不多就完成了,因为有了model,所以上节课写的veiwcontroller就需要改变一下,用通过controller与model“通话”的方法替代veiwcontroller的计算操作部分,分工明确一点。 controller和model通过brain来通话连结: [php]var brain = CalculatorBrain() @IBAction func operate(sender: UIButton) { if userIsInTheMiddleOfTypingANumber{ enter() } if let operation = sender.currentTitle{ if let result = brain.performOperation(operation){ displayValue = result }else{ displayValue = 0 } } } @IBAction func enter() { userIsInTheMiddleOfTypingANumber = false //每次把operand压进栈,都会通过brain里的evaluate()把运算结果赋值给displayValue if let result = brain.pushOperand(displayValue){ displayValue = result }else{ displayValue = 0 } } [/php] 1.else里可以试着返回一个错误信息,或者把displayValue清空;如果displayValue是一个optional,这里就可以返回一个错误信息,或者把displayValue清空,总之比直接设为0好啦。 今天就写到这里啦,等我下次文思泉涌的晚上,我再说说我目前对mvc的理解啦,文章里写的有什么不对的不妥的,欢迎斧正哟~ 昨天去发廊焗油,洗头的大姐姐说:“小妹妹,你年纪轻轻的脖子怎么那么劳损啊”,我默默的回了一句并且内心在流泪:“大姐,我是学软加工程的😭”,而且最近口腔溃疡两次,让超级无敌馋的我吃东西的时候充分体验到什么叫“痛并快乐着”了😭……
展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部