前言:
与Android相比较而言,iOS的视图传值、启动/返回、监听的方式显得似乎有些繁多。在此略微总结提及下,仅供参考。
视图传值:
有以下几种方式:
- 正向:直接访问被访问视图的属性
- 反向:使用闭包或协议
这里暂不提及KVO方式。
正向传值示例:
设现存一名为ViewController.swift的启动视图,内有一Button,单击该Button后将“test”传值到另一个名为SecondViewController.swift的视图内的一个Label。
ViewController.swift:
import UIKit
class ViewController: UIViewController {
@objc func launchView(){
var secondViewController = SecondViewController()
secondViewController.publicContent = "test"
present(secondViewController, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let butttonOne = UIButton(type: UIButton.ButtonType.system);
butttonOne.frame = CGRect(x: 200, y:400, width: 100, height: 30);
butttonOne.setTitle("Button", for: UIControl.State())
self.view.addSubview(butttonOne);
butttonOne.addTarget(self, action: #selector(launchView), for: UIControl.Event.touchUpInside)
}
}
SecondViewCtroller.swift:
import UIKit
class SecondViewController: UIViewController {
var label = UILabel()
var publicContent: String = ""
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
label = UILabel(frame: CGRect(x: 20, y: 20, width: 200, height:30));
label.text = publicContent;
label.textColor = UIColor.black;
label.font = UIFont.boldSystemFont(ofSize: 20);
self.view.addSubview(label);
}
}
这里提及下思路:在ViewController里面创建一个SecondViewController的对象示例,然后直接访问SecondViewController的一个属性变量。当要启动的时候,SecondViewController的Label的文本就被这个属性变量所赋予。这种方式类似于Swing和WinForm传值。
反向传值这里使用闭包,很简洁。设现存一名为ViewController.swift的主视图,内有一Button和Label,Button负责启动第二个名为SecondViewController.swift的视图,第二个视图内有一Button,可返回至第一个视图,并将"swift"传值给第一个视图的Label。
示例如下:
ViewController.swift:
import UIKit
class ViewController: UIViewController {
// Define a varible to receive a varible from SecondViewController().
var getData: String = ""
var label = UILabel()
var buttonOne = UIButton(type: UIButton.ButtonType.system)
@objc func launchView(){
var secondViewController = SecondViewController()
secondViewController.closure = {(getData: String) in
self.label.text = getData
}
present(secondViewController, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
label = UILabel(frame: CGRect(x: 120, y: 120, width: 200, height:30));
label.text = "";
label.textColor = UIColor.black;
label.font = UIFont.boldSystemFont(ofSize: 20);
self.view.addSubview(label);
buttonOne.frame = CGRect(x: 200, y:400, width: 100, height: 30);
buttonOne.setTitle("Button", for: UIControl.State())
self.view.addSubview(buttonOne);
buttonOne.addTarget(self, action: #selector(launchView), for: UIControl.Event.touchUpInside)
}
}
SecondViewController.swift:
import UIKit
class SecondViewController: UIViewController {
var closure: ((String) -> Void)?
var buttonBack = UIButton(type: UIButton.ButtonType.system)
@objc func backListener(){
self.closure!("swift")
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
buttonBack.frame = CGRect(x: 200, y:400, width: 100, height: 30);
buttonBack.setTitle("Back", for: UIControl.State())
buttonBack.addTarget(self, action: #selector(backListener), for: UIControl.Event.touchUpInside)
self.view.addSubview(buttonBack);
}
}
这里也简要地提及思路:主视图内有一属性变量用来接受从第二个视图传过来的文本。第二个视图先创建一个闭包,在返回至主视图的监听内调用该闭包并传值内容。在主视图内用于启动第二个视图的监听内先创建第二个视图的示例对象,调用闭包,并在闭包表达式内获取变量赋值给主视图的label属性。
启动/返回:
关于启动/返回的方式也不少,可以简略地分为以下几种:
present()
/dismiss()
pushViewController()
/popViewController()
/popToViewController()
- Segue
红色方式为代码式,Segue为连线式。
先来看第一种方式:
present(ViewController, animated: Bool, completion: nil)
说明:第一个参数为带启动的视图对象,第二个为是否要显示动画,第三个为闭包。
与之对应的是dismiss()
:
dismiss(animated: Bool, completion: nil)
说明:第一个参数为是否要显示动画,第二个为闭包。该语句执行后会返回至启动该视图的视图。
第二种方式系NavigationController专用,其它视图种类无法使用。单看 push与pop就可略知一二是与栈有关。
self.navigationController?.pushViewController(ViewController, animated: Bool)
说明:第一个参数为待入栈(将处于栈顶)的视图示例对象,第二个为是否要展示动画。
self.navigationController?.popViewController(animated: Bool)
说明:这里仅有一个参数为是否要展示动画,执行后将当前视图弹出视图栈(出栈)
func popToViewController(ViewController, animated: Bool) -> [UIViewController]?
说明:该语句会将指定位置的视图出栈,其它处于该视图上方的视图都会被出栈,并且将所有被出栈得视图以数组形式返回。
Segue依靠连线方式实现启动/返回,只需将如Button连接到被启动视图即可,返回亦是如此。需要指出的是,假设一个视图内有许多连线,那就要靠Identifier来区分。
示例如下:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue == "a" {
// Launch ViewController with "a"
}
if segue == "b" {
// Launch ViewController with "b"
}
if segue == "c" {
// Launch ViewController with "c"
}
}
监听:
这里也是分为纯代码和半代码式。
- IBAction
addTarget()
有关IBAction的介绍与理解有疑惑的可看这篇文章–IBOutlet与IBAction的理解
IBAction属于半代码式,示例如下:
@IBAction func buttonListener(_ sender: Any) {
}
说明:将某控件使用control键连线至ViewController中,便会出现该代码。关于监听的动作在弹出的窗口内可选择,种类很丰富。
纯代码就是addTarget()
了,示例如下:
addTarget(self, action: #selector(), for: UIControl.Event.touchUpInside)
说明:第一个为执行者,一般为self
即可,第二个为要执行的方法,第三个为触发的动作,这里为按下并抬起。