Exploración en profundidad del bloque de iOS

etiquetas: bloque

Analice el bloque en dos partes:

  1. cómo utilizar
  2. ¿Por qué usarlo así?

pila de bloques

clasificación:

Según la ubicación del bloque en la memoria, se divide en tres tipos: NSGlobalBlock, NSStackBlock y NSMallocBlock.

NSGlobalBlock: función similar, ubicada en la sección de texto; NSStackBlock: ubicado en la memoria de pila, Block no será válido después de que la función regrese; NSMallocBlock: ubicado en la memoria de pila. Necesita ser publicado por el desarrollador.
Distinguir: bajo no ARC, el que no hace referencia a variables externas es NSGlobalBlock, el que hace referencia a variables externas es NSStackBlock, y la copia de NSStakBlock es NSMallocBlock.
Gestión de la memoria:

El bloque se genera en tiempo de compilación, no en tiempo de ejecución. Entonces, si se usan variables externas durante la compilación, se colocará una instantánea de las variables en la pila.

  • NSGlobalBlock: el ciclo de vida comienza desde el principio de la aplicación hasta el final de la aplicación. No tiene ningún sentido retenerlo / liberarlo / copiarlo, o volver a sí mismo.
  • NSStackBlock: desaparece después de que regresa la función. No tiene ningún sentido retenerlo / liberarlo, o volver a sí mismo. Copiarlo copiará el contenido a la memoria del montón (NSMallocBlock) y generará un nuevo bloque de memoria.
  • NSMallocBlock: Necesita ser liberado por el programador, retenerlo es lo mismo que copiar, excepto que el contador del objeto puntiagudo se incrementa en 1, y siempre se muestra 1 al imprimir, pero el contador real ha aumentado. Disminuya el contador de liberación en uno, pero cuando se imprime el contador, siempre se muestra 1.

 

typedef int (^square)(int);

(void) viewDidLoad
{
[super viewDidLoad];

square tempBlock1 = ^(int a){ return a * a; };

NSLog(@"tempBlock1:%@, return1:%d", tempBlock1, tempBlock1(5));
// log: tempBlock1:<__NSGlobalBlock__: 0x10e6d9240>, return1:25

int i = 2;
square temptBlock2 = ^(int a){ int itRet = i * a; return itRet; };
NSLog(@"temptBlock2:%@, return2:%d", temptBlock2, temptBlock2(5));
// log: temptBlock2:<__NSStackBlock__: 0x7fff51528a50>, return2:10

square temptBlock3 = [temptBlock2 copy];
NSLog(@"temptBlock3:%@, return3:%d", temptBlock3, temptBlock3(5));
// log: temptBlock3:<__NSMallocBlock__: 0x7fbdc0608180>, return3:10

temptBlock = [temptBlock3 copy];
NSLog(@"temptBlock:%@, return:%d", temptBlock, temptBlock(5));
// log: temptBlock:<__NSMallocBlock__: 0x7fbdc0608180>, return3:10 此时temptBlock的计数器实际上是2

[temptBlock release];
}

(IBAction)Test:(id)sender {
NSLog(@"=====temptBlock:%@, return:%d, blockRec:%ld", temptBlock, temptBlock(5), [temptBlock retainCount]);

// 如果viewDidLoad中temptBlock再做次release就crash了 这里
}

 

Principio de modificación del valor de la variable

 

typedef int (^square)(int);

int i = 6;
square tempBlock1 = ^(int a){return a * i; };

printf("=====%d", tempBlock1(5));

Si desea cambiar el valor de i en tempBlock1 no está permitido, ¿por qué? Verifique la implementación subyacente del código: clang -rewrite-objc block2.c, elimine el código innecesario y conserve el código principal:

 

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int i;
__main_block_impl_0(void fp, struct __main_block_desc_0 desc, int _i, int flags=0) : i(_i) {

 
  1. impl.isa = &_NSConcreteStackBlock;

  2. impl.Flags = flags;

  3. impl.FuncPtr = fp;

  4. Desc = desc;

}
};

static int __main_block_func_0(struct __main_block_impl_0 *__cself, int a) {
int i = __cself->i; // bound by copy
return a * i; }

