ブロック探索
9270 ワード
私たちが使用するblockは、静的block(外部変数は一切使用していません)、スタックblock(外部一時変数を使用します)、スタックblock(外部メンバ変数または属性を使用します)の3種類に分けられます.静的block 以下はテストのソースコードです.
添付:テストコードにOCオブジェクトを使ってテストした結果も同様です.
2.スタックblock
テストコード
付:臨時変数をOCオブジェクトに置き換えると、NSArayなど、clangから出てくるコードが変わります.
前者の方法名にはCopyがありますが、copyのような操作が行われているとは思わないでください.この方法の具体的な実現は、_を呼び出しました.Block_objectassignメソッドBlock_objectassignメソッドは、伝わった実際のパラメータに基づいて、blockオブジェクトか、OCオブジェクトかを判断します.OCオブジェクトであれば、retainを行い、値を賦課します.
後者の方法は,解析関数的役割であるが,実際のパラメータタイプも同様に判断し,OCオブジェクトであればreleaseを行う.
3.ブロックブロック
テストコード
付1:_u ublockはどんな操作をしましたか?
皆さんはテストコードを作って、clangしてください.blockで修飾された変数は構造体に変化します.具体的な役割は、この変数をスタックからスタックにコピーすることです.
付2:なぜクラスの属性やメンバー変数が直接に変更されるのか、臨時変数は_u_u uとして宣言する必要があります.blockは修正できますか?
添付1の問題の解釈において、臨時変数は声明でブロック後、スタックからスタックにコピーし、クラスの属性やメンバー変数自体がヒープ上にあるか、またはそれぞれの作用領域が異なると理解することができます.
付3:これはblock実現過程のソースコードです. https://github.com/mackyle/blocksruntime
付4:blockは、その保有する変数をリリースするための構文関数を呼び出します.
blockは、その保有する変数を構文関数を呼び出して、blockがnilに設定されたり、releaseされたりするときです.したがって、一時的なblock(テストコードに見られるblock)であれば、メソッド呼び出しが終了したとき、blockとその保有変数をリリースします.blockは属性として、nilをアクティブにしない限り、その所在クラスで呼び出されます. deallocの時リリースします.
@interface MBlockObj : NSObject
@end
#import "MBlockObj.h"
@implementation MBlockObj
- (void)testMBlock {
void (^blockM)(void) = ^{
int i = 0;
i ++;
};
blockM();
}
@end
端末でclang-rewrite-objc MBlockObj.mコマンドを実行した後、余分なコードを削除して、下記の部分をもらいました.struct __MBlockObj__testMBlock_block_impl_0 {
struct __block_impl impl;
struct __MBlockObj__testMBlock_block_desc_0* Desc;
__MBlockObj__testMBlock_block_impl_0(void *fp, struct __MBlockObj__testMBlock_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __MBlockObj__testMBlock_block_func_0(struct __MBlockObj__testMBlock_block_impl_0 *__cself) {
int i = 0;
i ++;
}
static struct __MBlockObj__testMBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
} __MBlockObj__testMBlock_block_desc_0_DATA = { 0, sizeof(struct __MBlockObj__testMBlock_block_impl_0)};
static void _I_MBlockObj_testMBlock(MBlockObj * self, SEL _cmd) {
void (*blockM)(void) = ((void (*)())&__MBlockObj__testMBlock_block_impl_0((void *)__MBlockObj__testMBlock_block_func_0, &__MBlockObj__testMBlock_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)blockM)->FuncPtr)((__block_impl *)blockM);
}
私たちのblockMが変更されているのが見えます.((void (*)())&__MBlockObj__testMBlock_block_impl_0((void *)__MBlockObj__testMBlock_block_func_0, &__MBlockObj__testMBlock_block_desc_0_DATA));
同前MBlockObj__utest MBロックblockimpl_0は二つのパラメータが必要です. __MBlockObj__utest MBロックblockfunc0は主に方法の実現内容であり、2番目のパラメータはブロックに関するいくつかの情報記述である.添付:テストコードにOCオブジェクトを使ってテストした結果も同様です.
2.スタックblock
テストコード
- (void)testMBlock {
int i = 0;
void (^blockM)(void) = ^{
printf("%d", i);
};
blockM();
}
clangから出るコードはこうです.struct __MBlockObj__testMBlock_block_impl_0 {
struct __block_impl impl;
struct __MBlockObj__testMBlock_block_desc_0* Desc;
int i;
__MBlockObj__testMBlock_block_impl_0(void *fp, struct __MBlockObj__testMBlock_block_desc_0 *desc, int _i, int flags=0) : i(_i) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __MBlockObj__testMBlock_block_func_0(struct __MBlockObj__testMBlock_block_impl_0 *__cself)
{
int i = __cself->i; // bound by copy
printf("%d", i);
}
static struct __MBlockObj__testMBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
} __MBlockObj__testMBlock_block_desc_0_DATA = { 0, sizeof(struct __MBlockObj__testMBlock_block_impl_0)};
static void _I_MBlockObj_testMBlock(MBlockObj * self, SEL _cmd) {
int i = 0;
void (*blockM)(void) = ((void (*)())&__MBlockObj__testMBlock_block_impl_0((void *)__MBlockObj__testMBlock_block_func_0, &__MBlockObj__testMBlock_block_desc_0_DATA, i));
((void (*)(__block_impl *))((__block_impl *)blockM)->FuncPtr)((__block_impl *)blockM);
}
一時変数iにアクセスすることにより、構造体が変化し、対応するメンバー変数が多くなり、テストコードが実行するジョブはiを印刷し、_u_uMBlockObj__utest MBロックblockfunc0のprintfプリントのiは、実は一回の値転送をしました.付:臨時変数をOCオブジェクトに置き換えると、NSArayなど、clangから出てくるコードが変わります.
struct __MBlockObj__testMBlock_block_impl_0 {
struct __block_impl impl;
struct __MBlockObj__testMBlock_block_desc_0* Desc;
NSArray *mArr;
__MBlockObj__testMBlock_block_impl_0(void *fp, struct __MBlockObj__testMBlock_block_desc_0 *desc, NSArray *_mArr, int flags=0) : mArr(_mArr) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __MBlockObj__testMBlock_block_func_0(struct __MBlockObj__testMBlock_block_impl_0 *__cself)
{
NSArray *mArr = __cself->mArr; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_8x_br8kd9yd70g5q66ssb9jhblh0000gn_T_MBlockObj_6efbe8_mi_0, mArr);
}
static void __MBlockObj__testMBlock_block_copy_0(struct __MBlockObj__testMBlock_block_impl_0*dst, struct __MBlockObj__testMBlock_block_impl_0*src)
{
_Block_object_assign((void*)&dst->mArr, (void*)src->mArr, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
static void __MBlockObj__testMBlock_block_dispose_0(struct __MBlockObj__testMBlock_block_impl_0*src)
{
_Block_object_dispose((void*)src->mArr, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
static struct __MBlockObj__testMBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __MBlockObj__testMBlock_block_impl_0*, struct __MBlockObj__testMBlock_block_impl_0*);
void (*dispose)(struct __MBlockObj__testMBlock_block_impl_0*);
} __MBlockObj__testMBlock_block_desc_0_DATA = { 0, sizeof(struct __MBlockObj__testMBlock_block_impl_0), __MBlockObj__testMBlock_block_copy_0, __MBlockObj__testMBlock_block_dispose_0};
static void _I_MBlockObj_testMBlock(MBlockObj * self, SEL _cmd) {
NSArray* mArr = ((NSArray *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSArray"), sel_registerName("array"));
void (*blockM)(void) = ((void (*)())&__MBlockObj__testMBlock_block_impl_0((void *)__MBlockObj__testMBlock_block_func_0, &__MBlockObj__testMBlock_block_desc_0_DATA, mArr, 570425344));
((void (*)(__block_impl *))((__block_impl *)blockM)->FuncPtr)((__block_impl *)blockM);
}
ここは主に多くなりました.MBlockObj__utest MBロックblockcopy_0と_uMBlockObj__utest MBロックblockディspose0の二つの方法前者の方法名にはCopyがありますが、copyのような操作が行われているとは思わないでください.この方法の具体的な実現は、_を呼び出しました.Block_objectassignメソッドBlock_objectassignメソッドは、伝わった実際のパラメータに基づいて、blockオブジェクトか、OCオブジェクトかを判断します.OCオブジェクトであれば、retainを行い、値を賦課します.
後者の方法は,解析関数的役割であるが,実際のパラメータタイプも同様に判断し,OCオブジェクトであればreleaseを行う.
3.ブロックブロック
テストコード
@interface MBlockObj : NSObject
@property (nonatomic, strong) NSArray* mArr;
@end
#import "MBlockObj.h"
@implementation MBlockObj
- (void)testMBlock {
_mArr = [NSArray array];
void (^blockM)(void) = ^{
NSLog(@"mArr %@", _mArr);
};
blockM();
}
@end
clangからのコードstruct __MBlockObj__testMBlock_block_impl_0 {
struct __block_impl impl;
struct __MBlockObj__testMBlock_block_desc_0* Desc;
MBlockObj *self;
__MBlockObj__testMBlock_block_impl_0(void *fp, struct __MBlockObj__testMBlock_block_desc_0 *desc, MBlockObj *_self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __MBlockObj__testMBlock_block_func_0(struct __MBlockObj__testMBlock_block_impl_0 *__cself)
{
MBlockObj *self = __cself->self; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_8x_br8kd9yd70g5q66ssb9jhblh0000gn_T_MBlockObj_58d1bf_mi_0, (*(NSArray **)((char *)self + OBJC_IVAR_$_MBlockObj$_mArr)));
}
static void __MBlockObj__testMBlock_block_copy_0(struct __MBlockObj__testMBlock_block_impl_0*dst, struct __MBlockObj__testMBlock_block_impl_0*src)
{
_Block_object_assign((void*)&dst->self, (void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
static void __MBlockObj__testMBlock_block_dispose_0(struct __MBlockObj__testMBlock_block_impl_0*src)
{
_Block_object_dispose((void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
static struct __MBlockObj__testMBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __MBlockObj__testMBlock_block_impl_0*, struct __MBlockObj__testMBlock_block_impl_0*);
void (*dispose)(struct __MBlockObj__testMBlock_block_impl_0*);
} __MBlockObj__testMBlock_block_desc_0_DATA = { 0, sizeof(struct __MBlockObj__testMBlock_block_impl_0), __MBlockObj__testMBlock_block_copy_0, __MBlockObj__testMBlock_block_dispose_0};
static void _I_MBlockObj_testMBlock(MBlockObj * self, SEL _cmd) {
(*(NSArray **)((char *)self + OBJC_IVAR_$_MBlockObj$_mArr)) = ((NSArray *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSArray"), sel_registerName("array"));
void (*blockM)(void) = ((void (*)())&__MBlockObj__testMBlock_block_impl_0((void *)__MBlockObj__testMBlock_block_func_0, &__MBlockObj__testMBlock_block_desc_0_DATA, self, 570425344));
((void (*)(__block_impl *))((__block_impl *)blockM)->FuncPtr)((__block_impl *)blockM);
}
はい、上のコードがわかりました.メンバー変数にアクセスしても、SElfを通じてメンバー変数にアクセスします.上の説明があります.Block_objectassignは実際のパラメータがretain selfとなり、場合によっては循環参照を引き起こすことがあります.付1:_u ublockはどんな操作をしましたか?
皆さんはテストコードを作って、clangしてください.blockで修飾された変数は構造体に変化します.具体的な役割は、この変数をスタックからスタックにコピーすることです.
付2:なぜクラスの属性やメンバー変数が直接に変更されるのか、臨時変数は_u_u uとして宣言する必要があります.blockは修正できますか?
添付1の問題の解釈において、臨時変数は声明でブロック後、スタックからスタックにコピーし、クラスの属性やメンバー変数自体がヒープ上にあるか、またはそれぞれの作用領域が異なると理解することができます.
付3:これはblock実現過程のソースコードです. https://github.com/mackyle/blocksruntime
付4:blockは、その保有する変数をリリースするための構文関数を呼び出します.
blockは、その保有する変数を構文関数を呼び出して、blockがnilに設定されたり、releaseされたりするときです.したがって、一時的なblock(テストコードに見られるblock)であれば、メソッド呼び出しが終了したとき、blockとその保有変数をリリースします.blockは属性として、nilをアクティブにしない限り、その所在クラスで呼び出されます. deallocの時リリースします.