Objective-C頁面之間傳遞數(shù)據(jù)

stackoverflow上關(guān)于Objective-C關(guān)注度比較高的問題系列
鏈接

頁面之間傳遞數(shù)據(jù)

原文鏈接《Passing Data between View Controllers》
本文Github鏈接台腥,含代碼

關(guān)鍵詞

Passing Data between View Controllers
Delegate
Block
NSUserDefaults
Singleton
NSNotification

1.向下一個頁面?zhèn)鬟f數(shù)據(jù)

Passing Data Forward

從頁面A通過navitagion push進(jìn)入頁面B颅崩,此時需要傳遞數(shù)據(jù)(這個數(shù)據(jù)可以是object或者value)給頁面B,可以用下面這個方法话侧。

有兩個ViewController:ViewControllerAViewControllerB,需用從ViewControllerA傳遞一個字符串ViewControllerB.

  1. ViewControllerB中添加一個NSString類型的property title
@property (nonatomic, copy) NSString *title;

  1. ViewControllerA 中你需要導(dǎo)入ViewControllerB
#import "ViewControllerB.h"

然后在你需要pushViewControllerB之前給ViewControllerBpropetytitle賦值

ViewControllerB *viewControllerB = [[ViewControllerB alloc] init];
viewControllerB.title = @"The second View";
[self.navigationController pushViewController:viewControllerB animated:YES];

2.通過Segues進(jìn)入下個頁面的傳遞數(shù)據(jù)

Passing Data Forward using Segues

如果你使用了Storyboards栅炒,那么很大可能會用到segue來push頁面掂摔。這里的數(shù)據(jù)傳遞和上面中的數(shù)據(jù)傳遞類似,在push頁面之前下面這個方法會被調(diào)用

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

所以從ViewControllerA傳遞一個字符串ViewControllerB的步驟應(yīng)如下:

  1. ViewControllerB中添加一個NSString類型的property title
@property (nonatomic, copy) NSString *title;

  1. ViewControllerA 中你需要導(dǎo)入ViewControllerB
#import "ViewControllerB.h"
  1. 在Storyboard中創(chuàng)建一個從ViewControllerAViewControllerB的segue赢赊,并且給這個segue一個identifier乙漓,例如"showDetailSegue"

  2. ViewControllerA添加-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender方法,此方法會在任何使用segue進(jìn)行轉(zhuǎn)場時被調(diào)用(響應(yīng))释移。其中segue就是storyBoard轉(zhuǎn)場控制對象叭披,在參數(shù)segue中能夠獲取所要跳轉(zhuǎn)的試圖控制器,destinationViewController(目標(biāo)vc)玩讳,sourceViewController(源視圖vc)涩蜘。

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
    if([segue.identifier isEqualToString:@"showDetailSegue"]){
        ViewControllerB *viewControllerB = (ViewControllerB *)segue.destinationViewController;        
        viewControllerB.title = @"The second View";
    }
}

如果你的ViewControllerB是嵌入在一個NavigationController中那么需要使用下面這個方法來獲取ViewControllerB


-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
    if([segue.identifier isEqualToString:@"showDetailSegue"]){
        UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
        ViewControllerB * viewControllerB = (ViewControllerB *)navController.topViewController;
        viewControllerB.title = @"The second View";
    }
}

3.向上一個頁面?zhèn)鬟f數(shù)據(jù)

Passing Data Back

ViewControllerBViewControllerA回傳數(shù)據(jù),你可以使用Protocol和delegate 或者是 Block熏纯。后者可以作為一種低耦合的回調(diào)機(jī)制

Protocol and Delegate 方式

我們將使ViewControllerAViewControllerB的一個delegate(代理)同诫。這樣可以允許ViewControllerB發(fā)送一個message回傳給ViewControllerB,從而實現(xiàn)回傳數(shù)據(jù)樟澜。

要想使ViewControllerAViewControllerB的一個delegate误窖,ViewControllerA必須(conform)遵從ViewControllerB的protocol(協(xié)議)叮盘。此協(xié)議將告訴ViewControllerA哪些方法是必須要實現(xiàn)的。

  1. ViewControllerB中霹俺,在#import@interface之間你需要具體說明你的協(xié)議柔吼,代碼如下:

@class ViewControllerB;

@protocol ViewControllerBDelegate <NSObject>

- (void)viewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)content;

@end

  1. 接下來還是在ViewControllerB中,你需要給ViewContollerB添加一個delegate屬性丙唧,然后在.msynthesize
@property (nonatomic, weak) id<ViewControllerBDelegate> delegate;

  1. ViewControllerB中當(dāng)我們需要傳遞數(shù)據(jù)給ViewControllerA時愈魏,調(diào)用delegate的方法。通常在點擊button或者頁面pop的時候想际。