static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

int main()
{

 
  1. int i = 6;

  2. square tempBlock1 = ((int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, i));

  3.  
  4. printf("=====%d", ((int (*)(__block_impl *, int))((__block_impl *)tempBlock1)->FuncPtr)((__block_impl *)tempBlock1, 5));

  5.  
  6. return 0;

}

El código se ve mucho, mira la información principal:

  1. __block_impl: isa se refiere a un objeto, el puntero a la clase a la que pertenece es el tipo de bloque (aquí, el objeto de pila), flags registra el identificador del bloque, reservado: campos reservados para expansión, funcptr: el cuerpo de la función ejecutada por el bloque, es decir La realización de bloque. __main_block_impl_0: contiene __block_impl objetos y __main_block_desc_0 (es decir, registra el tamaño de __main_block_impl_0) y la imagen de las variables externas. La comprensión personal en realidad __block_impl es la clase base de __main_block_impl_0.
  2. Secuencia: crea un objeto tempBlock1 y ejecuta el cuerpo de la función del bloque.
  3. ¿Por qué no se puede cambiar el valor de la variable directamente en el bloque, porque solo se pasa el parámetro formal? Si se cambia, la i en tempBlock1 solo se puede cambiar, pero la variable externa i no se cambiará, por lo que esta operación simplemente está prohibida. Entonces, ¿cómo se puede vincular con el mundo exterior?

 

{
   
   
 
  1. __block int i = 6;

  2. square tempBlock1 = ^(int a){ i = i + 1; return a * i; };

  3.  
  4. i = 7;

  5.  
  6. printf("=====%d,i=%d", tempBlock1(5), i);

  7.  
  8. return 0;

}

También verifique el código fuente y elimine el código innecesario:

 

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

struct __Block_byref_i_0 {
void *__isa;
__Block_byref_i_0 *__forwarding;
int __flags;
int __size;
int i;
};

struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_i_0 *i; // by ref
__main_block_impl_0(void fp, struct __main_block_desc_0 desc, __Block_byref_i_0 *_i, int flags=0) : i(_i->__forwarding) {

 
  1. impl.isa = &_NSConcreteStackBlock;

  2. impl.Flags = flags;

  3. impl.FuncPtr = fp;

  4. Desc = desc;

}
};

static int __main_block_func_0(struct __main_block_impl_0 *__cself, int a) {
__Block_byref_i_0 *i = __cself->i; // bound by ref
(i->__forwarding->i) = (i->__forwarding->i) + 1; return a * (i->__forwarding->i); }

static void __main_block_copy_0(struct __main_block_impl_0dst, struct __main_block_impl_0src) {_Block_object_assign((void)&dst->i, (void)src->i, 8/BLOCK_FIELD_IS_BYREF/);}

static void __main_block_dispose_0(struct __main_block_impl_0src) {_Block_object_dispose((void)src->i, 8/BLOCK_FIELD_IS_BYREF/);}

static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (copy)(struct __main_block_impl_0, struct __main_block_impl_0*);
void (dispose)(struct __main_block_impl_0);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

int main()
{

 
  1. __attribute__((__blocks__(byref))) __Block_byref_i_0 i = {(void*)0,(__Block_byref_i_0 *)&i, 0, sizeof(__Block_byref_i_0), 6};

  2. square tempBlock1 = ((int (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_i_0 *)&i, 570425344));

  3.  
  4. (i.__forwarding->i) = 7;

  5.  
  6. printf("=====%d,i=%d", ((int (*)(__block_impl *, int))((__block_impl *)tempBlock1)->FuncPtr)((__block_impl *)tempBlock1, 5), (i.__forwarding->i));

  7.  
  8. return 0;

}

