第八章 界面通信
一、屬性傳值
1.屬性傳值:從視圖層級的前面傳到后面,必須獲取接收值的對象,并且在接收的類中聲明一個所傳值的類型,可以是字符串、數組、集合、字典等,將要傳遞的內容賦值給這個屬性,在后面的視圖中接受就可以了,步驟如下
第一步:SecondViewController* secondVC = [[SecondViewController alloc] init];
第二步:@property(nonatomic,strong) NSString* receiveString;
第三步:secondVC.receiveString = valueString;
第四步:mTextField.text = self.receiveString;
2.單例傳值:
1.創建一個類繼承于NSObject
2.聲明所傳值的屬性,可以是字符串、數組、集合、字典等
3.聲明一個便利構造器方法(類方法,加號方法),返回值可以是當前類的類型(Singleton)、id、instancetype,方法名一般為SharedSingleton。
4.實現類方法,方法體內
第一步:創建靜態的類對象,賦值為nil;賦值為nil的方法只會執行一次
static Singleton* singletan = nil;
第二步:判斷當前類對象是否被初始化
if(singletan == nil){
singletan = [[Singleton alloc] init];
}
第三步:返回singleton
return Singleton;
5.將要傳值的內容賦值給單例對象的屬性,然后再把值傳過去之后從單例中取出既可以了
二、協議傳值
協議傳值:本質上就是屬性傳值,是把當前類對象作為屬性傳到后面的視圖,然后后面的視圖再通過屬性傳值將要傳的內容傳過來,兩次屬性傳值,這里我們為了防止出現傳值多個界面時代碼的冗余,提高代碼的可擴展性(需要做別的事時只需要在協議里添加方法就可以了),使用協議傳值
1.在要傳內容的類中聲明協議,類型一般是類名后面加上delegate
2.聲明協議方法,帶參數(參數的類型就是要傳值的類型)
3.在類中聲明協議的代理方,注意內存管理的特性一定要用assign修飾
4.在按鈕事件中執行協議方法進行傳值
5.在接收值得類中遵循協議
6.在接受值的類中的按鈕跳轉事件的方法中指定代理對象
7.在接受值的類中實現代理方法
8.注意:在調用的時候判斷協議方法是否實現
if (self.delegate && [self.delegate respondsToSelector:@selector(passValue:)]){
[self.delegate passValue:self.mTextfield.text];
}
三、Block傳值
1.block的使用,一個特殊的函數
void(^block_1)(void) = ^(void){
};
1.方法解釋:void:返回值類型
(^block):方法名
(void):參數
void(^block)(void):方法的聲明
^(void){}; :方法的實現
2.四種類型:
無參無返回值:void(^block_1)(void) = ^(void){};
有參無返回值:void(^block_2)(NSString* name) = ^ (NSString* name){};
有參有返回值:NSString*(^block_3)(NSString* name) = ^ NSString*(NSString* name){ return name; };
無參有返回值的:NSString*(^block_4)(void) = ^NSString*(void){return @"無參有返回值的";};
3.注意:在實現的部分(等號的右邊)返回值可以省略不寫,如果沒有參數,在實現部分,參數部分也可以省略。
4.block的使用:
//實現一個方法,方法有三個參數,前兩個參數都是整型,第三個參數為block類型,并且在block中求出前兩個參數的和并在block中打印出來
1.方法的聲明
- (void)testBlockWithA:(int)a b:(int)b completion: (int(^)(int sum)) threeBlock{
第一種
threeBlock(a + b);
//調用普通的方法
[self sum:a + b];
};
第二種
- (void)sum:(int)s{
NSLog(@"s ==== %d",s);
}
block就相當于將方法的實現換了個方法
2.方法的調用
[self testBlockWithA:6 b:4 completion:^int(int sum) {
NSLog(@"a + b == %d",sum);
return sum;
}];
5.block的別名的聲明(重定義):
1.當block作為類型來使用的時候,我們為了與我們的語法習慣保持一致,需要為block類型起一個別名作為類型的名稱
2.typedef void(^Block)(NSString* name);
3.@property (nonatomic,copy) Block myBlock;
2.block的傳值:
1.Block起別名(后面VC.h):typedef void(^PassBlock)(NSString* title);
2.聲明Block屬性(后面VC.h):@property (nonatomic,copy) PassBlock passBlock;
3.調用block,進行傳值:self.passBlock(self.mTextfield.text);
判斷block是否實現,block的實現就相當于賦值操作,沒實現就相當于未賦值,那么此處就為空,不會進入if分支,如果實現了就相當于賦值了,就會進行if分支
if(self.passBlock){
self.passBlock(self.mTextfield.text);
}
4.實現block方法:
blockVC.passBlock = ^(NSString* title){
self.navigationItem.title = title;
};
3.關于block的問題:
1.block作為屬性要用copy修飾的原因:1.因為block有可能會持有需要我們釋放的資源,如果我們不管理他的內存,就可能會造成內存溢出;2.因為block有可能是在全局區、棧區、堆區,但是我們只能管理堆區的內存,所以我們需要將block copy到堆區,所以我們這里使用copy,不使用retain。
2.block的內存管理:Malloc:堆區; Global:全局
1.沒有局部變量的block,是在全局,不用管理內存
void(^block)(void) = ^{
};
2.帶有局部變量的block,__block的作用只是告訴編輯器該局部變量 不管在當前方法中有效,在該方法的block(匿名函數)中也有效,有效區域擴大;將block在堆區生成,以方便我們管理改block的內存
__block int a = 100;//局部變量
//block的本質上就是一個函數(方法),他相對于viewDidLoad方法來說就是另外一個方法
void(^block1)(void) = ^{
a = 1000;
};
3.在block中使用屬性
錯誤舉例:
在聲明block作為當前類的屬性后,又在block的方法體中通過點語法調用當前類的屬性
void(^block2)(void) = ^{
self.testString = @"kk";
};
結果:這樣使用會造成循環引用,block2作為self(當前類的一個屬性),而在block2 的方法體內又調用當前類中的屬性,造成block2 和 當前類相互持有,所以在系統管理內存的時候容易導致循環引用;
解決方法:
第一種;在block的方法體中調用當前類的屬性不使用點語法,而使用下劃線
第二種:告知編譯器或者系統self要在被它持有的block中使用,請不要糾結block中該self的內存情況。
MRC下:__block ViewController* vc = self;
ARC下:__weak ViewController* vc = self;
調用屬性的時候通過vc調用就行
4.關于協議中是否可以定義屬性:協議聲明出來的是方法,雖然看起來是屬性,其實只有getter、setter 這兩個方法,內部是沒有實例變量的,并且你不能去重定義它,只能在 getter、setter 里處理
http://blog.csdn.net/yuanchunzi/article/details/47104907
最后編輯于 :
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。