04.實(shí)戰(zhàn)技術(shù) block深入研究,UICollectionView的使用

@(iOS Study)[實(shí)戰(zhàn)技術(shù)]


目錄

  • 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ù)類型

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);
    }
    
  • MRC使用block的注意點(diǎn)

    • MRC:不能使用retain聲明block,block依然放在棧里面,會自動銷毀.如果用retain聲明的屬性引用block,則程序奔潰.
    • MRC:使用copy聲明block,才會放在堆里面
  • 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)骄幊?

2.UICollectionView的使用

UICollectionView注意點(diǎn)

  • UICollectionView注意點(diǎn):
    • 1.初始化必須要傳入布局,(流水布局:九宮格布局)
    • 2.UICollectionViewCell必須要注冊
    • 3.必須自定義cell
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撮躁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌璃吧,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異豺鼻,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)款慨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門儒飒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人檩奠,你說我怎么就攤上這事桩了。” “怎么了埠戳?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵井誉,是天一觀的道長。 經(jīng)常有香客問我整胃,道長颗圣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮在岂,結(jié)果婚禮上奔则,老公的妹妹穿的比我還像新娘。我一直安慰自己蔽午,他們只是感情好易茬,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著及老,像睡著了一般抽莱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上骄恶,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天食铐,我揣著相機(jī)與錄音,去河邊找鬼叠蝇。 笑死璃岳,一個胖子當(dāng)著我的面吹牛年缎,可吹牛的內(nèi)容都是我干的悔捶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼单芜,長吁一口氣:“原來是場噩夢啊……” “哼蜕该!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起洲鸠,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤堂淡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扒腕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绢淀,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年瘾腰,在試婚紗的時候發(fā)現(xiàn)自己被綠了皆的。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡蹋盆,死狀恐怖费薄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情栖雾,我是刑警寧澤楞抡,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站析藕,受9級特大地震影響召廷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一柱恤、第九天 我趴在偏房一處隱蔽的房頂上張望数初。 院中可真熱鬧,春花似錦梗顺、人聲如沸泡孩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仑鸥。三九已至,卻和暖如春变屁,著一層夾襖步出監(jiān)牢的瞬間眼俊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工粟关, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疮胖,地道東北人。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓闷板,卻偏偏與公主長得像澎灸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子遮晚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評論 2 359

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