Solo mira los diferentes códigos:

  1. Un __Block_byref_i_0 más: Genere __Block_byref_i_0 objeto i para almacenar el valor de las variables externas, de modo que el puntero del objeto __Block_byref_i_0 i se pase al bloque, y el valor de la variable int i en el objeto __Block_byref_i_0 i se cambie directamente en la función de bloque funptr Tanto el externo como el interno usan el mismo puntero de objeto, por lo que cambiar el valor dentro y fuera del bloque está vinculado, es decir, el mismo.
  2. Un __main_block_copy_0 más: Si el bloque se copia de la pila al montón, esta función será llamada. La implementación interna es apuntar el reenvío i-> del objeto __Block_byref_i_0 que apilo a la dirección en el montón __Block_byref_i_0. De esta forma, la operación en el montón también cambiará la pila. También es el papel del reenvío (la implementación del código se encuentra a continuación).
  3. __main_block_dispose_0: Esta función se llamará cuando se libere el bloque.

Para obtener el código fuente específico, vea el código fuente de estas implementaciones en blockRuntime de Apple. Haga clic aquí para ver la URL :

void _Block_object_assign(void destAddr, const void object, const int flags)
{
   
   
 
  1. //printf("_Block_object_assign(*%p, %p, %x)\n", destAddr, object, flags);

  2. if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER)

  3. {

  4. if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK)

  5. {

  6. _Block_assign_weak(object, destAddr);

  7. }

  8. else

  9. {

  10. // do *not* retain or *copy* __block variables whatever they are

  11. _Block_assign((void *)object, destAddr);

  12. }

  13. }

  14. else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF)

  15. {

  16. // copying a __block reference from the stack Block to the heap

  17. // flags will indicate if it holds a __weak reference and needs a special isa

  18. _Block_byref_assign_copy(destAddr, object, flags);

  19. }

  20. // (this test must be before next one)

  21. else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK)

  22. {

  23. // copying a Block declared variable from the stack Block to the heap

  24. _Block_assign(_Block_copy_internal(object, flags), destAddr);

  25. }

  26. // (this test must be after previous one)

  27. else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT)

  28. {

  29. //printf("retaining object at %p\n", object);

  30. _Block_retain_object(object);

  31. //printf("done retaining object at %p\n", object);

  32. _Block_assign((void *)object, destAddr);

  33. }

}

static void _Block_byref_assign_copy(void dest, const void arg, const int flags)
{

 
  1. struct Block_byref **destp = (struct Block_byref **)dest;

  2. struct Block_byref *src = (struct Block_byref *)arg;

  3. if (src->forwarding->flags & BLOCK_IS_GC)

  4. {

  5. ; // don't need to do any more work

  6. }

  7. else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0)

  8. {

  9. //printf("making copy\n");

  10. // src points to stack

  11. bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));

  12. // if its weak ask for an object (only matters under GC)

  13. struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);

  14. copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack

  15. copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)

  16. src->forwarding = copy; // patch stack to point to heap copy

  17. copy->size = src->size;

  18. if (isWeak) {

  19. copy->isa = &_NSConcreteWeakBlockVariable; // mark isa field so it gets weak scanning

  20. }

  21. if (src->flags & BLOCK_HAS_COPY_DISPOSE) {

  22. // Trust copy helper to copy everything of interest

  23. // If more than one field shows up in a byref block this is wrong XXX

  24. copy->byref_keep = src->byref_keep;

  25. copy->byref_destroy = src->byref_destroy;

  26. (*src->byref_keep)(copy, src);

  27. }

  28. else {

  29. // just bits. Blast 'em using _Block_memmove in case they're __strong

  30. _Block_memmove(

  31. (void *)&copy->byref_keep,

  32. (void *)&src->byref_keep,

  33. src->size - sizeof(struct Block_byref_header));

  34. }

  35. }

  36. // already copied to heap

  37. else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) {

  38. latching_incr_int(&src->forwarding->flags);

  39. }

  40. // assign byref data block pointer into new Block

  41. _Block_assign(src->forwarding, (void **)destp);

}

 

Referencia circular

fenómeno

Haga [[Person alloc] init] y [Person release] para las siguientes tres clases Person respectivamente, y compruebe si se llamará a dealloc en la clase Person.

Persona tipo A:

 

typedef int (^square)(int);

import "Person.h"

@interface Person ()
{

square tempBlock;

}

@property (nonatomic, assign) int i;

@end

@implementation Person

(id) init
{
self = [super init];
if (self)
{

 
  1. _i = 8;

  2. tempBlock = ^(int a){

  3. return a * _i;

  4. };

  5.  
  6. NSLog(@"tempBlock:%@", tempBlock);

}

return self;
}

