傳值需求
- 將用戶信息 userInfo 作為傳值對象進行傳遞。
場景一 主頁傳值到詳情頁
屬性傳值
- 屬性傳值一般用于從主頁傳值到詳情頁。
- 傳值步驟:
steps 1:在DetailViewController.h文件中將需要獲取的值聲明成屬性。
#import <UIKit/UIKit.h>
@interface DetailViewController : UIViewController
@property (nonatomic, strong)NSString *userInfo; /**< 用戶信息 */
@end
steps 2:在HomeViewController.m文件中導入頭文件“DetailViewController.h”,然后在界面跳轉邏輯處理方法中初始化DetailViewController,并通過點語法給屬性userInfo賦需要傳遞的值。
- (void)respondsToButton:(UIButton *)sender {
// 初始化詳情視圖控制器n
DetailViewController *detailVc = [[DetailViewController alloc] init];
// 屬性傳值:賦值
NSDictionary *userInfo = @{@"name":@"Charles", @"age":@(22)};
detailVc.userInfo = userInfo;
// 模態切換(界面跳轉)
[self presentViewController:detailVc animated:YES completion:nil];
}
steps 3:在DetailViewController.m文件viewDidLoad方法中獲取userName的值,此時獲取到的值就是從主頁傳過來的值。
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@", userInfo);
}
init傳值
- init方法傳值與屬性傳值類似,一般用于從主頁傳值到詳情頁。
steps 1:在DetailViewController.h文件中聲明init方法。
- (instancetype)initWithUserInfo:(NSDictionary *)userInfo; /**< init傳值方法聲明 */
steps 2:在HomeViewController.m文件中導入頭文件“DetailViewController.h”,然后在界面跳轉邏輯處理方法中通過initWithUserInfo:方法初始化DetailViewController并賦值。
- (void)respondsToButton:(UIButton *)sender {
NSDictionary *userInfo = @{@"name":@"Charles", @"age":@(22)};
// 初始化詳情視圖控制器
DetailViewController *detailVc = [[DetailViewController alloc] initWithUserInfo:userInfo];
// 模態切換(界面跳轉)
[self presentViewController:detailVc animated:YES completion:nil];
}
steps 3:在DetailViewController.m文件中重寫init方法,即實現initWithUserInfo:方法,在這個方法中獲取userName的值,此時獲取到的值就是從主頁傳過來的值。
- (instancetype)initWithUserInfo:(NSDictionary *)userInfo {
if (self = [super init]) {
NSLog(@"%@", userInfo);
}
return self;
}
場景二 詳情頁傳值到主頁
Block塊傳值
- block在傳值中主要用于回調,現模擬從詳情視圖控制器傳值到主頁視圖控制器。
steps 1:在 DetailViewController.h文件中聲明block類型、屬性以及block回調方法。
#import <UIKit/UIKit.h>
// 1 聲明block類型
typedef void(^CallBackBlock)(NSString *context);
@interface DetailViewController : UIViewController
// 2 聲明block屬性
@property (nonatomic, copy) CallBackBlock callBackBlock;
/ 3 聲明block傳值方法
- (void)getsUserInfoWithBlocks:(CallBackBlock)callBackBlock;
@end
steps 2:在 DetailViewController.m文件中,實現如下操作:
// 4 賦值屬性block
- (void)getsUserInfoWithBlocks:(CallBackBlock)callBackBlock {
self.callBackBlock = callBackBlock;
}
// 處理按鈕點擊
- (void)respondsToButtonClick:(UIButton *)sender {
// 5 傳值
if (self.callBack) {
NSDictionary *userInfo = @{@"name":@"Charles", @"age":@(22)};
self.callBackBlock(userInfo);
[self dismissViewControllerAnimated:YES completion:nil];
}
}
steps 3:在 ViewController.m文件實現如下操作:
- (void)respondsToButtonClick:(UIButton *)sender {
DetailViewController *detailVc = [[DetailViewController alloc] init];
// 6 調用block,取值
[detailVc getsUserInfoWithBlocks:^(NSDictionary *userInfo) {
NSLog(@"%@", userInfo);
}];
// 模態切換(界面跳轉)
[self presentViewController:detailVc animated:YES completion:nil];
}
- Tips:
1、為block取別名,可在參數列表中將需要傳遞的參數寫成形參;
2、設置block屬性注意使用copy關鍵字;
3、設置一個方法持有當前block;
4、在合適的地方進行調用類似于代理;
5、在創建該對象的地方進行block方面的調用;
協議傳值
- 協議傳值又稱代理傳值,可直接將需要傳遞的值從委托方傳送至代理人,協議傳值可用于從下一個視圖控制器傳值到上一個視圖控制器(詳情頁傳值到主頁),現假定主頁是詳情頁的代理。
steps 1:在DetailViewController.h文件中聲明協議,并且設置代理屬性。
#import <UIKit/UIKit.h>
// @class 意在告訴編譯器,“DetailViewController”為一個類。
@class DetailViewController;
// @protocol 聲明協議
// 協議命名規范:類名 + delegate
@protocol DetailViewControllerDelegate <NSObject>
// @optional:聲明可選協議方法
// 協議方法的聲明模仿蘋果官方聲明方式,將類實例以及傳遞信息一并暴露在參數中
@optional
- (void)detailViewController:(DetailViewController *)detailViewController goBackWithUserInfo:(NSDictionary *)userInfo;
@end
@interface DetailViewController : UIViewController
// 聲明代理屬性,注意關鍵字使用 weak || assign,可避免保留環
@property (nonatomic, weak) id <DetailViewControllerDelegate> delegate;
@end
steps 2:在DetailViewController.m文件處理返回按鈕方法中調用協議方法傳值。
- (void)respondsToButton:(UIButton *)sender {
// 首先判斷代理人是否存在并且是否遵守協議并且實現了協議方法
if (_delegate && [_delegate respondsToSelector:@selector(detailViewController:goBackWithUserInfo:)]) {
// 如果滿足判斷條件,則讓代理執行協議方法,此處讓代理人執行協議方法,在代理人那個控制器中的協議方法會被執行;
// 通常經協議傳值在此處調用方法時,直接給參數賦值即可,在代理人控制器實現的協議方法中,可直接獲取此處設置的值;
NSDictionary *userInfo = @{@"name":@"Charles", @"age":@(22)};
[_delegate detailViewController:self goBackWithUserInfo:userInfo];
}
}
steps 3:在HomeViewController.m文件處理界面跳轉按鈕方法中初始化詳情視圖控制器,設置詳情視圖控制器協議代理為self(主頁),并且遵守<DetailViewControllerDelegate>協議。
- (void)respondsToButton:(UIButton *)sender {
// 初始化詳情視圖控制器
DetailViewController *detailVc = [[DetailViewController alloc] init];
// 設置代理,并且遵守<DetailViewControllerDelegate>
detailVc.delegate = self;
// 模態切換(界面跳轉)
[self presentViewController:detailVc animated:YES completion:nil];
}
steps 4:在HomeViewController.m中實現<DetailViewControllerDelegate>協議方法,獲取值。
#pragma mark *** DetailViewControllerDelegate ***
// 實現協議方法,獲取值
- (void)detailViewController:(DetailViewController *)detailViewController goBackWithUserInfo:(NSDictionary *)userInfo {
NSLog(@"%@", userInfo);
}
場景三 多界面傳值
通知傳值
- 通知傳值適用于任意控制器(界面),不管兩個控制器之間是否有關聯,只需滿足一個條件,在傳值的時候必須保證通知已經被設定,即已添加通知(觀察者observer)?,F假設從詳情界面傳值到主界面,即從下一個界面傳值到上一個界面,具體實現方式如下。
steps 1:注冊通知:為保證在傳值時通知已經被設定,因此需要在HomeViewController.m文件中注冊通知。
#import "HomeViewController.h"
#import "DetailViewController.h"
@interface HomeViewController ()
@end
@implementation HomeViewController
- (instancetype)init {
self = [super init];
if (self) {
/**
* 注冊通知
*
* @param observer 觀察者對象
* @param selector 觸發方法,即當收到通知之后執行的方法
* @param name 通知代號,即通知標識,發送通知時的標識必須和注冊通知時的標識一致
* @param object 是否傳值,在注冊通知的時候無需值,因此此處可填nil
*
*/
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(respondsToNotification:) name:@"notification_name" object:nil];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark *** responds notification ***
// 處理通知,當接收到通知的時候該方法會自動調用
// 在此處獲取從發送通知的控制器傳過來的值
- (void)respondsToNotification:(NSNotification *)info {
}
steps 2:發送通知:在DetailViewController.m文件處理返回按鈕方法中,發送通知,傳值到主界面,發送通知時的標識必須與注冊通知時的標識一致。
- (void)respondsToButton:(UIButton *)sender {
// 發送通知:通知標識必須與注冊通知時的標識一致
// 將需要傳遞的信息以字典形式賦給 userInfo 參數
NSDictionary *userInfo = @{@"name":@"Charles", @"age":@(22)};
[[NSNotificationCenter defaultCenter] postNotificationName:@"notification_name" object:nil userInfo:userInfo];
}
steps 3:處理通知:在HomeViewController.m文件處理通知方法中,獲取值。
#pragma mark *** responds notification ***
// 處理通知,在此處獲取從發送通知的控制器傳過來的值
// 注意:info參數包含兩個屬性,可通過點語法訪問。
// 1、name:為對應通知的標識
// 2、userInfo:為傳遞的信息
- (void)respondsToNotification:(NSNotification *)info {
NSLog(@"%@", info.userInfo);
}
steps 4:移除通知:通知在界面被釋放的時候一定記得移除,否則可能會導致程序的奔潰。移除通知在注冊通知控制器中的[dealloc]方法中實現。
- (void)dealloc
{
// 移除通知
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- 注意
1、通知傳值的使用會貫穿如下4個步驟:注冊通知 -> 發送通知 -> 處理通知 -> 移除通知
2、通知必須先注冊再使用,通知必須在不需要的時候調用remove方法移除。
單例傳值
- 單例貫穿整個應用程序聲明周期,利用單例傳值適用于任何控制器,使用前提是在獲取值的時候必須保證單例屬性有值,否則獲取值為nil,此處模擬從主頁視圖控制器傳值到詳情視圖控制器。
steps 1:創建單例,繼承于NSObject,任意命名,必須符合規范。此處創建單例類名為Singleton。
steps 2:在Singleton.h中聲明傳值屬性,并且聲明單例類便利構造器。
@interface Singleton : NSObject
@property (nonatomic, strong) NSDictionary *userInfo; /**< 單例屬性 */
+ (instancetype)defaultSingleton; /**< 單例便利構造器 */
@end
steps 3:在Singleton.m文件中實現遍歷構造器方法。
#import "Singleton.h"
static Singleton *singleton = nil;
@implementation Singleton
+ (instancetype)defaultSingleton {
// GCD創建單例,效率更高,性能更好,消耗更低。
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[Singleton alloc] init];
});
return singleton;
}
@end
steps 4:在HomeViewController.m文件中獲取單例實例,并且賦值單例屬性,賦值位置可根據實際情況進行調整。
// 單例屬性賦值
- (void)viewDidLoad {
[super viewDidLoad];
// 獲取單例實例,首先需導入Singleton.h
Singleton *singleton = [Singleton defaultSingleton];
// 單例屬性賦值
NSDictionary *userInfo = @{@"name":@"Charles", @"age":@(22)};
singleton.userInfo = userInfo;
}
steps 5:在DetailViewController.m文件中獲取單例屬性,取值位置可根據實際情況進行調整。
// 獲取單例屬性
- (void)viewDidLoad {
[super viewDidLoad];
// 獲取單例實例,首先需導入Singleton.h
Singleton *singleton = [Singleton defaultSingleton];
// 獲取單例屬性值
NSLog(@"%@", singleton.userInfo);
}
NSUserDefaults傳值
- NSUserDefaults系統單例傳值和自定義單例傳值基本一致,首先需保證NSUserDefaults對應key中有值,此處模擬主頁視圖控制器傳值到詳情視圖控制器
steps 1:在HomeViewController.m中獲取NSUserDefaults實例,并且存值。
- (void)saveValueInUserDefaults {
// 獲取NSUserDefaults實例
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 存值
NSDictionary *userInfo = @{@"name":@"Charles", @"age":@(22)};
[defaults setObject:userInfo forKey:@"userInfo"];
// 同步數據
[defaults synchronize];
}
steps 2:在DetailViewController.m中獲取值
- (void)getValueInUserDefaults {
// 獲取NSUserDefaults實例
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 根據key獲取值
NSDictionary *userInfo = [defaults objectForKey:@"userInfo"];
NSLog(@"%@", userInfo);
}