IOS开发之多重MVC以及手势
ios开发之多重mvc以及手势
继续学习ios开发,这一次学习的是多重mvc架构以及手势识别。
把之前的view接口化
首先需要把之前的faceit程序的可以改变的参数单独提取出来。
//changable parameters //1 means smile and -1 means sad. var smilefactor: cgfloat = 1 var eyeopen: bool = false var eyebrowtiltfactor: cgfloat = -1 var linecolor: uicolor = uicolor.black
如果想要在main.storyboard里面实时可以看到view里面的情况,只需要在类前面加入如下的一行代码。
同样的,可以使用以下的放下把这些参数放到interface里面。
这样子的话就可以在storyboard的侧面的边栏里面了。
但是这个时候会发现,如果在faceview里面直接改变变量的初始值,storyboard的图像并不会重新渲染。要改变这个,需要使用变量的didset属性,意思是如果变量在某种程度上更改了,那么就需要执行dieset括号内的内容。
var smilefactor: cgfloat = 1 { didset{setneedsdisplay()}}
model部分
接下来我们将会完成mvc中model的部分,我把它命名为facialexpressionmodel。这个时候问题来了,是使用class呢,还是使用struct呢?因为看到stanford的老师在这个demo里面使用了struct。后来查阅了相关的资料,发现了它们根本的区别在于:
struct传值,class传引用
结构(struct)是一种值类型。也就是说,结构实例是分配在线程堆栈上的,结构本身是包含有值的,而不是像类一样的引用类型,包含的是所指向堆当中的引用(指针)。也就是说,结构的生存周期与简单类型(int,double等)相同的。
你使用的是一个对class实例的引用。而你使用的不是对一个struct的引用。(而是直接使用它们)
当我们将class作为参数传给一个方法,我们传递的是一个引用。struct传递的是值而非引用。
紧接着会有一个让人非常困惑的问题,到底model写的内容是什么呢?其实目前来看,我们的这个小应用都只是在控制view,所以目前只需要用到view和viewcontroller,那么model只需要模拟把各种情况写出来就好了(计算机的是结果,因为要显示的不是情况)。
model返回的是view的各种情况类型,一般用enum。
关于enum有以下两点需要注意:
1. relative值的使用
可以如下方式定义relative值,然后如下方式使用。
//定义 enum barcode { case upca(int, int, int) case qrcode(string) } //使用 switch productbarcode { case .upca(let numbersystem, let identifier, let check): println("upc-a with value of \(numbersystem), \(identifier), \(check).") case .qrcode(let productcode): println("qr code with value of \(productcode).") }rawvalue的相关使用
作为相关值的替代,枚举成员可以被默认值(称为原始值)预先填充,其中这些原始值具有相同的类型。
enum asciicontrolcharacter: character { case tab = "\t" case linefeed = "\n" case carriagereturn = "\r" }
原始值可以是字符串,字符,或者任何整型值或浮点型值。每个原始值在它的枚举声明中必须是唯一的。当整型值被用于原始值,如果其他枚举成员没有值时,它们会自动递增。
enum planet: int { case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune } let possibleplanet = planet(rawvalue: 7) //这里就是possibleplanet就是uranus
关于这些类型的切换,有一个要处理的问题就是边界问题。比如如果我要从伤心、平静、开心三种状态之间切换,【更开心】这个操作有可能会向上跳一级,或者什么都不发生。以下的代码可以轻易的解决这个问题。
func moresmile() -> mouth{ return mouth(rawvalue: rawvalue + 1) ?? .smile } func moresad() -> mouth{ return mouth(rawvalue: rawvalue - 1) ?? .sad }
这里插播一个swift的命名规范。
其中类名、协议名、结构体、枚举等类型的命名规范通常是,大写字母作为开始,其余单词首字母大写,例如类名helloworldapp。
完成controller调控两大板块
我们已经知道了model里面是一个struct,所以我们需要一个变量来装载它(class类似的)。然后我们需要让他时刻更新view。方法和上面很类似,这里把关键函数updateui贴出来。
func updateui(){ switch facialexpression.eye{ case .open: faceview.eyeopen = true case .close: faceview.eyeopen = false default: break } switch facialexpression.mouth{ case .smile: faceview.smilefactor = 1.0 case .relax: faceview.smilefactor = 0.0 case .sad: faceview.smilefactor = -1.0 default: break } switch facialexpression.eyebrow{ case .happy: faceview.eyebrowtiltfactor = 1.0 case .relax: faceview.eyebrowtiltfactor = 0.0 case .sad: faceview.eyebrowtiltfactor = -1.0 default: break } }
手势
手势的基类是uigesturereconizer,但是这是一个抽象的概念,真正的类是各种手势的gesturereconizer( 比如pinch和swipe)。而且必须view才能使用它们。一般来说是controller添加到view。不过一些基本的gesture可能本事就在view上。当识别成功,会使用handler来传输信息,如果不涉及和model沟通,那么只需要在view中,否则需要在controller中设立。
接下来尝试使用swipegesturerecognizer来改变model的状况(请看下图对比改变model和只是改变view的区别)。
let happyreconizer = uiswipegesturerecognizer(target: self, action: #selector(faceviewcontroller.happier)) happyreconizer.direction = .down faceview.addgesturerecognizer(happyreconizer)
分别是创建reconizer、设置属性、以及添加进去view里面。
我们来看uigesturereconizer的基本格式(target:self/view, action: #selector(controller/view.函数名))。
所有的对应的处理函数func前面都要加入@objc。
@objc func happier(){ facialexpression.mouth = facialexpression.mouth.moresmile() }
同样的reconizer也可以通过在storyboard拖拽加入然后使用ctrl在controller中建立联系。
@ibaction func eyechange(_ recognizer: uitapgesturerecognizer) { if recognizer.state == .ended{ switch facialexpression.eye{ case .open: facialexpression.eye = .close case .close: facialexpression.eye = .open default: break } } }
vc">多重mvc
这里我们使用xcode提供给我们的mvc,常用的分别有以下三种。
第一种是tabbar。
第二种是split,常用在ipad。左边一般是master,右边叫做detail。potrait的时候一般master隐藏在左边,可以抽屉式抽取出来。
第三种是navigationcontrol。
需要知道的是,ios在处理多级菜单的时候,是使用stack来存的。每一个页面push进去,然后返回就是pop。这一切是通过一个更高一级的controller(比如navigationcontrol)来控制的。
在这个root controller,里面有一个变量(array)来记录旗下的所有mvc。var viewcontrollers: [uiviewcontroller]? {get set}
上一篇: IOS开发技巧--如何使用lookup table为图片添加滤镜
下一篇: 手机铃声是鸟叫声