前五種方法點擊這兒:一篇文章學會頁面傳值的10種方法(上)
6、代理委托實現頁面之間的反向傳值
這一種方法就是運用協議實現傳值,這種方式也是在工程中常用的一種傳值方法。首先創建好ViewController和SubViewController,在ViewController中創建好一個展示信息的Label,在SubViewController中創建好一個TextFeild,我們實現在第二個界面點擊屏幕時,將TextFeild中的文字傳到第一個界面,然后讓背景顏色變色。
效果如下:
第一步:
首先我們要弄清楚ViewController和SubViewController誰是代理方,誰是委托方。委托方制訂協議,并且擁有一個代理,代理方準守協議,并且實現協議中的方法。因為是從SubViewController中向ViewController中傳遞信息,SubViewController需要讓代理完成傳值的動作,所以這里SubViewController便是委托方
在SubViewController中我們指定一個協議BackValueProtocol:
extension ViewController:BackValueProtocol {
func backValue(text: String, color: UIColor){}
}
因為我們要傳遞文字和顏色,所以協議里的方法帶有text:String 和color:UIColor 兩個參數
第二步:
制定好協議之后,我們還要給SubViewController添加一個代理屬性
var delegate: BackValueProtocol?
第三步:
然后就是給SubViewController指定一個代理人,當然,這里就是ViewController了
我們設置當點擊屏幕時跳轉到第二個界面,并且告訴第二個界面,ViewController就是他的代理方
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//獲取第二個界面
let svc = SubViewController()
self.presentViewController(svc, animated: true, completion: nil)
//MARK:告訴第二個界面ViewController就是他的代理
svc.delegate = self
}
第四步:
接下來就是在ViewController中實現協議中的方法了
extension ViewController:BackValueProtocol {
func backValue(text: String, color: UIColor) {
//讓label的文字顯示為傳過來的 文字
textLabel.text = text
//讓背景顏色改變為傳過來的顏色
self.view.backgroundColor = color
}
}
效果如下:
第五步
最后就是執行傳值操作了,我們設置在點擊第二個界面時傳值所以,在SubViewController的touchBegan里開始傳值
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//B頁面根部不需要考慮傳值的目標和方法具體是誰,直接去調用自己的屬性即可
//這種方式稱為回調,讓目標調用目標方法,參數為我傳入的TextField的值
let color = UIColor.redColor()
//MARK:讓自己的代理去執行傳值操作
self.delegate?.backValue(self.tf.text!, color: color)
self.dismissViewControllerAnimated(true, completion: nil)
}
到此為止,整個的反向傳值就完成了,整個步驟如下:
- 想好誰是委托方誰是代理方,委托方制定協議并擁有一個代理屬性
- 代理方遵守協議并實現協議中的方法
- 告訴委托方誰是代理
- 委托方告訴代理方去執行協議中的方法
7、使用TargetAction實現傳值
這種傳值方式和使用代理傳值有相似之處,大致的思想就是在有數據的界面進行傳值開始的指令,在接收數據的界面完成實質的傳值操作
效果如下:
首先,同樣ViewController和SubViewController,并分別設置好label和TextFeild
第一步
在SubViewController中我們設置兩個屬性:target和action
//設置兩個屬性接收傳值目標和方法
//用來去接收傳值的目標是任意目標
var target: AnyObject?
//用來去接收傳值的方法
var action: Selector?
第二步
在SubViewController中,當點擊屏幕時發送傳值指令
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//B頁面根部不需要考慮傳值的目標和方法具體是誰,直接去調用自己的屬性即可
//MARK:這種方式稱為回調,讓目標調用目標方法,參數為我傳入的TextField的值
self.target?.performSelector(self.action!, withObject: self.tf.text )
self.dismissViewController
第三步
在ViewController中我們要給SubViewController指定是指真正的target,真正的 action是什么。
同樣。我們設置當點擊屏幕時,將這些信息告訴給SubVIewController,顯然,target是ViewController,action則是我們指定的某個實現方法
那么,我們首先要設定一個用來回傳數據的方法
//定義一個用來去回傳數據的方法
func backValue(string:String) {
//通過傳進來的參數,給label賦值
textLabel.text = string
}
然后將target和action告訴SubViewController
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//獲取SubViewController
let svc = SubViewController()
//通過正向傳值,來告訴B頁面回調時需要用到的參數
svc.target = self
//MARK:將action告訴SubViewController
//NSSelectorFromString 方法是將一個字符串方法轉換成真正的方法名
svc.action = NSSelectorFromString("backValue:")
self.presentViewController(svc, animated: true, completion: nil)
}
到此為止,當點擊ViewController屏幕時,將taget和action告訴了第二個界面,在第二個界面點擊屏幕時,執行了target action命令,實現了backValue方法,完成了完整的傳值操作
8、使用系統單例去傳值
這個方法就厲害了我的哥!使用UIApplication這個單例類去完成數據的存儲,將需要傳輸的數據存儲到一個公共的數據源中,任何一個界面的任何地方都可以使用里面的資源
效果圖如下:
在工程中,我們對AppDelegate.swift文件都不陌生,這個文件配置好了window層,并且可以設置指定的很視圖控制器,在AppDelegate中我們知道它遵守了UIResponder和UIApplicationDelegate協議,而UIApplication便是一個系統提供的單例類,AppDelegate雖然不是單例類 ,但是共享的數據可以存放到這個類中
第一步
在AppDelegate聲明一個用來去和共享數據的數組,然后配置一個帶有的VC1,VC2和VC3的TabBarController做為根視圖控制器
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
//用來去共享數據的數組
var datas = [String]()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//給數組里加一個原始數據
datas.append("AD")
//配置window
window?.frame = UIScreen.mainScreen().bounds
window?.backgroundColor = UIColor.whiteColor()
let vc = ViewController()
vc.view.backgroundColor = UIColor.redColor()
let vc1 = ViewController1()
vc1.view.backgroundColor = UIColor.yellowColor()
let vc2 = ViewController2()
vc2.view.backgroundColor = UIColor.blueColor()
//設置標題
vc.title = "視圖1"
vc1.title = "視圖2"
vc2.title = "視圖3"
let tvc = UITabBarController()
tvc.viewControllers = [vc,vc1,vc2]
window?.rootViewController = tvc
window?.makeKeyAndVisible()
return true
}
第二步
當點擊屏幕時,添加數據到公共的數據源中并且讀取出來
因為在VC1,VC2,VC3中的任何一個界面都可以完成相同操作,在這里只拿一個做展示
- 首先我們獲取UIApplication的單例類
- 通過單例類獲取AppDelegate
- 通過AppDelegate操作共享的數組
代碼如下:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//獲取單例
let application = UIApplication.sharedApplication()
//通過這個單例獲取AppDelegate這個對象
let appDelegate = application.delegate as! AppDelegate
//通過這個AppDelegate來操作共享的datas數組
appDelegate.datas.append("VC-\(n + 1)")
print(appDelegate.datas)
}
當點擊屏幕時,我們可以看到控制臺中打印出來了我們設置的初始值“AD”和新加入的值“VC-2”,
同樣在VC2中我們使用同樣的放法獲取數據
import UIKit
class ViewController1: UIViewController {
var n = 1
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//UIApplication 是一個單例類
//AppDelegate并不是單例類,但是共享的數據放到了這個類里
//獲取單例
let application = UIApplication.sharedApplication()
//通過這個單例獲取AppDelegate這個對象
let appDelegate = application.delegate as! AppDelegate
//銅鼓這個APPDelegate來操作共享的datas數組
appDelegate.datas.append("VC1-\(n + 1)")
print(appDelegate.datas)
}
}
在控制臺中我們看到VC1傳入的數據和VC2自己傳入的數據,實現了頁面之間的傳值
9、使用自定義的單例實現頁面之間的傳值
本方法和第8中方法的實質原理是一樣的,共享一個公共的數據源數組,任何一個界面都可以通過單例找到這個數據源進而進行寫入和讀取的操作,只不過,這里我們使用了自己的單例。
首先將根視圖控制器設置為帶有三個界面的標簽控制器
1、自定義一個單例
在工程中我們繼承于NSObject新建一個SingleInstance單例類,在單例類中我們聲明一個公共的數據源,并且提供一個公開用來去獲取單例的方法
//創建一個單例類
class SingleInstance: NSObject {
//在單例類中,有一個用來共享數據的數組
var datas = [String]()
//創建一個靜態或者全局變量,保存當前單例實例值
private static let singleInstance = SingleInstance()
//私有化構造方法
private override init() {
//給數組加一個原始數據
datas.append("SI")
}
//提供一個公開的用來去獲取單例的方法
class func defaultSingleInstance() ->SingleInstance {
//返回初始化好的靜態變量值
return singleInstance
}
}
2、在VC1中寫入并讀取數據
當點擊屏幕時,將數據傳入公共數據源,并讀出
class ViewController1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK:-當點擊屏幕時寫入并讀取數據
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//獲取單例對象
let si = SingleInstance.defaultSingleInstance()
//給單例中的數組加一個數據
si.datas.append("VC1")
print(si.datas)
}
}
3、在VC2中寫入并讀取數據
class ViewController2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//獲取單例對象
let si = SingleInstance.defaultSingleInstance()
//給單例中的數組加一個數據
si.datas.append("VC2")
print(si.datas)
}
}
在VC2中同樣可以通過單例找到數據源,并且實現了頁面之間的傳值
10、通過通知中心NSNotificationCenter傳值
在這里我們實現用通知中心的方法實現從VC中向VC1和VC2中傳值
通知傳值類似于廣播和接收信號的過程,我們在AppDelegate中共享一個公共的數據源,在傳值的界面設置了一個公共的廣播站,并且獲取這個數據源,需要接收數據的頁面就相當于一個收音機,一旦收到廣播站的信號,便去執行相應的方法
1、在AppDelegate中我們共享一個數據源
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
//用來保存共享數據的數組
var datas = [Int]()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow()
window?.frame = UIScreen.mainScreen().bounds
window?.backgroundColor = UIColor.whiteColor()
let vc = ViewController()
vc.title = "VC"
let vc1 = ViewController1()
vc1.title = "VC1"
let vc2 = ViewController2()
vc2.title = "VC2"
let tvc = UITabBarController()
tvc.viewControllers = [vc,vc1,vc2]
window?.rootViewController = tvc
window?.makeKeyAndVisible()
return true
}
2、在VC1和VC2中擴展一個成為觀察者的方法,并設置接收到數據后需要執行的動作
擴展為觀察者的方法
extension ViewController1{
//成為觀察者的方法
func becomeObserver(){
//先去獲取通知中心的單例
let notificationCenter = NSNotificationCenter.defaultCenter()
//向通知中心去加入觀察者
notificationCenter.addObserver(self, selector: #selector(ViewController1.sum), name: "又有新數據啦!", object: nil)
}
}
接收到信號后執行的動作
//觀察者的響應方法
func sum(){
let datas = ((UIApplication.sharedApplication().delegate)as!AppDelegate).datas
var sum = 0
for i in datas{
sum += i
}
print("VC1計算求和得:\(sum)")
}
完整代碼如下:
class ViewController1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController1{
//成為觀察者的方法
func becomeObserver(){
//先去獲取通知中心的單例
let notificationCenter = NSNotificationCenter.defaultCenter()
//向通知中心去加入觀察者
notificationCenter.addObserver(self, selector: #selector(ViewController1.sum), name: "又有新數據啦!", object: nil)
}
//觀察者的響應方法
func sum(){
let datas = ((UIApplication.sharedApplication().delegate)as!AppDelegate).datas
var sum = 0
for i in datas{
sum += i
}
print("VC1計算求和得:\(sum)")
}
}
3、回到AppDelegate中將VC1和VC2注冊成為觀察者
//讓vc1,注冊成為觀察者
vc1.becomeObserver()
//讓vc2,注冊成為觀察者
vc2.becomeObserver()
4、當點擊VC屏幕時寫入數據并發送通知
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//在這里,向數據源中去增加數據,并發送通知
//隨機生成一個數字
let num = arc4random_uniform(100)
//通過UIApplication獲取單例類并獲取數據
((UIApplication.sharedApplication().delegate) as! AppDelegate).datas.append(Int(num))
//MARK-獲取通知中心
let nc = NSNotificationCenter.defaultCenter()
//發送通知
nc.postNotificationName("又有新數據啦!", object: nil)
}
在控制臺中我們就可以看見當點擊VC的時候,VC1和VC2都執行了響應的方法
效果如下:
到此,頁面傳值的10種方法全部介紹完了,文中有描述不當之處希望大家包涵和指正,有需要源代碼的伙伴們可以點擊這兒下載!