深入了解iOS中的VC切换的传值方式

由于上次面试中有提到相关内容,所以这次我专门深入研究了iOS的几种方式:
首先把所有的传值方式都列出来,如果有遗漏,请指正


首先列出iOS中使用的传值方式:

  1. init 传值(即在创建VC的时候就对响应的参数进行设置)
  2. property 传值(即属性赋值)
  3. Router 传值(这个在OC中被使用,因为作者没有写Swift版本,所以先开个坑,估计我会填坑)
  4. Delegate 传值(通过协议和代理传值)
  5. 闭包(block)传值 (通过swift中的闭包,类似于OC中的block传值)
  6. Notification 传值 (通过消息中心进行传值)
  7. KVO 传值 (通过观察者模式进行传值)
  8. AppDelegate 传值 通过Appdelegate进行传值
  9. NSUserDefault 传值 通过NSUserDefault传值
  10. 通过static进行全局变量的存储,这里就不再进行演示

基本上总结起来就是以上10种,接下来我会一种种介绍,同时会讲明传值方式中所遇到的坑。

本文中的所有代码已经放到github上,我会在文章最后加上github地址,所以在文章中只展示主要的代码。

一、init 传值


这个解释起来很简单,就是在VC对象init的时候,通过调用自定义的init函数,从而将所需要的参数传入对应的对象内。

实现代码如下:

//源VC
func jumpToNextVC() {
    let goal = TVGoalViewController.init(text: self.input.text!)
    navigationController?.pushViewController(goal, animated: true)
}
    
//目标VC
convenience init(text:String) {
    self.init(nibName:nil, bundle:nil)
    self.text.text = text
}

很明显,这种传值方式有着较高的耦合,对后期的维护有一定的影响,所以个人不建议。(虽然我在一开始写代码的时候很不要脸的这么干的~~)

二、property 传值(即属性赋值)


property传值就是通过在创建完VC后,对VC中的每个属性都单独复制。

//源VC:
func jumpToNextViewController() {
    let goal = TVGoal2ViewController()
        
    goal.showlabel.text = self.input.text
        
    self.navigationController?.pushViewController(goal, animated: true)
}

优缺点:虽然相较上一种方式来说,解了耦合,但是因为要在原VC中进行赋值,所以需要目标VC中的相应属性设置为Public,这对于代码的安全性有一定的影响。

三、Router 传值


这种方式在OC中有一定的用到,但是比较冷门,主要的方式通过一个单独的类来保存所有需要跳转的VC,同时将值保存在对应的params。从而通过类的函数对类进行转换,这个因为原作者只有OC版本,所以这里就不贴上OC代码,估计我会在接下来几天将这个函数移植到swift上。

优缺点:由于通过类来保存需要的内容,这样就解耦了,不过由于要引入第三方类,所以操作相对而言比较繁琐,而且需要学习第三方框架的函数,所以有一定的学习成本。

四、Delegate 传值


这种方式在iOS开发中是比较常见的几种方法之一,而且苹果官方也大量的使用这个方法,比如说AppDelegate。同时在UITextField,UIScrollView等控件中也经常性的使用这种方法传值。

苹果官方对Delegate有以下的解释:

Delegation is a simple and powerful pattern in which one object in a program 1 acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.

代码如下:

//原VC文件
protocol LoginDelegate {
    func changeText(name:String)
}

class TVLoginViewController: UIViewController {
    
    @IBOutlet weak var label: UITextField!
    @IBOutlet weak var loginButton: UIButton!
    var delegate:LoginDelegate?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.loginButton.addTarget(self, action: #selector(clickLogin), forControlEvents: UIControlEvents.TouchUpInside)
    }
    
    func clickLogin() {
        self.delegate?.changeText(self.label.text!)
        self.navigationController?.popViewControllerAnimated(true)
    }
}

//目标VC文件
class TVDelegateViewController: UIViewController,LoginDelegate{
    @IBOutlet weak var welcomeLabel: UILabel!
    @IBOutlet weak var login: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        login.addTarget(self, action: #selector(next), forControlEvents: UIControlEvents.TouchUpInside)
    }
    
    func changeText(name: String) {
        self.welcomeLabel.text = "欢迎回来:"+name
    }
    
    func next() {
        let goal = TVLoginViewController()
        goal.delegate = self
        self.navigationController?.pushViewController(goal, animated: true)
    }
}

优缺点:个人来说,我比较看好delegate传值,因为他结构明显,清晰的语法定义,减少维护成本,较强的代码可读性。 同时减少代码的耦合性,使事件监听和事件处理相分离。 不需要创建第三方来监听事件和传输数据。 并且一个控制器可以实现多个代理,满足自定义开发需求,可选必选有较大的灵活性。但是由于需要创建协议,再进行编码,可能代码量比较大。

五、闭包传值


闭包传值类似于oc中的block传值。而苹果官方对于Block的解释是这样的:

A block is an anonymous inline collection of code, and sometimes also called a “closure”.
Blocks are a powerful C-language feature that is part of Cocoa application development. They are similar to “closures” and “lambdas” you may find in scripting and programming languages such as Ruby, Python, and Lisp. Although the syntax and storage details of blocks might at first glance seem cryptic, you’ll find that it’s actually quite easy to incorporate blocks into your projects' code.