- (IBAction)backButtonClicked:(id)sender {
    NSString *content = @"Pass this value back to ViewControllerA";
    if ([self.delegate respondsToSelector:@selector(viewController:didFinishEnteringItem:)]) {
        [self.delegate viewController:self didFinishEnteringItem:content];
    }
}

  1. 以上ViewControllerB部分就完成了培漏,接下來在ViewControllerA中,導(dǎo)入ViewControllerB.h并且遵從它的協(xié)議沼琉。
#import "ViewControllerB.h"

@interface ViewControllerA ()<ViewControllerBDelegate>

@end

  1. ViewControllerA中實現(xiàn)ViewControllerBDelegate的方法北苟。
#pragma mark - ViewControllerBDelegate

- (void)viewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)content {
    NSLog(@"This was returned from ViewControllerB %@", content);
}

  1. 在push進(jìn)入ViewControllerB之前,你需要告訴ViewControllerB打瘪,它的delegateViewControllerA友鼻。
ViewControllerB *viewControllerB = [[ViewControllerB alloc] init];
viewControllerB.delegate = self
[self.navigationController pushViewController:viewControllerB animated:YES];

Block 方式

我們將在ViewControllerA中給ViewControllerB的block賦值,當(dāng)在ViewControllerB調(diào)用block時闺骚,ViewControllerA中block將響應(yīng)彩扔,并執(zhí)行block中的操作。

  1. ViewControllerB.h中添加一個block屬性
@property (nonatomic, copy) void (^block)(NSString *content);

  1. ViewControllerB.m中僻爽,當(dāng)我們需要傳遞數(shù)據(jù)給ViewControllerA時虫碉,調(diào)用block。通常在點擊button或者頁面pop的時候胸梆。
- (IBAction)backButtonClicked:(id)sender {
    NSString *content = @"Pass this value back to ViewControllerA";
    if (self.block) {
        self.block(content);
    }
}
  1. 在push進(jìn)入ViewControllerB之前敦捧,你需要給ViewControllerB的block賦值。特別注意碰镜,在此處block中兢卵,如果要使用self的話,需要使用weakSelf绪颖,這樣能夠防止循環(huán)引用秽荤。具體代碼如下:
ViewControllerB *viewControllerB = [[ViewControllerB alloc] init];
__weak __typeof__ (self)weakSelf = self;
viewControllerB.block = ^(NSString *content) {
    NSLog(@"This was returned from ViewControllerB %@", content);
    weakSelf.tipLabel.text = content;
};
[self.navigationController pushViewController:viewControllerB animated:YES];

4.跨頁面的數(shù)據(jù)傳遞

有時候傳遞數(shù)據(jù)的兩個頁面并非相互緊挨著,有時候數(shù)據(jù)需要傳遞給多個頁面柠横,那么上述的方法就不太好用了窃款,下面介紹三個跨頁面的數(shù)據(jù)傳遞: NSUserDefaults, Singleton, NSNotification。

NSUserDefaults

官方文檔

簡單來說NSUserDefaults是iOS系統(tǒng)提供的一個單例類(iOS提供了若干個單例類)牍氛,通過類方法standardUserDefaults可以獲取NSUserDefaults單例晨继,可以讀寫一下幾類數(shù)據(jù)。

NSData
NSString
NSNumber(BOOL, integer, float, double)
NSDate
NSArray
NSDictionary
NSURL

使用NSUserDefaults很簡單搬俊,在需要存儲的地方寫入數(shù)據(jù)紊扬,在需要使用的地方讀取數(shù)據(jù)曲饱。當(dāng)APP重新啟動,版本更新珠月,所存儲的數(shù)據(jù)都不會丟失;但是如果將APP卸載了楔敌,存儲在NSUserDefaults中的數(shù)據(jù)就會被一并刪除啤挎。

  1. 寫入
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:@"This string was in NSUserDefaults." forKey:@"kPassingDataBetweenViewControllers"];
[userDefaults synchronize];

  1. 讀取
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *content = [userDefaults objectForKey:@"kPassingDataBetweenViewControllers"];
self.userDefaultsLabel.text = content;

Singleton 單例

Singleton 會阻止其他對象實例化其自己的 Singleton 對象的副本,從而確保所有對象都訪問唯一實例卵凑。單例一旦被創(chuàng)建庆聘,在APP的整個生命周期內(nèi)都不會被銷毀(如果沒有手動銷毀的話)。所以單例可以用來存儲數(shù)據(jù)勺卢。

  1. 創(chuàng)建一個基于NSObject的文件伙判,PassingDataManager。在.h中添加需要存儲數(shù)據(jù)的屬性和一個類方法(用于向整個系統(tǒng)提供這個實例)黑忱。
