MVC应用实战
iOS开发中设计模式是很重要的,其中,使用最多的就是MVC模式,今天就简单介绍一下在Swift中这么使用MVC模式来实现我们想要的功能;
模型-视图-控制器(Model-View-Controller,MVC)是Xerox PARC在20世纪80年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已广泛应用于用户交互应用程序中。在iOS开发中MVC的机制被使用的淋漓尽致,充分理解iOS的MVC模式,有助于我们程序的组织合理性。
1:模型对象
模型对象封装了应用程序的数据,并定义操控和处理该数据的逻辑和运算。例如,模型对象可能是表示游戏中的角色或地址簿中的联系人。用户在视图层中所进行的
创建或修改数据的操作,通过控制器对象传达出去,最终会创建或更新模型对象。模型对象更改时(例如通过网络连接接收到新数据),它通知控制器对象,控制器
对象更新相应的视图对象。
2:视图对象
视图对象是应用程序中用户可以看见的对象。视图对象知道如何将自己绘制出来,并可能对用户的操作作出响应。视图对象的主要目的,就是显示来自应用程序模型对象的数据,并使该数据可被编辑。尽管如此,在 MVC 应用程序中,视图对象通常与模型对象分离。
在iOS应用程序开发中,所有的控件、窗口等都继承自 UIView,对应MVC中的V。UIView及其子类主要负责UI的实现,而UIView所产生的事件都可以采用委托的方式,交给UIViewController实现。
3:控制器对象
在应用程序的一个或多个视图对象和一个或多个模型对象之间,控制器对象充当媒介。控制器对象因此是同步管道程序,通过它,视图对象了解模型对象的更改,反之亦然。控制器对象还可以为应用程序执行设置和协调任务,并管理其他对象的生命周期。
控制器对象解释在视图对象中进行的用户操作,并将新的或更改过的数据传达给模型对象。模型对象更改时,一个控制器对象会将新的模型数据传达给视图对象,以便视图对象可以显示它。
对于不同的UIView,有相应的UIViewController,对应MVC中的C。例如在iOS上常用的UITableView,它所对应的Controller就是UITableViewController。
- Model和View永远不能相互通信,只能通过Controller传递。
- Controller可以直接与Model对话(读写调用Model),Model通过Notification和KVO机制与Controller间接通信。
- Controller
可以直接与View对话,通过outlet,直接操作View,outlet直接对应到View中的控件,View通过action向
Controller报告事件的发生(如用户Touch我了)。Controller是View的直接数据源(数据很可能是Controller从
Model中取得并经过加工了)。Controller是View的代理(delegate),以同步View与Controller。
import UIKit class AppsModel: NSObject { //定义模型的三个属性 var imageName:String! //图片名称 var appName:String! //应用名称 var appDescription:String! //应用描述 //自定义初始化方法 init(imageName image_Name:String , app_Name:String , app_Description:String) { self.imageName=image_Name self.appName=app_Name self.appDescription=app_Description } // MARK: - NSCoding func encodeWithCoder(_encoder: NSCoder) { _encoder.encodeObject(self.imageName, forKey: "M_imageName") _encoder.encodeObject(self.appName, forKey: "M_appName") _encoder.encodeObject(self.appDescription, forKey: "M_appDescription") } init(coder decoder: NSCoder) { // imageName = decoder.decodeObjectForKey("M_imageName") as String // appName = decoder.decodeObjectForKey("M_appName") as String // appDescription = decoder.decodeObjectForKey("M_appDescription") as String //2015年5月2号修改 imageName = decoder.decodeObjectForKey("M_imageName") as! String appName = decoder.decodeObjectForKey("M_appName") as! String appDescription = decoder.decodeObjectForKey("M_appDescription") as! String } }
import UIKit class MyTableViewCell: UITableViewCell { var iconImageView:UIImageView! //图片 var appNameLabel:UILabel! //标题 var decLabel:UILabel! //描述 //赋值方法 - 显示cell内容方法 func showAppInfoWithModel(model:AppsModel) { //获取model中得图片 iconImageView.image = UIImage(named: model.imageName) //获取model中app名称 appNameLabel.text = model.appName //获取model中app描述 decLabel.text = model.appDescription } override init(style: UITableViewCellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) //创建iconImageView iconImageView = UIImageView(frame: CGRectMake(, , , )) self.addSubview(iconImageView) //创建appNameLabel appNameLabel = UILabel(frame: CGRectMake(, , , )) appNameLabel.font = UIFont.systemFontOfSize() self.addSubview(appNameLabel) //创建decLabel decLabel = UILabel(frame: CGRectMake(, , , )) decLabel.font = UIFont.systemFontOfSize() decLabel.numberOfLines = decLabel.textColor = UIColor.lightGrayColor() self.addSubview(decLabel) } required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func setSelected(selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } }
import UIKit class UITableViewControllerCustom: UIViewController, UITableViewDataSource, UITableViewDelegate { var titleString:String! @IBOutlet var titleLabel:UILabel! @IBOutlet var listTableView : UITableView! //定义数组 var items:[AppsModel]! //返回按钮事件 @IBAction func backButtonClick() { self.navigationController?.popViewControllerAnimated(true) } override func viewDidLoad() { super.viewDidLoad() titleLabel.text = titleString //定义三个模型对象 var model1:AppsModel = AppsModel(imageName: "appIcon1.png", app_Name: "Football Maze", app_Description: "足球迷宫,迷宫的新玩法,益智虚拟迷宫游戏。快来挑战你的空间想象,足球迷宫带你到一个不同的世界… 迷宫大家都在玩,你还在等什么。") var model2:AppsModel = AppsModel(imageName: "appIcon2.png", app_Name: "租房点评", app_Description: "租房被骗?现在开始,你来改变这一切!《租房点评》为你而备,租房无忧!") var model3:AppsModel = AppsModel(imageName: "appIcon3.png", app_Name: "iJump", app_Description: "摇动手机,松鼠就可以运动啦,越跳越高,注意会有虫子咬坏跳板哦,祝你玩得开心") var model4:AppsModel = AppsModel(imageName: "appIcon4.png", app_Name: "哪里逃", app_Description: "哪里逃 是一款躲避类游戏,拖动美女图片,躲避,追来的帅锅,帅锅人数越来越多,不要被追到哦。") //修改数组值 items = [model1,model2,model3,model4] //TabelView刷新 listTableView.reloadData() // Do any additional setup after loading the view. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. } */ //MARK: - UITableViewDelegate //tableView数据源:返回行数 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } //tableView 数据源:每一行高度 func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { } //tableView数据源:每一行内容 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { //Cell标示符,代表一系列 // OC:使用static, swift:使用let let cellIdentifier: String = "cellIdentifier" //通过cellIdentifier标示符取没有使用的Cell //有可能不存在,所以使用:optional var cell: MyTableViewCell? = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? MyTableViewCell //如果cell取到是空 if cell == nil { // no value //创建新的MyTableViewCell实例 //cell样式:UITableViewCellStyle.Default //cell标示符:cellIdentifier cell = MyTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: cellIdentifier) //设置字体 // cell!.textLabel.font = UIFont.systemFontOfSize(14) //2015年4月10号修改 cell!.textLabel?.font = UIFont.systemFontOfSize() //设置选中cell样式 cell!.selectionStyle = .Gray; //设置cell后面箭头样式 cell!.accessoryType = .DisclosureIndicator; } var cellModel:AppsModel = self.items[indexPath.row] //通过自定义方法给cell赋值 cell?.showAppInfoWithModel(cellModel) return cell!; } //tableView代理:点击一行 func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { //释放选中效果 tableView.deselectRowAtIndexPath(indexPath, animated: true) var urlString:String! = "https://itunes.apple.com/us/app/fruit-storm/id859713088?l=zh&ls=1&mt=8" { urlString = "https://itunes.apple.com/us/app/football-maze/id879720177?l=zh&ls=1&mt=8" } { urlString = "https://itunes.apple.com/us/app/zu-fang-dian-ping/id893902071?l=zh&ls=1&mt=8" } { urlString = "https://itunes.apple.com/us/app/ijump/id877475648?l=zh&ls=1&mt=8" } { urlString = "https://itunes.apple.com/us/app/na-li-tao/id880016522?l=zh&ls=1&mt=8" } UIApplication.sharedApplication().openURL(NSURL(string: urlString)!) } }