(void) funTest
{

NSLog(@"tmpBlock:%d", tempBlock(5));

}

(void) dealloc
{

 
  1. [super dealloc];

  2.  
  3. NSLog(@"dealloc run");

}

@end

Clase B: Persona B:

 

typedef int (^square)(int);

import "Person1.h"

@interface Person1 ()
{

square tempBlock;

}

@property (nonatomic, assign) int i;

@end

@implementation Person1

(id) init
{
self = [super init];
if (self)
{

 
  1. _i = 8;

  2. square tempBlock1 = ^(int a){

  3. return a * _i;

  4. };

  5.  
  6. tempBlock = [tempBlock1 copy];

  7.  
  8. NSLog(@"tempBlock:%@, temptBlock1:%@", tempBlock, tempBlock1);

}

return self;
}

(void) funTest
{

NSLog(@"tmpBlock:%d", tempBlock(5));

}

(void) dealloc
{

 
  1. [super dealloc];

  2.  
  3. NSLog(@"dealloc run");

}

@end

Clase C: Persona C:

 

typedef int (^square)(int);

import "Person2.h"

@interface Person2 ()
{

square tempBlock;

}

@property (nonatomic, assign) int i;

@end

@implementation Person2

(id) init
{
self = [super init];
if (self)
{

 
  1. _i = 8;

  2. __block Person2* weakSelf = self;

  3. square tempBlock1 = ^(int a){

  4. return a * weakSelf.i;

  5. };

  6.  
  7. tempBlock = [tempBlock1 copy];

  8.  
  9. NSLog(@"tempBlock:%@, temptBlock1:%@", tempBlock, tempBlock1);

}

return self;
}

(void) funTest
{

NSLog(@"tmpBlock:%d", tempBlock(5));

}

(void) dealloc
{

 
  1. [super dealloc];

  2.  
  3. NSLog(@"dealloc run");

}

@end

Encontrar:

  1. Dealloc de A y C se llamará, pero no se llamará dealloc de B
  2. El bloque en A es el bloque de pila, y los tempBlocks en B y C son el bloque de pila (copia de la pila)
  3. Significa que los bloques de la pila no harán una fuerte referencia a sí mismo, mientras que los bloques del montón harán una fuerte referencia a uno mismo. Si se agrega __block Person2 * thinSelf = self;, entonces la variable de débilSelf no se referenciará fuertemente en el bloque.

¿por qué?

Consulta de realización esencial

Al observar la implementación del código fuente, sabrá que cuando el bloque de la pila se copia en el montón, el objeto persona se retiene, y cuando el objeto persona se agrega con __block, la persona dentro del bloque no se retiene. Los detalles son los siguientes: El
código fuente de la vista Clang para el código person1 es el siguiente:

 

struct __block_impl 
{
   
   
 
  1. void *isa;

  2. int Flags;

  3. int Reserved;

  4. void *FuncPtr;

};

struct Person1_IMPL
{

 
  1. struct NSObject_IMPL NSObject_IVARS;

  2. square tempBlock;

  3. int _i;

};

struct __Person1__init_block_impl_0
{
struct __block_impl impl;
struct __Person1__init_block_desc_0* Desc;
Person1 *self;
__Person1__init_block_impl_0(void fp, struct __Person1__init_block_desc_0 desc, Person1 *_self, int flags=0) : self(_self)
{

 
  1. impl.isa = &_NSConcreteStackBlock;

  2. impl.Flags = flags;

  3. impl.FuncPtr = fp;

  4. Desc = desc;

}
};

static int __Person1__init_block_func_0(struct __Person1__init_block_impl_0 *__cself, int a)
{

 
  1. Person1 *self = __cself->self; // bound by copy

  2. return a * (*(int *)((char *)self + OBJC_IVAR_$_Person1$_i));

}

static void __Person1__init_block_copy_0(struct __Person1__init_block_impl_0dst, struct __Person1__init_block_impl_0src)
{

 
  1. _Block_object_assign((void*)&dst->self, (void*)src->self, 3/

  2. *BLOCK_FIELD_IS_OBJECT*/);

}

