iOS-Blockの使用

8711 ワード

まず、Blockとは何かを知る必要があります.Blockとは?一言で言えば、自動変数を持つ匿名関数です.匿名関数と自動変数とは何ですか?
匿名関数は名前の通り名前を付けない関数であり,C言語ではこのような方法は許されないが,OCのBlockではポインタで直接関数を呼び出すことができるが,それでもポインタの名前を知る必要がある.
Blockでの自動変数の具体的な表現は、自動変数をキャプチャすることです.次のコードを見てください.int b = 0; void (^blo)() = ^{ NSLog(@"Input:b=%d",b); }; b = 3; blo(); /** * Input:b=0 */
bloを呼び出す前にbの値を変更しましたが、出力はBlockコンパイル時のbの値なので、瞬間自動変数をキャプチャするのは、Blockに変数の値が保存され、変数の値の変更に伴って変更されません.
コードを見てみましょうint b = 0; void (^blo)() = ^{ b = 3; };
このコードのコンパイルでエラーが発生しました.コンパイラが提示したのは、Blockで変数の値を変更できないことです.Blockで変数の瞬間値をキャプチャしてから変数の値を変更することはできないので、Blockで変数の値を変更したい場合は、変数宣言時に__を付けるだけです.Block修飾子、このように:__block int b = 0; void (^blo)() = ^{ b = 3; };
しかし、このような状況は許可されています.NSMutableArray *array = [[NSMutableArray alloc]init]; void (^blo)() = ^{ [array addObject:@"Obj"]; };
なぜなら,我々はキャプチャした変数に対してのみ操作を行い,付与を行わないため,キャプチャ変数に対しては付与を行わずに操作を行うことができるからである.
また、Blockでは、~~~がサポートされていないため、C言語の配列を操作できないことに注意してください...
匿名関数と自動変数のキャプチャの特性を組み合わせて,Blockは多くのことをすることができ,以下で見る.
Blockの文法の書き方を具体的に見てみましょう.まず、完全なBlockを見てみましょう.^ NSString *(NSString *a,NSString *b){  return a; };
それぞれの部分が何なのかを説明します.
  • "^"という記号はBlockであることを示しています.
  • NSString*は戻り値を表します.
  • (NSString a,NSString b)という括弧の中でBlockのパラメータで、文法とC言語は似ています.

  • Blockの戻り値を省略して、次のように書くことができます.^ (NSString *a,NSString *b){  return a; };
    このように書くのは上記のような書き方とそっくりですが、実際にはパラメータリストがなければ、パラメータリストを省略することもできます.^ {  NSLog(@" "); };
    このコードを完全に書くと、次のようになります.^void(void) {  NSLog(@" "); };
    なぜBlock変数が必要ですか?このBlock変数によってBlockのポインタを取得し,このポインタによってBlock関数を使用できることを理解できる.まずBlock変数を宣言する方法を見てみましょうint (^Blo)(NSString *s1,NSString *s2);
    前のBlock関数と比較して,各部分の意味を比較的容易に理解できる.
    彼らはそれぞれ:
  • 戻り値
  • 変数名
  • パラメータリスト
  • では、上記のBlock構文を使用して、このBlock変数を割り当てます.int (^Blo)(NSString *s1,NSString *s2); Blo = ^(NSString *s1,NSString *s2){   return 1; };
    そして、このBlock変数をC言語関数として使用することができます.
    ではBlockはいったいどうやって使うのでしょうか.
    Blockは関数パラメータとして使用できます.まず、Blockタイプ変数を宣言し、typedef修飾子を追加します.typedef void(^Blo)(NSString *s1,UIColor *c);
    これにより、Bloを使用してこのBlockを表すことができ、Bloを関数パラメータに追加して、関数を宣言することができます.-(void)func:(Blo)BlockPra{  BlockPra(@"Str",[UIColor redColor]);}
    この関数は次のように使用できます.[self func:^(NSString *s1, UIColor *c) {   NSLog(@"%@",s1); self.view.backgroundColor = c; }];
    見覚えがあるのではないでしょうか.普段使っている多くのコールバックの中にはこのような形式が多いのではないでしょうか.その多くはネットコールバックかもしれません.私たちは方法を呼び出すだけで、コールバックの中で結果を操作することができます.多くのアップルが自分で書いたAPIはこのような方法を使っています.このようなメリットは形式の10部が簡潔であることです.もちろんこのような場所でdelegateを使ってもいいに違いありませんが、表現的にはBlockほど簡潔ではなく、Blockほど便利ではありません.
    さらに、Blockは、コントローラ間の通信として使用することもできる.Blcokは匿名の関数であり、ポインタでもあることはすでに知られていますが、Blockを使用するとiOSでの関数伝達の機能を補うことができます.通常は次のように使用されます.
    ページBのhファイルには、このようなBlock政権が定義され、変数が宣言されています.typedef void(^Blo)(NSString *s1,UIColor *c);  @property (nonatomic, copy) Blo block;
    ページAには次のようなコードがあります.ViewController *b = [[ViewController alloc]init]; __weak ViewController *wself = self; b.block = ^(NSString *s1,UIColor*c){  NSLog(@"%@",s1); wself.view.backgroundColor = c; }; [self.navigationController pushViewController:b animated:true];
    次に、ページBの任意の場所でblock変数を呼び出します.self.block(@"str",[UIColor redColor]);
    いずれもAページでBページから渡されたパラメータを呼び出し、Aページで操作してコントローラAを変更するやり方で、コントローラの逆方向の値を伝えるのが一般的です.
    ここで注意すべき点は、Blockの使用によるループ参照である.Blockで使用する場合は添付_strong修飾子のオブジェクトタイプ自動変数は、ブロックがスタックからスタックにコピーされると、ブロックのすべてに変更されます.これにより、ループリファレンスが発生しやすくなり、メモリの漏洩が発生しますが、現在のコントローラ、すなわちselfが解放される必要があるときに正しく解放されることを保証するだけでよいので、上記のコードを見てみましょう.__weak ViewController *wself = self;
    wself変数を定義し、__を追加します.Weak修飾子は、Blockコードブロックでselfが必要なすべての場所をwselfで置き換えます.これにより、参照カウントが増加しないため、Blockがselfオブジェクトを保持してもループ参照が発生せず、メモリが漏洩します.Blockを関数パラメータとして使用するか、逆転送に使用するかにかかわらず、実際にはBlockの本質、すなわち「自動変数付き匿名関数」の2つの修飾、「自動変数付き」、「匿名関数」の2つの特性への応用である.
    転載先:https://www.cnblogs.com/fwx2015/p/4949819.html