当前位置: 首页 > news >正文

网站开发课题开发背景恩施做网站公司

网站开发课题开发背景,恩施做网站公司,wordpress 自适应菜单,平乡县网站建设平台block 文章目录block如何通过终端clang生成源码cpp文件block实质截获自动变量全局变量和静态变量的截获__block说明符iOS开发“强弱共舞”——weak和strong配套使用解决block循环引用问题如何通过终端clang生成源码cpp文件 之前在学习block中学习的比较浅,只看了oc…

block

文章目录

  • block
    • 如何通过终端clang生成源码cpp文件
    • block实质
    • 截获自动变量
    • 全局变量和静态变量的截获
    • __block说明符
    • iOS开发“强弱共舞”——weak和strong配套使用解决block循环引用问题

如何通过终端clang生成源码cpp文件

之前在学习block中学习的比较浅,只看了oc高级编程书上有的源码,学习的比较浅,这节来对之前的作以补充。
首先来看看怎么将oc文件生成cpp的源码文件:
在这里插入图片描述

将项目大文件里的二级文件,打开终端 cd 并将此文件拖入:
然后再输入:

clang -rewrite-objc main.m

在这里插入图片描述

回车打开之前的项目文件,即可看到生成了一个cpp文件,打开就是oc的c++源码。
打开后发现有60000多行,很抽象,关键部分看最前面和最后面即可。

block实质

我们现在时文件中写一个最简单的block,看看源码是什么:

int main(int argc, const char * argv[]) {@autoreleasepool {// insert code here...void (^blk)(void) = ^{printf("Block\n");};blk();}return 0;
}

源码:

//经过clang转换后的C++代码
struct __block_impl {void *isa;//指向所属类的指针int Flags;//标志性参数,暂时没用到所以默认为0int Reserved;//今后版本升级所需的区域大小。void *FuncPtr;//函数指针,指向实际执行的函数,也就是block中花括号里面的代码内容。
};struct __main_block_impl_0 {struct __block_impl impl;//上面点1中的结构体的变量struct __main_block_desc_0* Desc;//上面点2中的结构体的指针 __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};static void __main_block_func_0(struct __main_block_impl_0 *__cself {printf("Block\n");
}static struct __main_block_desc_0 {size_t reserved;  //今后版本升级所需区域的大小(一般填0)size_t Block_size;   //Block的大小
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};int main(int argc, const char * argv[]) {void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);return 0;
}

我们来分开说一下每部分的意义:
1.第一个结构体

struct __block_impl {void *isa;//指向所属类的指针int Flags;//标志性参数,暂时没用到所以默认为0int Reserved;//今后版本升级所需的区域大小。void *FuncPtr;//函数指针,指向实际执行的函数,也就是block中花括号里面的代码内容。
};
  • 结构体的名称:impl即implementation的缩写,换句话说这一部分是block的实现部分结构体。
  • void *isa:声明一个不确定类型的指针,用于保存Block结构体实例。
  • int Flags:标识符。
  • int Reserved:今后版本升级所需的区域大小。
  • void *FuncPtr:函数指针,指向实际执行的函数,也就是block中花括号里面的代码内容。

2.在介绍struct __main_block_impl_0结构体之前,先介绍一下这个结构体里的static struct __main_block_desc_0结构体
这个结构体在上面一坨源码的最底下:

static struct __main_block_desc_0 {size_t reserved;  //今后版本升级所需区域的大小(一般填0)size_t Block_size;   //Block的大小
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
  • 第一个成员变量指的是今后版本升级所需区域的大小(一般填0)。
  • 第二个成员变量是Block的大小。
    __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};:
    1⃣️.这就是和我们平时用结构体一样,在定义完最后写一个结构体实例变量,变量名就是__main_block_desc_0_DATA。
    2⃣️.其中reserved为0,Block_size是sizeof(struct __main_block_impl_0)。

3.接下来看struct __main_block_impl_0结构体

struct __main_block_impl_0 {struct __block_impl impl;//上面点1中的结构体的变量struct __main_block_desc_0* Desc;//上面点2中的结构体的指针__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
  • 第一个成员变量是impl,也就是上面点1中的结构体的变量。
  • 第二个成员变量是Desc指针,就是上面点2中的结构体的指针。
  • 剩下的代码是:初始化含有这些结构体的__main_block_impl_0结构体的构造函数,给结构体里的元素赋值。

4.然后是static void __main_block_func_0

static void __main_block_func_0(struct __main_block_impl_0 *__cself {printf("Block\n");
}

这个就比较简单了,Blcok执行的实际代码块。也是点3中fp指针指向的函数。括号中的参数__cself是相当于OC语言版的self,代表的是Block本身。

5.最后来看main函数

int main(int argc, const char * argv[]) {void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);return 0;
}

这两句代码不长但是比较恶心,我们先来看第一句,把强制类型转换去一下试试:

//加了个临时变量temp,看着更方便点
struct __main_block_impl_0 temp = __main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA);
struct __main_block_impl_0 *blk = &temp;