static void __Person1__init_block_dispose_0(struct __Person1__init_block_impl_0*src)
{
_Block_object_dispose((void)src->self, 3/BLOCK_FIELD_IS_OBJECT*/);
}

static struct __Person1__init_block_desc_0
{

 
  1. size_t reserved;

  2. size_t Block_size;

  3. void (*copy)(struct __Person1__init_block_impl_0*, struct __Person1__init_block_impl_0*);

  4. void (*dispose)(struct __Person1__init_block_impl_0*);

} __Person1__init_block_desc_0_DATA = { 0, sizeof(struct __Person1__init_block_impl_0), __Person1__init_block_copy_0, __Person1__init_block_dispose_0};

static id _I_Person1_init(Person1 * self, SEL _cmd)
{

 
  1. self = ((Person1 *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Person1"))}, sel_registerName("init"));

  2. if (self)

  3. {

  4. (*(int *)((char *)self + OBJC_IVAR_$_Person1$_i)) = 8;

  5. square tempBlock1 = ((int (*)(int))&__Person1__init_block_impl_0((void *)__Person1__init_block_func_0, &__Person1__init_block_desc_0_DATA, self, 570425344));

  6.  
  7. (*(square *)((char *)self + OBJC_IVAR_$_Person1$tempBlock)) = (square)((id (*)(id, SEL))(void *)objc_msgSend)((id)tempBlock1, sel_registerName("copy"));

  8.  
  9. NSLog((NSString *)&__NSConstantStringImpl__var_folders_4x_l4ckkvk570s3grlbg_9fdk_40000gn_T_Person1_617ecb_mi_0, (*(square *)((char *)self + OBJC_IVAR_$_Person1$tempBlock)), tempBlock1);

  10. }

  11.  
  12. return self;

}

static void _I_Person1_funTest(Person1 * self, SEL _cmd)
{

NSLog((NSString *)&__NSConstantStringImpl__var_folders_4x_l4ckkvk570s3grlbg_9fdk_40000gn_T_Person1_617ecb_mi_1, ((int (*)(__block_impl *, int))((__block_impl *)(*(square *)((char *)self + OBJC_IVAR_$_Person1$tempBlock)))->FuncPtr)((__block_impl *)(*(square *)((char *)self + OBJC_IVAR_$_Person1$tempBlock)), 5));

}

static void _I_Person1_dealloc(Person1 * self, SEL _cmd)
{

 
  1. ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Person1"))}, sel_registerName("dealloc"));

  2.  
  3. NSLog((NSString *)&__NSConstantStringImpl__var_folders_4x_l4ckkvk570s3grlbg_9fdk_40000gn_T_Person1_617ecb_mi_2);

}

static int _I_Person1_i(Person1 self, SEL _cmd) { return ((int )((char )self + OBJC_IVAR_$_Person1$_i)); }
static void _I_Person1_setI_(Person1 self, SEL _cmd, int i) { ((int )((char )self + OBJC_IVAR_$_Person1$_i)) = i; }
// @end

Combine runtime.h para ver el proceso de ejecución del código anterior:

  1. Primero ejecute la función _I_Person1_init para ejecutar la copia del bloque. Ver block_copy en runtime.h ejecutará _Block_copy_internal
  2. Ejecutar _Block_copy_internal (const void arg, const int flags)

    struct Block_layout 
    un bloque;
    // Lo siguiente se haría mejor como una declaración de cambio
    aBlock = (struct Block_layout *) arg; // Es un bloque de pila. Hacer una copia.
    if (! isGC) {
     
    1. struct Block_layout *result = malloc(aBlock->descriptor->size);

    2. if (!result) return (void *)0;

    3. memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first

    4. // reset refcount

    5. result->flags &= ~(BLOCK_REFCOUNT_MASK); // XXX not needed

    6. result->flags |= BLOCK_NEEDS_FREE | 1;

    7. result->isa = _NSConcreteMallocBlock;

    8. if (result->flags & BLOCK_HAS_COPY_DISPOSE) {

    9. //printf("calling block copy helper %p(%p, %p)...\n", aBlock->descriptor->copy, result, aBlock);

    10. (*aBlock->descriptor->copy)(result, aBlock); // do fixup

    11. }

    12. return result;

    }

  3. Realice la copia anterior en el bloque de la pila y genere un nuevo bloque de memoria en el montón. La bandera es BLOCK_NEEDS_FREE y ~ (BLOCK_REFCOUNT_MASK). Recuerde que esto se usará más adelante. isa se declara como un bloque del montón. Luego ejecute (* aBlock-> descriptor-> copy) (result, aBlock) que es la función anterior __Person1__init_block_copy_0
  4. Ejecute _Block_object_assign ((void ) & dst-> self, (void )
    src- > self, 3 / BLOCK_FIELD_IS_OBJECT /); revise runtime.h para ver su implementación.
  5. El código ejecutado es el siguiente:

    void _Block_object_assign(void destAddr, const void object, const int flags) 
    {
    // (this test must be after previous one)
    else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
         
         
     
    1. //printf("retaining object at %p\n", object);

    2. _Block_retain_object(object);

    3. //printf("done retaining object at %p\n", object);

    4. _Block_assign((void *)object, destAddr);

    }
    }

  6. El objeto, src-> self, la persona contenida en el bloque se retiene, y _block_assign asigna la dirección de memoria del objeto persona contenido en la pila a la dirección del objeto persona en el montón. De esta manera, apuntar a un objeto persona puede manipular directamente las variables y valores del objeto persona.

Del mismo modo, compile el código fuente de person2, verifique runtime.cy analice el código fuente compilado en el siguiente paso:

 

struct __block_impl 
{
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

static void __Block_byref_id_object_copy_131(void dst, void src){
// 4个指针加上2个int 48+24=40即__Block_byref_weakSelf_0中的person对象 131即为BLOCK_FIELD_IS_OBJECT|BLOCK_BYREF_CALLE
_Block_object_assign((char)dst + 40, (void ) ((char*)src + 40), 131);
}

static void __Block_byref_id_object_dispose_131(void *src) {
_Block_object_dispose((void ) ((char)src + 40), 131);
}

static NSConstantStringImpl __NSConstantStringImpl__var_folders_4x_l4ckkvk570s3grlbg_9fdk_40000gn_T_Person2_62cdd7_mi_0 __attribute ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"tempBlock:%@, temptBlock1:%@",28};
static NSConstantStringImpl __NSConstantStringImpl__var_folders_4x_l4ckkvk570s3grlbg_9fdk_40000gn_T_Person2_62cdd7_mi_1 __attribute ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"tmpBlock:%d",11};
static NSConstantStringImpl __NSConstantStringImpl__var_folders_4x_l4ckkvk570s3grlbg_9fdk_40000gn_T_Person2_62cdd7_mi_2 __attribute ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"dealloc run",11};

