@(iOS Study)[實(shí)戰(zhàn)技術(shù)]
- 作者: Liwx
- 郵箱: 1032282633@qq.com
目錄
- 04.實(shí)戰(zhàn)技術(shù) block深入研究,UICollectionView的使用
- 1.block的深入研究
- block基本使用
- block開發(fā)使用場景(保存代碼)
- block開發(fā)使用場景(傳值)
- block內(nèi)存管理(MRC)
- block內(nèi)存管理(ARC)
- block循環(huán)引用
- block循環(huán)引用(復(fù)雜)
- block變量傳遞
- block開發(fā)使用場景(參數(shù)使用)
- block開發(fā)中使用場景(返回值)
- 2.UICollectionView的使用
- UICollectionView注意點(diǎn)
1.block的深入研究
block的作用: 可以用來
保存一段代碼段
,也可以用來傳遞參數(shù)
.block如果存放代碼段,該代碼段并不會馬上執(zhí)行,需用手動調(diào)用.
- 快速生成block代碼
- 輸入'inlineBlock'快速生成block代碼
-block類型是對象
,不是普通數(shù)據(jù)類型
- 輸入'inlineBlock'快速生成block代碼
block基本使用
- block的格式
// block的完整格式
block返回類型(^block變量名)(block參數(shù)) = ^(block返回類型,一般情況都省略)(block參數(shù)>) {
// block代碼段
}
- block的聲明方式
// block聲明:返回值(^Block變量名)(block參數(shù)類型),參數(shù)變量名可以省略
void(^block)();
void(^block1)(int);
- block的定義方式
// block定義: 等號右邊 ^(參數(shù)類型 參數(shù)變量名){};
void(^block2)(int a) = ^(int a){
};
// block定義二: 等號右邊 ^返回值(參數(shù)類型 參數(shù)變量名){};,返回值(=號后面第一個int)可以省略,但是也有不省略
int(^block3)(int a) = ^int(int a){
return 2;
};
// block定義三: 當(dāng)沒有返回值,沒有參數(shù),可以省略
void(^block4)() = ^{
};
block開發(fā)使用場景(保存代碼)
- 模型中block類型屬性的使用
- 給模型添加一個block類型的成員屬性,用來存放代碼段.
- 參考代碼
// 聲明block類型的成員屬性
@interface CellItem : NSObject
// 聲明一個block類型的成員屬性
@property (nonatomic, strong) void(^block)();
@property (nonatomic, strong) NSString *title;
+ (instancetype)itemWithTitle:(NSString *)title;
@end
// 給block添加代碼段
CellItem *item = [CellItem itemWithTitle:@"打電話"];
item.block = ^{
NSLog(@"打電話");
};
// 執(zhí)行block,需判斷block是否為空,如果為空,調(diào)用時會導(dǎo)致程序奔潰
if (item.block) {
item.block();
}
block開發(fā)使用場景(傳值)
順傳:定義屬性
逆?zhèn)?代理,block
,block可以用來替代代理
-
block逆?zhèn)髦挡襟E(控制器B由控制器A Modal出來的, 控制器B逆?zhèn)髦到o控制器A)
- 1.在控制器B添加一個block屬性
// 控制器B @property (nonatomic, strong) void(^blockValue)(NSString *value);
- 2.在控制器A中給控制器B的block添加代碼段
// 控制器A // REMARKS: block傳值(逆?zhèn)? - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { ModalViewController *modalVc = [[ModalViewController alloc] init]; // 給modalVc的block屬性添加代碼段 modalVc.blockValue = ^(NSString *value){ NSLog(@"%@", value); }; [self presentViewController:modalVc animated:YES completion:nil]; }
- 3.在控制器B點(diǎn)擊時調(diào)用block
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // block逆?zhèn)? if (self.blockValue) { self.blockValue(@"123"); } [self dismissViewControllerAnimated:YES completion:nil]; }
- 4.控制器B調(diào)用block時,會將@"123"傳遞給控制器A中的
// 控制器B調(diào)用block會調(diào)用以下代碼段,并將value傳遞過來 modalVc.blockValue = ^(NSString *value){ NSLog(@"%@", value); };
block內(nèi)存管理(MRC)
-
內(nèi)存5個區(qū):堆,棧,方法區(qū),常量區(qū),全局區(qū)
- 堆:手動管理內(nèi)存
- 棧:自動管理,代碼塊一過,就會自動釋放.
-
在MRC中的存儲
- 如果block
沒有訪問外部的局部變量
或者訪問被static修飾局部變量
,block默認(rèn)存放在全局區(qū)
. - 如果block訪問外部的局部變量,block存放在"棧"里面
// REMARKS: 測試block訪問外部局部變量,block的存儲 - (void)test2 { // 1.驗(yàn)證block的存儲區(qū)域 int a = 10; void(^block)() = ^{ NSLog(@"%d", a); }; self.block = block; // ARC打印結(jié)果: <__NSMallocBlock__: 0x7fc433d0fab0> (block存儲在堆區(qū)) // MRC打印結(jié)果: <__NSStackBlock__: 0x7fff51e24a18> (block存儲在棧區(qū)) NSLog(@"%@", block); }
// REMARKS: 驗(yàn)證block的方法static修飾的局部變量,block的存儲 - (void)test1 { // 1.驗(yàn)證block的存儲區(qū)域 static int a = 10; void(^block)() = ^{ NSLog(@"%d", a); }; // ARC和MRC打印結(jié)果一樣: <__NSGlobalBlock__: 0x10e1d9090> NSLog(@"%@", block); }
- 如果block
-
MRC使用block的注意點(diǎn)
- MRC:
不能使用retain聲明block,block依然放在棧里面,會自動銷毀
.如果用retain聲明的屬性引用block,則程序奔潰. - MRC:
使用copy聲明block,才會放在堆里面
- MRC:
MRC開發(fā)習(xí)慣:訪問屬性或者設(shè)置屬性,
MRC必須使用點(diǎn)語法
,不要使用下劃線
.因?yàn)?code>點(diǎn)語法會調(diào)用get方法,get方法會做引用計(jì)數(shù)器+1操作.而用下劃線沒有對引用計(jì)數(shù)器+1.MRC:沒有strong,和weak
, 只有assign, retain, copy-
區(qū)分MRC代碼:
- 1.看能否調(diào)用release retain retainCount
- 2.ARC不能調(diào)用[super dealloc]
block內(nèi)存管理(ARC)
ARC環(huán)境block的存儲區(qū)
如果block訪問外部的局部變量,block存放在"堆"里面-
block原則
- 如果block沒有訪問外部的局部變量或者局部變量被static修飾,block默認(rèn)存放在"全局區(qū)"
- ARC:使用
strong聲明block
,不要使用weak.
ARC管理原則:默認(rèn)一個局部變量對象,都是強(qiáng)指針,存放堆里面
block循環(huán)引用
block會對外部所有
強(qiáng)指針對象給強(qiáng)引用
,block不會對外部弱指針對象給強(qiáng)引用
.
-
block代碼段內(nèi)部使用self
- 正確用法: 使用__weak typeof(self) weakSelf = self;將self轉(zhuǎn)換成弱指針.對象能正常被銷毀
// 使用__weak typeof(self) weakSelf = self;將self轉(zhuǎn)換成弱指針. __weak typeof(self) weakSelf = self; _block = ^{ NSLog(@"%@", weakSelf); };
- 錯誤用法: 直接在block內(nèi)部使用self,造成循環(huán)引用,對象不會被銷毀.
_block = ^{ NSLog(@"%@", self); };
block循環(huán)引用(復(fù)雜)
-
block在多線程中的應(yīng)用
- block內(nèi)部執(zhí)行延遲操作或者異步任務(wù)需要在block內(nèi)部對weakSelf做一次__strong的引用,讓對象延遲釋放,以確保在執(zhí)行延遲操作或異步任務(wù)時,對象還沒被釋放.
- 以下block內(nèi)部執(zhí)行延遲操作,對象會延遲2秒后才釋放.
- (void)blockTest { // SINGLE: block內(nèi)部執(zhí)行延遲操作或者異步任務(wù)需要在block內(nèi)部對weakSelf做一次__strong的引用 __weak typeof(self) weakSelf = self; _block = ^{ // 需要在block內(nèi)部對weakSelf做一次__strong的引用,必須用__strong強(qiáng)引用weakSelf,這樣才能延遲釋放self對象,否則會出現(xiàn)延遲打印結(jié)果為null,在執(zhí)行延遲任務(wù)前,對象已經(jīng)被釋放了. __strong typeof(weakSelf) strongSelf = weakSelf; // 執(zhí)行延遲操作或異步任務(wù), dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"%@", strongSelf); }); }; // 執(zhí)行block _block(); }
block變量傳遞
- block訪問
外部局部變量沒有被任何關(guān)鍵字修飾,都是值傳遞
.值傳遞表示block中的value不會隨外部的改變而改變
.
- (void)test
{
// block訪問外部局部變量沒有被任何關(guān)鍵字修飾,都是值傳遞.值傳遞表示外部的value值改變不會影響block內(nèi)部的值.
int value = 10;
void(^block)() = ^{
NSLog(@"%d", value);
};
value = 20;
block();
// 打印結(jié)果: 10
}
- block訪問
外部變量是全局變量
或者被__block,static修飾
,都是指針傳遞
,block中的value會隨外部的改變而變
.
- (void)test1
{
// block訪問外部變量是全局變量或者被__block,static修飾,都是指針傳遞,block中的value會隨外部的改變而改變.
static int value = 10;
void(^block)() = ^{
NSLog(@"%d", value);
};
value = 20;
block();
// 打印結(jié)果: 20
}
block開發(fā)使用場景(參數(shù)使用)
- block作為方法參數(shù)使用
// block當(dāng)參數(shù)使用 caculatorBlock帶有一個參數(shù)result,并且返回值為int類型
- (void)caculator:(int(^)(int result))caculatorBlock;
block開發(fā)中使用場景(返回值)
鏈?zhǔn)骄幊趟枷?把方法調(diào)用通過點(diǎn)語法鏈接,可讀性非常好 (Masonry框架使用)
鏈?zhǔn)骄幊趟枷氲暮唵问褂?
block當(dāng)返回值
- (void)test1
{
// self.add()相當(dāng)于調(diào)用 add的get方法,get方法返回值是block類型的,再用返回值調(diào)用
// void(^block)() = self.add;
// block();
self.add();
}
- (void(^)())add
{
return ^{
NSLog(@"add");
};
}
-
使用block當(dāng)做返回值, 實(shí)現(xiàn)manager.add(10).add(5)鏈?zhǔn)骄幊?/p>
- 1.先分析
manager.minus(3)
操作,相當(dāng)于先調(diào)用get方法
,返回block類型的值,再通過返回值調(diào)用block
.
// manager.minus(3)相當(dāng)于執(zhí)行以下兩個操作 // void(^block)(int) = manager.minus; // block(3);
- 2.由以上可推出manager的方法聲明
- (void(^block)(int))minus; // 實(shí)現(xiàn)- (void(^block)(int))minus方法 - (void(^block)(int))minus { return ^(int value){ _result -= value; }; }
- 3.分析
manager.minus(3).minus(10)
,如果想再調(diào)用.minus(10)執(zhí)行操作,manager.minus(3)返回值必須是CalculatorManager類型對象
,由此可以分析出,block的返回值不是void,而是CalculatorManager類型
.
- (CalculatorManager *(^)(int)) minus; // 實(shí)現(xiàn)- (CalculatorManager *(^)(int)) minus方法 - (CalculatorManager *(^)(int)) minus { return ^(int value){ _result -= value; // 下面的return表示block的返回值,返回當(dāng)前對象 return self; }; }
- 4.以上操作完成,外部就能用manager.minus(3).minus(10)鏈?zhǔn)骄幊?
- 1.先分析
2.UICollectionView的使用
UICollectionView注意點(diǎn)
- UICollectionView注意點(diǎn):
- 1.
初始化必須要傳入布局
,(流水布局:九宮格布局) - 2.
UICollectionViewCell必須要注冊
- 3.
必須自定義cell
- 1.