该源代码将__main_block_impl_0结构体类型的自动变量,也就是栈上生成的__main_block_impl_0结构体实例的指针,赋值给__main_block_impl_0结构体指针类型的变量blk。
第二行代码就是相当于源代码中的blk(),即使用该Block部分。去掉转换部分就是:

(*blk->impl.FuncPtr)(blk);

这是使用函数指针调用函数。由Block语法转换的__main_block_impl_0函数的指针被赋值成员变量FunPtr中。

截获自动变量

int main(int argc, const char * argv[]) {int dmy = 256;int val = 10;const char  *fmt = "val = %d\n";void (^blk)(void) = ^{printf(fmt, val);};blk();return 0;
}

转化后的代码:

//经过clang转换后的C++代码
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;const char *fmt;int val;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, const char *_fmt, int _val, int flags=0) : fmt(_fmt), val(_val) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};static void __main_block_func_0(struct __main_block_impl_0 *__cself {const char *fmt = __cself->fmt;int val = __cself->val; printf(fmt, val);
}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(int argc, const char * argv[]) {int dmy = 256;int val = 10;const char *fmt = "val = %d\n";void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, fmt, val));return 0;
}

与上次不同的是在Block语法表达式中使用的自动变量被当作成员变量追加到了__main_block_impl_0结构体中:

struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;const char *fmt;int val;
}

初始化该结构体实例的构造函数也发生了变化

__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, const char *_fmt, int _val, int flags=0) : fmt(_fmt), val(_val) 

初始化时自动变量fmt和val进行了赋值操作:

	impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;fmt = "val = %d\n";val = 10;

在转换后的代码中,截获到__main_block_impl_0结构体实例的成员变量上的自动变量,这些变量在Block语法表达式之前被声明定义,所以之后即使改变自动变量的值也不会对Block语法中的内容有所变化。

总的来说,所谓“截获自动变量值”意味着在执行Block语法时,Block语法表达式所使用的自动变量值被保存到Block的结构体实例(即Block自身中)。
总结一下就是说:
调用__main_block_impl_0的构造函数,构造函数正常有两个参数,func_0和desc_0,在截获自动变量时,会把需要截获的自动变量也放入参数列表中,同时__main_block_impl_0中也会增加两个成员变量a,b,构造函数带参数就是自动给这两个成员变量赋值。在调用func_0时,直接通过__cself(相当于self,其传递的参数也是其本身)的a、b(此时的a,b就是成员变量中的,因为上面的构造函数已经赋值了)

全局变量和静态变量的截获

我们以以下代码为例:

int global_val = 10; // 全局变量
static int static_global_val = 20; // 静态全局变量int main(int argc, const char * argv[]) {@autoreleasepool {static int static_val = 30; // 静态局部变量void (^myLocalBlock)(void) = ^{global_val *= 1;static_global_val *= 2;static_val *= 3;printf("static_val = %d, static_global_val = %d, global_val = %d\n",static_val, static_global_val, global_val);};myLocalBlock();}return 0;
}

源码:

struct __block_impl {void *isa;int Flags;int Reserved;void *FuncPtr;
};int global_val = 10;
static int static_global_val = 20;struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;int *static_val;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_static_val, int flags=0) : static_val(_static_val) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {int *static_val = __cself->static_val; // bound by copyglobal_val *= 1;static_global_val *= 2;(*static_val) *= 3;printf("static_val = %d, static_global_val = %d, global_val = %d\n",(*static_val), static_global_val, global_val);}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(int argc, const char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; static int static_val = 30;void (*myLocalBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &static_val));((void (*)(__block_impl *))((__block_impl *)myLocalBlock)->FuncPtr)((__block_impl *)myLocalBlock);}return 0;
}

我们主要来看下这段代码:

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {int *static_val = __cself->static_val; // bound by copyglobal_val *= 1;static_global_val *= 2;(*static_val) *= 3;printf("static_val = %d, static_global_val = %d, global_val = %d\n",(*static_val), static_global_val, global_val);}

我们发现只有static_val是从__cself中获取的值

再来看看上面的一段代码:

struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;int *static_val;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_static_val, int flags=0) : static_val(_static_val) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
  • 我们发现全局变量,静态全局变量,我们的Block都没有用结构体去特地保存它
  • 只有对于我们的静态局部变量会来保存,但这里要注意,我们使用的不是int static_val,而是int *static_val
  • 也就是说我们使用一个指针来保存的静态局部变量
  • 它会直接保存该变量的地址,之后的操作也是直接对该值本身进行操作,而不是向之前截获的那些变量,等于是重新开辟空间进行保存

产生这个问题的原因:
原因在于,我们的静态变量是存在数据区的,在程序结束前它其实一直都会存在,之所以会被称为局部,只是说出了作用域无法调用到它了,并不是说这块数据不存在了。因此我们只要自己准备好一个指针,保证出了作用域依然能调用到他就行;而对于自动变量,它们真正的问题在于一但出了作用域,直接被释放了,所以要在结构体里开辟空间重新存放,进行值传递
在这里插入图片描述

__block说明符

来看书上的例子:

int main(int argc, const char * argv[]) {__block int val = 10;void (^blk)(void) = ^{val = 1;printf("val = %d\n", val);};blk();return 0;
}

