04.實戰技術 block深入研究,UICollectionView的使用

@(iOS Study)[實戰技術]


目錄

  • 04.實戰技術 block深入研究,UICollectionView的使用
  • 1.block的深入研究
    • block基本使用
    • block開發使用場景(保存代碼)
    • block開發使用場景(傳值)
    • block內存管理(MRC)
    • block內存管理(ARC)
    • block循環引用
    • block循環引用(復雜)
    • block變量傳遞
    • block開發使用場景(參數使用)
    • block開發中使用場景(返回值)
  • 2.UICollectionView的使用
    • UICollectionView注意點


1.block的深入研究

block的作用: 可以用來保存一段代碼段,也可以用來傳遞參數.block如果存放代碼段,該代碼段并不會馬上執行,需用手動調用.

  • 快速生成block代碼
    • 輸入'inlineBlock'快速生成block代碼
      -block類型是對象,不是普通數據類型

block基本使用

  • block的格式
// block的完整格式
block返回類型(^block變量名)(block參數) = ^(block返回類型,一般情況都省略)(block參數>) {
    // block代碼段
}
  • block的聲明方式
// block聲明:返回值(^Block變量名)(block參數類型),參數變量名可以省略
void(^block)();
void(^block1)(int);
  • block的定義方式
    // block定義: 等號右邊 ^(參數類型 參數變量名){};
    void(^block2)(int a) = ^(int a){
        
    };
    
    // block定義二: 等號右邊 ^返回值(參數類型 參數變量名){};,返回值(=號后面第一個int)可以省略,但是也有不省略
    int(^block3)(int a) = ^int(int a){
        return 2;
    };
    
    // block定義三: 當沒有返回值,沒有參數,可以省略
    void(^block4)() = ^{
        
    };

block開發使用場景(保存代碼)

  • 模型中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(@"打電話");
};

// 執行block,需判斷block是否為空,如果為空,調用時會導致程序奔潰
if (item.block) {
    item.block();
}

block開發使用場景(傳值)

順傳:定義屬性
逆傳:代理,block,block可以用來替代代理

  • block逆傳值步驟(控制器B由控制器A Modal出來的, 控制器B逆傳值給控制器A)

    • 1.在控制器B添加一個block屬性
    // 控制器B
    @property (nonatomic, strong) void(^blockValue)(NSString *value);
    
    • 2.在控制器A中給控制器B的block添加代碼段
      // 控制器A
      // REMARKS: block傳值(逆傳)
      - (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點擊時調用block
      - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
      {
          // block逆傳
          if (self.blockValue) {
              self.blockValue(@"123");
          }
          
          [self dismissViewControllerAnimated:YES completion:nil];
      }
    
    • 4.控制器B調用block時,會將@"123"傳遞給控制器A中的
    // 控制器B調用block會調用以下代碼段,并將value傳遞過來
    modalVc.blockValue = ^(NSString *value){
        NSLog(@"%@", value);
    };
    

block內存管理(MRC)

  • 內存5個區:堆,棧,方法區,常量區,全局區

    • 堆:手動管理內存
    • 棧:自動管理,代碼塊一過,就會自動釋放.
  • 在MRC中的存儲

    • 如果block沒有訪問外部的局部變量或者訪問被static修飾局部變量,block默認存放在全局區.
    • 如果block訪問外部的局部變量,block存放在"棧"里面
      // REMARKS: 測試block訪問外部局部變量,block的存儲
      - (void)test2 {
          
          // 1.驗證block的存儲區域
          int a = 10;
          void(^block)() = ^{
              NSLog(@"%d", a);
          };
          
          self.block = block;
          // ARC打印結果: <__NSMallocBlock__: 0x7fc433d0fab0> (block存儲在堆區)
          // MRC打印結果: <__NSStackBlock__: 0x7fff51e24a18>  (block存儲在棧區)
          NSLog(@"%@", block);
      }
    
    // REMARKS: 驗證block的方法static修飾的局部變量,block的存儲
    - (void)test1 {
        
        // 1.驗證block的存儲區域
        static int a = 10;
        void(^block)() = ^{
            NSLog(@"%d", a);
        };
        // ARC和MRC打印結果一樣: <__NSGlobalBlock__: 0x10e1d9090>
        NSLog(@"%@", block);
    }
    
  • MRC使用block的注意點

    • MRC:不能使用retain聲明block,block依然放在棧里面,會自動銷毀.如果用retain聲明的屬性引用block,則程序奔潰.
    • MRC:使用copy聲明block,才會放在堆里面
  • MRC開發習慣:訪問屬性或者設置屬性,MRC必須使用點語法,不要使用下劃線.因為點語法會調用get方法,get方法會做引用計數器+1操作.而用下劃線沒有對引用計數器+1.

  • MRC:沒有strong,和weak, 只有assign, retain, copy

  • 區分MRC代碼:

    • 1.看能否調用release retain retainCount
    • 2.ARC不能調用[super dealloc]

block內存管理(ARC)

  • ARC環境block的存儲區
    如果block訪問外部的局部變量,block存放在"堆"里面

  • block原則

    • 如果block沒有訪問外部的局部變量或者局部變量被static修飾,block默認存放在"全局區"
    • ARC:使用strong聲明block,不要使用weak.
  • ARC管理原則:默認一個局部變量對象,都是強指針,存放堆里面

block循環引用

block會對外部所有強指針對象給強引用,block不會對外部弱指針對象給強引用.

  • block代碼段內部使用self

    • 正確用法: 使用__weak typeof(self) weakSelf = self;將self轉換成弱指針.對象能正常被銷毀
    // 使用__weak typeof(self) weakSelf = self;將self轉換成弱指針.
    __weak typeof(self) weakSelf = self;
    _block = ^{
        NSLog(@"%@", weakSelf);
    };
    
    • 錯誤用法: 直接在block內部使用self,造成循環引用,對象不會被銷毀.
    _block = ^{
        NSLog(@"%@", self);
    };
    

block循環引用(復雜)

  • block在多線程中的應用

    • block內部執行延遲操作或者異步任務需要在block內部對weakSelf做一次__strong的引用,讓對象延遲釋放,以確保在執行延遲操作或異步任務時,對象還沒被釋放.
    • 以下block內部執行延遲操作,對象會延遲2秒后才釋放.
      - (void)blockTest
      {
          // SINGLE: block內部執行延遲操作或者異步任務需要在block內部對weakSelf做一次__strong的引用
          
          __weak typeof(self) weakSelf = self;
          _block = ^{
              
              // 需要在block內部對weakSelf做一次__strong的引用,必須用__strong強引用weakSelf,這樣才能延遲釋放self對象,否則會出現延遲打印結果為null,在執行延遲任務前,對象已經被釋放了.
              __strong typeof(weakSelf) strongSelf = weakSelf;
              
              // 執行延遲操作或異步任務,
              dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                  NSLog(@"%@", strongSelf);
              });
              
          };
          
          // 執行block
          _block();
      }
    