struct __Block_byref_weakSelf_0 {
void *__isa;
__Block_byref_weakSelf_0 *__forwarding;
int __flags;
int __size;
void (__Block_byref_id_object_copy)(void, void*);
void (__Block_byref_id_object_dispose)(void);
Person2 *weakSelf;
};

struct __Person2__init_block_impl_0 {
struct __block_impl impl;
struct __Person2__init_block_desc_0* Desc;
__Block_byref_weakSelf_0 *weakSelf; // by ref
__Person2__init_block_impl_0(void fp, struct __Person2__init_block_desc_0 desc, __Block_byref_weakSelf_0 *_weakSelf, int flags=0) : weakSelf(_weakSelf->__forwarding) {

 
  1. impl.isa = &_NSConcreteStackBlock;

  2. impl.Flags = flags;

  3. impl.FuncPtr = fp;

  4. Desc = desc;

}
};

static int __Person2__init_block_func_0(struct __Person2__init_block_impl_0 *__cself, int a)
{

 
  1. __Block_byref_weakSelf_0 *weakSelf = __cself->weakSelf; // bound by ref

  2. return a * ((int (*)(id, SEL))(void *)objc_msgSend)((id)(weakSelf->__forwarding->weakSelf), sel_registerName("i"));

}

static void __Person2__init_block_copy_0(struct __Person2__init_block_impl_0dst, struct __Person2__init_block_impl_0src)
{

_Block_object_assign((void*)&dst->weakSelf, (void*)src->weakSelf, 8/*BLOCK_FIELD_IS_BYREF*/);

}

