Blockの本質
4761 ワード
Objective Cオブジェクトメモリモデル
blockの背後にあるメモリモデルは実際には構造体であり、この構造体はblockの実際の実行コードを指す関数ポインタを格納する.
クラスの構造の表示struct DemoClass_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_value;
};
NSObject_の表示IMPL struct NSObject_IMPL {
Class isa;
};
Classの表示typedef struct objc_class *Class;
struct objc_の表示class struct objc_class {
Class isa ;
};
Cの中にBがあります.Bの中にAがあります.Aの中にAがあります.
blockの本質
コード変換static void _I_DemoClass_demoFunction(DemoClass * self, SEL _cmd) {
NSInteger variable = 10;
VoidBlock temp = ((void (*)())&__DemoClass__demoFunction_block_impl_0((void *)__DemoClass__demoFunction_block_func_0, &__DemoClass__demoFunction_block_desc_0_DATA, variable));
((void (*)(__block_impl *))((__block_impl *)temp)->FuncPtr)((__block_impl *)temp);
}
分析:
ブロックの構造体 struct __DemoClass__demoFunction_block_impl_0 {
struct __block_impl impl;
struct __DemoClass__demoFunction_block_desc_0* Desc;
NSInteger variable;
__DemoClass__demoFunction_block_impl_0(void *fp, struct __DemoClass__demoFunction_block_desc_0 *desc, NSInteger _variable, int flags=0) : variable(_variable) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
__block_impl(すなわちblockクラスの構造)struct __block_impl {
void *isa; // OC isa , ,
int Flags; //
int Reserved; //
void *FuncPtr; //Block
};
__DemoClass__demoFunction_block_desc_0(本構造体の説明情報)static struct __DemoClass__demoFunction_block_desc_0 {
size_t reserved;
size_t Block_size;
} __DemoClass__demoFunction_block_desc_0_DATA = { 0, sizeof(struct __DemoClass__demoFunction_block_impl_0)};
コンストラクション関数(すなわち、構造体インスタンスを作成する際に必要な初期化作業を行うための初期化関数)__DemoClass__demoFunction_block_impl_0(void *fp, struct __DemoClass__demoFunction_block_desc_0 *desc, NSInteger _variable, int flags=0) : variable(_variable) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
参考:blockの本質
メモリ内のストレージ領域の分割
struct DemoClass_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_value;
};
struct NSObject_IMPL {
Class isa;
};
typedef struct objc_class *Class;
struct objc_class {
Class isa ;
};
コード変換
static void _I_DemoClass_demoFunction(DemoClass * self, SEL _cmd) {
NSInteger variable = 10;
VoidBlock temp = ((void (*)())&__DemoClass__demoFunction_block_impl_0((void *)__DemoClass__demoFunction_block_func_0, &__DemoClass__demoFunction_block_desc_0_DATA, variable));
((void (*)(__block_impl *))((__block_impl *)temp)->FuncPtr)((__block_impl *)temp);
}
分析:
ブロックの構造体
struct __DemoClass__demoFunction_block_impl_0 {
struct __block_impl impl;
struct __DemoClass__demoFunction_block_desc_0* Desc;
NSInteger variable;
__DemoClass__demoFunction_block_impl_0(void *fp, struct __DemoClass__demoFunction_block_desc_0 *desc, NSInteger _variable, int flags=0) : variable(_variable) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
__block_impl(すなわちblockクラスの構造)
struct __block_impl {
void *isa; // OC isa , ,
int Flags; //
int Reserved; //
void *FuncPtr; //Block
};
__DemoClass__demoFunction_block_desc_0(本構造体の説明情報)
static struct __DemoClass__demoFunction_block_desc_0 {
size_t reserved;
size_t Block_size;
} __DemoClass__demoFunction_block_desc_0_DATA = { 0, sizeof(struct __DemoClass__demoFunction_block_impl_0)};
コンストラクション関数(すなわち、構造体インスタンスを作成する際に必要な初期化作業を行うための初期化関数)
__DemoClass__demoFunction_block_impl_0(void *fp, struct __DemoClass__demoFunction_block_desc_0 *desc, NSInteger _variable, int flags=0) : variable(_variable) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
参考:blockの本質
メモリ内のストレージ領域の分割
Blockのタイプ
Blockの宣言と使用
int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
return num * multiplier;
};
// int (^)(int) ,myBlock ,^(int num) {
// return num * multiplier;
// };
printf("%d", myBlock(3));
// prints "21"
Blockの直接使用
char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine" };
qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) {
char *left = *(char **)l;
char *right = *(char **)r;
return strncmp(left, right, 1);
});
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }
__ブロック変数
blockでblock外の変数を使用する
blockの不思議な点は、block外の変数がシームレスにblock内部で直接使用できることです.例えば、
float price = 1.99;
float (^finalPrice)(int) = ^(int quantity) {
// Notice local variable price is
// accessible in the block
return quantity * price;
};
int orderQuantity = 10;
NSLog(@"Ordering %d units, final price is: $%2.2f", orderQuantity, finalPrice(orderQuantity));
Ordering 10 units, final price is: $19.90
しかし、block内部でローカル変数の値を変更することはできません.さらに注意しなければならないのはpriceのような局所変数の変化はblockに現れないことです!たとえば、上のコードに続いて、次のように書きます.
price = .99;
NSLog(@"Ordering %d units, final price is: $%2.2f", orderQuantity, finalPrice(orderQuantity));
Ordering 10 units, final price is: $19.90
これは悲しいですが、block内のpriceはreadonlyであり、blockを定義するときだけ付与されると理解できます(補足説明ですが、実際にはpriceがvalue typeなので、block内のpriceはblock内にコピーされていることを明らかにし、block外のpriceはどのように変化してもblock内のpriceとは関係ありません.reference typeであれば、外部の変化は実際にblock内に影響します).
blockで変数を変更する
blockで変数を変更するには、次の2つの方法が考えられます.1.blockで変更したい外部ローカルオブジェクトについては、これらの変数に
__block
キーワード修飾を加えることで、blockで変更することができます. __block int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
multiplier ++;
return num * multiplier;
};
myBlock(2);
2.インスタンス変数を使用すると、インスタンス内の変数がインスタンス全体にわたって横行するように変更できます.