@interface PassingDataManager : NSObject

@property (nonatomic, copy) NSString *content;

+ (instancetype)sharedManager;

@end
  1. .m
+ (instancetype)sharedManager {
    static PassingDataManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[PassingDataManager alloc] init];
    });
    return manager;
}

單例不能放在堆區(qū)(控制器A死了宴抚,里面創(chuàng)建的對象也死了),在任何需要的地方的都能拿到甫煞,因此放到靜態(tài)區(qū)(靜態(tài)區(qū)內(nèi)部的對象只要一創(chuàng)建菇曲,它的聲明周期就和app 一樣)

  1. 在需要給其賦值的地方,需要#import "PassingDataManager.h"
[PassingDataManager sharedManager].content = @"This message come from Singleton";
  1. 在需要取值的地方抚吠,需要#import "PassingDataManager.h"
self.singletonLabel.text = [PassingDataManager sharedManager].content;

NSNotification 通知

使用通知可以在一處發(fā)送常潮,多處接收。

  1. 在需要添加通知的地方(接收數(shù)據(jù)處)添加通知楷力,并且添加處理通知的方法
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleData:) name:@"kPassingDataBetweenViewControllersNotification" object:nil];

#pragma mark - Notification

- (void)handleData:(NSNotification *)notification {
    NSDictionary *info = notification.object;
    NSString *content = [info valueForKey:@"content"];
    self.title = content;
}

  1. 在發(fā)送通知的地方(發(fā)送數(shù)據(jù)處)
NSDictionary *info = @{@"content" : @"Notification"};
    [[NSNotificationCenter defaultCenter] postNotificationName:@"kPassingDataBetweenViewControllersNotification" object:info];

  1. 在需要添加通知的地方(接收數(shù)據(jù)處)喊式,當(dāng)對象銷毀前需要將該對象注冊的通知移除掉,否則萧朝,程序會crash岔留。
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

5.總結(jié)

頁面見傳遞數(shù)據(jù)的方法有如下幾點:

  1. 在alloc一個class之后初始化該class的屬性;
  2. Delegate剪勿;
  3. Block贸诚;
  4. NSUserDefaults,此處可以延伸為數(shù)據(jù)持久化:plist, SQLite3, CoreData厕吉。
  5. Singleton;
  6. NSNotification
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酱固,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子头朱,更是在濱河造成了極大的恐慌运悲,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件项钮,死亡現(xiàn)場離奇詭異班眯,居然都是意外死亡希停,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門署隘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宠能,“玉大人,你說我怎么就攤上這事磁餐∥コ纾” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵诊霹,是天一觀的道長羞延。 經(jīng)常有香客問我,道長脾还,這世上最難降的妖魔是什么伴箩? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮鄙漏,結(jié)果婚禮上嗤谚,老公的妹妹穿的比我還像新娘。我一直安慰自己怔蚌,他們只是感情好呵恢,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布婶芭。 她就那樣靜靜地躺著趟大,像睡著了一般明棍。 火紅的嫁衣襯著肌膚如雪熏兄。 梳的紋絲不亂的頭發(fā)上坷备,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天敞掘,我揣著相機(jī)與錄音折柠,去河邊找鬼章办。 笑死芒炼,一個胖子當(dāng)著我的面吹牛瘫怜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播本刽,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼鲸湃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了子寓?” 一聲冷哼從身側(cè)響起暗挑,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斜友,沒想到半個月后炸裆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡鲜屏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年烹看,在試婚紗的時候發(fā)現(xiàn)自己被綠了国拇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡惯殊,死狀恐怖酱吝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情土思,我是刑警寧澤掉瞳,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站浪漠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏霎褐。R本人自食惡果不足惜址愿,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冻璃。 院中可真熱鬧响谓,春花似錦、人聲如沸省艳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跋炕。三九已至赖晶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辐烂,已是汗流浹背遏插。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留纠修,地道東北人胳嘲。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像扣草,于是被迫代替她去往敵國和親了牛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理辰妙,服務(wù)發(fā)現(xiàn)鹰祸,斷路器,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,125評論 29 470
  • 用到的組件 1密浑、通過CocoaPods安裝 2福荸、第三方類庫安裝 3、第三方服務(wù) 友盟社會化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 14,601評論 1 180
  • 1.自定義控件 a.繼承某個控件 b.重寫initWithFrame方法可以設(shè)置一些它的屬性 c.在layouts...
    圍繞的城閱讀 3,349評論 2 4
  • 聽說今夜大雨瓢潑 聽說今夜我做了一個你從未夢見過的夢 聽說今夜哀鴻遍野 聽說今夜你喜歡玫瑰與吉他 我告訴你 其實今...
    涼城未涼1983閱讀 309評論 0 7