转换后的源码:

struct __Block_byref_val_0 {void *__isa;__Block_byref_val_0 *__forwarding;int __flags;int __size;int val;
};struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__Block_byref_val_0 *val; // by ref__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_val_0 *_val, int flags=0) : val(_val->__forwarding) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};static void __main_block_func_0(struct __main_block_impl_0 *__cself) {__Block_byref_val_0 *val = __cself->val; (val->__forwarding->val) = 1;printf("val = %d\n", (val->__forwarding->val));
}static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->val, (void*)src->val, BLOCK_FIELD_IS_BYREF);
}static void __main_block_dispose_0(struct __main_block_impl_0*src {_Block_object_dispose((void*)src->val, 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(int argc, const char * argv[]) {__Block_byref_val_0 val = {0,(__Block_byref_val_0 *)&val, 0, sizeof(__Block_byref_val_0), 10};blk = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, &val, 0x22000000);return 0;
}

和没加修饰符的比较来说,主要有两处不同:

struct __Block_byref_val_0 {void *__isa;__Block_byref_val_0 *__forwarding;int __flags;int __size;int val;
};

在第一个结构体中,我们发现多了一个__Block_byref_val_0 *__forwarding,这个相当于指向该结构体本身的一个指针。

第二个地方:

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {__Block_byref_val_0 *val = __cself->val; (val->__forwarding->val) = 1;printf("val = %d\n", (val->__forwarding->val));
}

在这里我们发现打印的并不是__Block_byref_val_0 *val而是(val->__forwarding->val)。

最后来看一下主函数:

int main(int argc, const char * argv[]) {__Block_byref_val_0 val = {0,(__Block_byref_val_0 *)&val, 0, sizeof(__Block_byref_val_0), 10};blk = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, &val, 0x22000000);return 0;
}

看下其中赋值部分:

__Block_byref_val_0 val = {0,(__Block_byref_val_0 *)&val, 0, sizeof(__Block_byref_val_0), 10};

这个__block变量val变为了__Block_byref_val_0结构体变量。通过调用 static void __main_block_func_0函数(通过__Block_byref_val_0结构体成员变量__forwarding访问成员变量val),将10赋给val。

iOS开发“强弱共舞”——weak和strong配套使用解决block循环引用问题

__weak是为了解决循环引用

如果一个对象A持有了一个block,同时block内又持有了对象A,为了解决循环引用我们要在用__weak修饰完对象A后再去持有它,这样就解决了循环引用。

__strong可以防止block持有的对象提前释放

我们用GCD延迟方法打印self的信息:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{[self dismissViewControllerAnimated:YES completion:nil];__weak typeof(self) weakSelf = self;void (^Block) (void) = ^{dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSLog(@"%@", weakSelf);});};Block();
}

输出结果:

在这里插入图片描述
点击屏幕,当前控制器消失,同时被销毁掉,5秒后打印的weakSelf就是一个(null),而我们如果在block内使用__strong后就能保证再打印完strongSelf之后再释放当前控制器。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{[self dismissViewControllerAnimated:YES completion:nil];__weak typeof(self) weakSelf = self;void (^Block) (void) = ^{__strong typeof(self) strongSelf = weakSelf;dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSLog(@"%@", strongSelf);});};Block();
}

请添加图片描述

http://www.yayakq.cn/news/404969/

相关文章:

  • 如何做网站网页流程国外网站建设发展现状
  • 温州市网站建设公司网络营销是啥意思
  • 如何免费建购物网站wordpress dashicons
  • 招聘网站开发时间网站建设方案产业
  • 东莞网站建设的方案博采网络
  • 外贸英语 网站网站建设中 倒计时
  • 手机网页设计制作网站wordpress 兔
  • 常州网站价格公司网站建设一条龙
  • 东莞做网站首选企业铭什么网站做简历
  • 手机怎么打开自己做的网站wordpress 云服务器
  • 网站优化目标网站图片3d显示效果
  • 护肤品网站建设环境分析深圳公司排行榜
  • 个人公司网站模板网站开发江西
  • 制作商城网站模板创意极简logo
  • 珠海市企业网站制作品牌新乡门户网站建设方案
  • 建立个人网站的详细步骤阿里云clouder网站建设
  • 怎样写网站设计意义5188关键词平台
  • 外贸网站模板外贸网站建设互联网搜索引擎有哪些
  • 品牌建设再发力广州seo公司推荐
  • 电商网页制作教程网站怎么关键字优化
  • 网站运营编辑做什么的砀山推广公司
  • 在百度做网站推广怎么做学做网站要学哪些
  • 音乐网站开发编程语言协会网站建设哪里实惠
  • 网站做竞价经常会被攻击吗wordpress为什么放弃
  • 做一个网站需要怎么做绵阳建设局网站
  • 企业如何建设免费网站百度seo公司哪家最好
  • 如何免费自己做网站经销商网
  • 青岛网站排名外包淘宝上做网站 源代码怎么给你
  • 公司网站开发费摊销网络设计是干什么工作的
  • 汽车类网站搭建企业内部网站建设