static void __Person2__init_block_dispose_0(struct __Person2__init_block_impl_0*src)
{

_Block_object_dispose((void*)src->weakSelf, 8/*BLOCK_FIELD_IS_BYREF*/);

}

static struct __Person2__init_block_desc_0
{
size_t reserved;
size_t Block_size;
void (copy)(struct __Person2__init_block_impl_0, struct __Person2__init_block_impl_0*);
void (dispose)(struct __Person2__init_block_impl_0);
} __Person2__init_block_desc_0_DATA = { 0, sizeof(struct __Person2__init_block_impl_0), __Person2__init_block_copy_0, __Person2__init_block_dispose_0};

static id _I_Person2_init(Person2 * self, SEL _cmd) {

 
  1. self = ((Person2 *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Person2"))}, sel_registerName("init"));

  2. if (self)

  3. {

  4. //33554432即为BLOCK_HAS_COPY_DISPOSE

  5. (*(int *)((char *)self + OBJC_IVAR_$_Person2$_i)) = 8;

  6. __attribute__((__blocks__(byref))) __Block_byref_weakSelf_0 weakSelf = {(void*)0,(__Block_byref_weakSelf_0 *)&weakSelf, 33554432, sizeof(__Block_byref_weakSelf_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, self};

  7. square tempBlock1 = ((int (*)(int))&__Person2__init_block_impl_0((void *)__Person2__init_block_func_0, &__Person2__init_block_desc_0_DATA, (__Block_byref_weakSelf_0 *)&weakSelf, 570425344));

  8. (*(square *)((char *)self + OBJC_IVAR_$_Person2$tempBlock)) = (square)((id (*)(id, SEL))(void *)objc_msgSend)((id)tempBlock1, sel_registerName("copy"));

  9. NSLog((NSString *)&__NSConstantStringImpl__var_folders_4x_l4ckkvk570s3grlbg_9fdk_40000gn_T_Person2_62cdd7_mi_0, (*(square *)((char *)self + OBJC_IVAR_$_Person2$tempBlock)), tempBlock1);

  10. }

  11. return self;

}

static void _I_Person2_funTest(Person2 * self, SEL _cmd)
{

NSLog((NSString *)&__NSConstantStringImpl__var_folders_4x_l4ckkvk570s3grlbg_9fdk_40000gn_T_Person2_62cdd7_mi_1, ((int (*)(__block_impl *, int))((__block_impl *)(*(square *)((char *)self + OBJC_IVAR_$_Person2$tempBlock)))->FuncPtr)((__block_impl *)(*(square *)((char *)self + OBJC_IVAR_$_Person2$tempBlock)), 5));

}

static void _I_Person2_dealloc(Person2 * self, SEL _cmd)
{

 
  1. ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Person2"))}, sel_registerName("dealloc"));

  2. ((void (*)(id, SEL))(void *)objc_msgSend)((id)(*(square *)((char *)self + OBJC_IVAR_$_Person2$tempBlock)), sel_registerName("release"));

  3. NSLog((NSString *)&__NSConstantStringImpl__var_folders_4x_l4ckkvk570s3grlbg_9fdk_40000gn_T_Person2_62cdd7_mi_2);

}

static int _I_Person2_i(Person2 self, SEL _cmd) { return ((int )((char )self + OBJC_IVAR_$_Person2$_i)); }
static void _I_Person2_setI_(Person2 self, SEL _cmd, int i) { ((int )((char )self + OBJC_IVAR_$_Person2$_i)) = i; }

Pasos:

  1. Ejecute _I_Person2_init para generar débilSelf en __Block_byref_weakSelf_0, y use débilSelf para generar objetos tempBlock. Realice una copia de tempBlock.
  2. También ejecute _Block_copy_internal (const void * arg, const int flags)

    struct Block_layout *aBlock;
    // The following would be better done as a switch statement
    aBlock = (struct Block_layout *)arg;// Its a stack block.  Make a copy.
    if (!isGC) {
         
         
     
    1. struct Block_layout *result = malloc(aBlock->descriptor->size);

    2. if (!result) return (void *)0;

    3. memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first

    4. // reset refcount

    5. result->flags &= ~(BLOCK_REFCOUNT_MASK); // XXX not needed

    6. result->flags |= BLOCK_NEEDS_FREE | 1;

    7. result->isa = _NSConcreteMallocBlock;

    8. if (result->flags & BLOCK_HAS_COPY_DISPOSE) {

    9. //printf("calling block copy helper %p(%p, %p)...\n", aBlock->descriptor->copy, result, aBlock);

    10. (*aBlock->descriptor->copy)(result, aBlock); // do fixup

    11. }

    12. return result;

    }

  3. Realice la copia anterior en el bloque de la pila y genere un nuevo bloque de memoria en el montón. La bandera es BLOCK_NEEDS_FREE y ~ (BLOCK_REFCOUNT_MASK). Recuerde que esto se usará más adelante. isa se declara como un bloque del montón. Luego ejecute (* aBlock-> descriptor-> copy) (result, aBlock) que es la función __Person2__init_block_copy_0 anterior
  4. llevado a cabo
    static void __Person2__init_block_copy_0(struct __Person2__init_block_impl_0dst, struct __Person2__init_block_impl_0src)

{ _Block_object_assign ((void ) & dst-> débilSelf, (void ) src-> débilSelf, 8 / BLOCK_FIELD_IS_BYREF /); }

  1. Ver ejecución de runtime.h
    void _Block_object_assign(void destAddr, const void object, const int flags)

{

 
  1. else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF)

  2. {

  3. // copying a __block reference from the stack Block to the heap

  4. // flags will indicate if it holds a __weak reference and needs a special isa

  5. _Block_byref_assign_copy(destAddr, object, flags);

  6. }

}

  1. llevado a cabo
    static void _Block_byref_assign_copy(void dest, const void arg, const int flags)

{

 
  1. struct Block_byref **destp = (struct Block_byref **)dest;

  2. struct Block_byref *src = (struct Block_byref *)arg;

  3.  
  4. else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0)

  5. {

  6. //printf("making copy\n");

  7. // src points to stack

  8. bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));

  9. // if its weak ask for an object (only matters under GC)

  10. struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);

  11. copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack

  12. copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)

  13. src->forwarding = copy; // patch stack to point to heap copy

  14. copy->size = src->size;

  15. if (isWeak) {

  16. copy->isa = &_NSConcreteWeakBlockVariable; // mark isa field so it gets weak scanning

  17. }

  18. if (src->flags & BLOCK_HAS_COPY_DISPOSE) {

  19. // Trust copy helper to copy everything of interest

  20. // If more than one field shows up in a byref block this is wrong XXX

  21. copy->byref_keep = src->byref_keep;

  22. copy->byref_destroy = src->byref_destroy;

  23. (*src->byref_keep)(copy, src);

  24. }

  25. }</code></pre>

  26. 其中最后(*src->byref_keep)(copy, src);即为:__Block_byref_id_object_copy_131,static void __Block_byref_id_object_copy_131(void *dst, void *src) {

// 4 punteros más 2 int 4 8 + 2 4 = 40, es decir, el objeto persona 131 en __Block_byref_weakSelf_0 es BLOCK_FIELD_IS_OBJECT | BLOCK_BYREF_CALLE
_Block_object_assign ((char ) dst + 40, (void ) ((40 char *) src ), 131);}

  1. Ver runTime.h

    void _Block_object_assign(void destAddr, const void object, const int flags) {
    //printf("_Block_object_assign(*%p, %p, %x)n", destAddr, object, flags);
    if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
         
         
     
    1. if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {

    2. _Block_assign_weak(object, destAddr);

    3. }

    4. else {

    5. // do *not* retain or *copy* __block variables whatever they are

    6. _Block_assign((void *)object, destAddr);

    7. }

    }
    }

    Ejecutar _Block_assign en el medio es solo asignar el puntero de la persona en la pila inicial al montón. La persona no será retenida. Por tanto, no provocará referencias circulares.

Supongo que te gusta

Origin blog.csdn.net/wangletiancsdn/article/details/104380807
Recomendado
Clasificación