block變量傳遞

  • block訪問外部局部變量沒有被任何關鍵字修飾,都是值傳遞.值傳遞表示block中的value不會隨外部的改變而改變.
- (void)test
{
    // block訪問外部局部變量沒有被任何關鍵字修飾,都是值傳遞.值傳遞表示外部的value值改變不會影響block內部的值.
    int value = 10;
    
    void(^block)() = ^{
        
        NSLog(@"%d", value);
    };
    
    value = 20;
    
    block();
    
    // 打印結果: 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();
    
    // 打印結果: 20
}

block開發使用場景(參數使用)

  • block作為方法參數使用
// block當參數使用 caculatorBlock帶有一個參數result,并且返回值為int類型
- (void)caculator:(int(^)(int result))caculatorBlock;

block開發中使用場景(返回值)

  • 鏈式編程思想:把方法調用通過點語法鏈接,可讀性非常好 (Masonry框架使用)

  • 鏈式編程思想的簡單使用,block當返回值

- (void)test1
{
    // self.add()相當于調用 add的get方法,get方法返回值是block類型的,再用返回值調用
//    void(^block)() = self.add;
//    block();
    
    self.add();
}

- (void(^)())add
{
    return ^{
        NSLog(@"add");
    };
}

  • 使用block當做返回值, 實現manager.add(10).add(5)鏈式編程

    • 1.先分析manager.minus(3)操作,相當于先調用get方法,返回block類型的值,再通過返回值調用block.
    // manager.minus(3)相當于執行以下兩個操作
    // void(^block)(int) = manager.minus;
    // block(3);
    
    • 2.由以上可推出manager的方法聲明
      - (void(^block)(int))minus;
      
      // 實現- (void(^block)(int))minus方法
      - (void(^block)(int))minus
      {
          return ^(int value){
              _result -= value;
          };
      }
    
    • 3.分析manager.minus(3).minus(10),如果想再調用.minus(10)執行操作,manager.minus(3)返回值必須是CalculatorManager類型對象,由此可以分析出,block的返回值不是void,而是CalculatorManager類型.
      - (CalculatorManager *(^)(int)) minus;
      
      // 實現- (CalculatorManager *(^)(int)) minus方法
      - (CalculatorManager *(^)(int)) minus
      {
          return ^(int value){
              _result -= value;
              // 下面的return表示block的返回值,返回當前對象
              return self;
          };
      }
    
    • 4.以上操作完成,外部就能用manager.minus(3).minus(10)鏈式編程.

2.UICollectionView的使用

UICollectionView注意點

  • UICollectionView注意點:
    • 1.初始化必須要傳入布局,(流水布局:九宮格布局)
    • 2.UICollectionViewCell必須要注冊
    • 3.必須自定義cell
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容