这说明闭包在实际使用中有着较大的使用面,不仅仅在oc中,在ruby,python,lisp中均有使用。同时由于实现它所需要的代码量相对于delegate更少,所以很多人都喜欢用(不过我不太喜欢)。
代码如下:

//原VC文件:
typealias returnClosure = (string:String)->Void
...
func login() {
    if closureValue != nil {
        closureValue!(string: self.input.text!)
    }
    self.navigationController?.popViewControllerAnimated(true)
}

//目标VC文件
func myClosure(string:String) -> Void {
    self.welcomeLabel.text = "欢迎:"+string
}

func jump() {
    let goal = TVLogin1ViewController()
    goal.closureValue = myClosure
    self.navigationController?.pushViewController(goal, animated: true)
}

六、Notification传值


Notification也是和上面的Delegate一样,在iOS开发中经常使用,他通过使用设计模式中的观察者模式,不过当其中一个内容进行变化的时候,通过NotificationCenter来接受内容变化,从而告诉需要告诉的人,原值已经发生改变了。

代码如下:

//原VC文件:
func logYouName() {
    let notific = NSNotification.init(name: "loginNameNotification", object: self, userInfo: ["name":name.text!])

    NSNotificationCenter.defaultCenter().postNotification(notific)

    self.navigationController?.popViewControllerAnimated(true)
}

//目标VC文件:
func next() {
    let goal = TVLogin2ViewController()
        
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(loginName), name: "loginNameNotification", object: goal)
        
    self.navigationController?.pushViewController(goal, animated: true)
}
    
func loginName(notification:NSNotification) {
    let dic = notification.userInfo

    self.welcomeButton.text = "欢迎:"+(String)(dic!["name"]!)
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

优缺点:Notificatoin使用了设计模式中的观察者模式,这种模式的好处就是:使用简单,代码精简。同时解决了同时向多个对象监听相应的问题,当需要调用修改的内容的时候也十分方便。

七、KVO 传值


这种传值和Notification的传值方法想法上面基本一致,都是通过设计模式中的观察者模式来进行实现的。不过区别是,一般来说Notification是作为一个第三者的单例来进行实现,而KVO是直接通过一个对象来观察另一个对象的值是否发生改变,观察者本身和被观察者不一定是要VC,只要是继承了NSObject即可实现该方法。

代码如下:

//原来VC文件
func login() {
    self.setValue(input.text, forKey: "username")
    self.navigationController?.popViewControllerAnimated(true)
}

//目标VC文件:
override func viewDidLoad() {
    super.viewDidLoad()
    
    loginButton.addTarget(self, action: #selector(login), forControlEvents: UIControlEvents.TouchUpInside)    

    goal.addObserver(self, forKeyPath: "username", options: [NSKeyValueObservingOptions.New,NSKeyValueObservingOptions.Old], context: nil)
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if keyPath == "username" {
        self.welcomeLabel.text = "欢迎"+(String)((change!)["new"]!)
    }
}

优缺点:优缺点和Notification大相近庭,不过在这里面使用的时候有个坑,当你在input输入相应的文字内容的时候,你需要在点击log之后,将文本中的内容进行保存,因为观察者不会对UITextField中的内容进行观察,所以很有可能发生问题。(个人不建议使用这个方法来用来观察需要手动输入的变量)

八、AppDelegate 传值


这个方法基于iOS App的实际创建方法,通过AppDelegate来唤起整个App,从而使得AppDelegate可以操控整个App,同时作为总控制,所有内部的类都能够通过UIApplication来获取Delegate,从而得到AppDelegate。所以可以通过他来进行值的传输。
代码如下:

//源VC文件
func next()  {
    let next = TVGoal3ViewController()

    let selfDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

    selfDelegate.storeString = self.input.text!

    self.navigationController?.pushViewController(next, animated: true)
}

//目标VC文件
override func viewDidLoad() {
    super.viewDidLoad()

    let app = UIApplication.sharedApplication()

    let selfDelegate = app.delegate as! AppDelegate

    showLabel.text = selfDelegate.storeString

    self.backButton.addTarget(self, action: #selector(goBack), forControlEvents: UIControlEvents.TouchUpInside)
}

优缺点:由于通过AppDelegate来实现,基本上内容都保存在AppDelegate中,所以调用起来方便,由于都保存在那里面,导致整个AppDelegate显得臃肿,不方便与以后的维护。

九、NSUserDefault 传值


苹果提供给开发者一个NSUserDefault这个系统变量,开发者可以通过这个来将内容保存到整个系统中,从而方便下一次的调用,这个和AppDelegate有异曲同工之妙。
代码如下:

//源文件NSUserDefaults.standardUserDefaults().setObject(self.input.text, forKey: "store")

//目标文件
let userdefault = NSUserDefaults.standardUserDefaults()
self.showLabel.text = (String)(userdefault.valueForKey("store")!)

优缺点:主要和AppDelegate一样,不过因为是系统级的变量,所以他所给予我们的内存空间是有限的,不能存放太大的资料。(记得存储完同步下,方便以后继续使用)

十、全局变量Static 传值


这个和一般语言中都一样,由于Static存在于全局存储区(静态存储区),只要程序不退出,那么就会一直保存起来。这样的一个好处就是你可以反复使用,但是由于不释放,所以如果量一大,容易发生内存不足~~所以不建议使用。

总结:以上就是所有10种iOS中的常见传值方式,他们各有各的优点,缺点,所以具体到底如何使用,还是需要开发者自己甄别。

最后贴上Github地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容