block形参

之前漏了一篇block形参的介绍,这里给补上。

block形参就是定义block带的参数,和函数的参数使用一样,我们可以在block随意使用修改block形参。

我们来看个例子:

我们声明了两个NSString 指针_p1 _p2、int 型_p3、可变数组_p4,并把这些参数传入block,在block内修改。

-(void )test3
{
NSString *_p1=[NSString stringWithFormat:@"hello %@",@"world11"];
NSString *_p2=[NSString stringWithFormat:@"hello %@",@"world12"];
int _p3=;
NSMutableArray *_p4=[[NSMutableArray alloc]init];
//初始值
NSLog(@"init p1:%@,%p,%p",_p1,_p1,&_p1);
NSLog(@"init p2:%@,%p,%p",_p2,_p2,&_p2);
NSLog(@"init p3:%d,%p",_p3,&_p3);
NSLog(@"init p4:%@,%p,%p",_p4,_p4,&_p4);
void (^myBlock)(NSString *,NSString **,int,NSMutableArray *) = ^(NSString *p1,NSString **p2,int p3,NSMutableArray * p4) {
//block内赋值
p1=@"";
*p2=@"";
p3=;
[p4 addObject:@""];
NSLog(@"excuteing p1:%@,%p,%p",p1,p1,&p1);
NSLog(@"excuteing p2:%@,%p,%p,%p",*p2,*p2,p2,&p2);
NSLog(@"excuteing p3:%d,%p",p3,&p3);
NSLog(@"excuteing p4:%@,%p,%p",p4,p4,&p4);
};
myBlock(_p1,&_p2,_p3,_p4);
//block执行后
NSLog(@"excuteafter p1:%@,%p,%p",_p1,_p1,&_p1);
NSLog(@"excuteafter p2:%@,%p,%p",_p2,_p2,&_p2);
NSLog(@"excuteafter p3:%d,%p",_p3,&_p3);
NSLog(@"excuteafter p4:%@,%p,%p",_p4,_p4,&_p4);
}

输出日志:

-- ::06.774 Test[:60b] init p1:hello world11,0x16537b20,0x27df8990
-- ::06.776 Test[:60b] init p2:hello world12,0x1652d760,0x27df898c
-- ::06.778 Test[:60b] init p3:,0x27df8988
-- ::06.779 Test[:60b] init p4:(
),0x1652b6d0,0x27df8984
-- ::06.781 Test[:60b] excuteing p1:,0x11a08,0x27df893c
-- ::06.782 Test[:60b] excuteing p2:,0x11a18,0x27df897c,0x27df8938
-- ::06.783 Test[:60b] excuteing p3:,0x27df8934
-- ::06.784 Test[:60b] excuteing p4:( ),0x1652b6d0,0x27df8930
-- ::06.785 Test[:60b] excuteafter p1:hello world11,0x16537b20,0x27df8990
-- ::06.786 Test[:60b] excuteafter p2:,0x11a18,0x27df898c
-- ::06.787 Test[:60b] excuteafter p3:,0x27df8988
-- ::06.788 Test[:60b] excuteafter p4:( ),0x1652b6d0,0x27df8984

从日志可以看出:

  • 我们把指针_p1(NSString *)传入block,传参数的过程其实可以理解为用新的指针指向  _p1所指向的内存地址。这时候在block内部修改指针指向,只是修改了block形参的指针的指向,所以block内部p1的内容和block外部_p1的不一样。
  • 我们把指针_p4(NSMutableArray *)传入block,传参数的过程和上面一样,用了一个新的指针指向  参数所指向的内存地址,在block内部对 形参指针指向的内存进行修改,即操作的是同一片内存,所以能同步到block外部。
  • 我们把指针_p2(NSString **)传到了block内部,传递的是指针的地址,我们在block内部修改*p2,其实是修改 指针p2 指向的指针  指向的内存地址,也能同步到block外部。
  • 因为_p3是值传递,所以block内部修改不会影响外部,这个和函数一样。

我们来看看block对行参变量的处理:

这是block结构体,并没有生成成员 对形参进行引用

struct __KDBlockTest__test3_block_impl_0 {
struct __block_impl impl;
struct __KDBlockTest__test3_block_desc_0* Desc;
__KDBlockTest__test3_block_impl_0(void *fp, struct __KDBlockTest__test3_block_desc_0 *desc, int flags=) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};

我们看block实现的函数,对变量的访问,都是通过形参来实现的,并没有通过结构体的成员

static void __KDBlockTest__test3_block_func_0(struct __KDBlockTest__test3_block_impl_0 *__cself, NSString *p1, NSString **p2, int p3, NSMutableArray *p4) {

        p1=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_9;
*p2=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_10;
p3=23;
((void (*)(id, SEL, id))(void *)objc_msgSend)((id)p4, sel_registerName("addObject:"), (id)(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_11);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_12,p1,p1,&p1);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_13,*p2,*p2,p2,&p2);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_14,p3,&p3);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_15,p4,p4,&p4);
}

下面是我们的测试函数,看红色部分,是通过函数参数传递,和函数调用一样,和block内使用局部变量、静态变量、成员变量还是有很大区别的,并没有截获变量。

static void _I_KDBlockTest_test3(KDBlockTest * self, SEL _cmd) {
NSString *_p1=((NSString *(*)(id, SEL, NSString *, ...))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("stringWithFormat:"), (NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_1, (NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_2);
NSString *_p2=((NSString *(*)(id, SEL, NSString *, ...))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("stringWithFormat:"), (NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_3, (NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_4);
int _p3=;
NSMutableArray *_p4=((id (*)(id, SEL))(void *)objc_msgSend)((id)((id (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSMutableArray"), sel_registerName("alloc")), sel_registerName("init")); NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_5,_p1,_p1,&_p1);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_6,_p2,_p2,&_p2);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_7,_p3,&_p3);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_8,_p4,_p4,&_p4);
void (*myBlock)(NSString *,NSString **,int,NSMutableArray *) = (void (*)(NSString *, NSString **, int, NSMutableArray *))&__KDBlockTest__test3_block_impl_0((void *)__KDBlockTest__test3_block_func_0, &__KDBlockTest__test3_block_desc_0_DATA);
((void (*)(__block_impl *, NSString *, NSString **, int, NSMutableArray *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock, _p1, &_p2, _p3, _p4);//block 执行 NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_16,_p1,_p1,&_p1);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_17,_p2,_p2,&_p2);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_18,_p3,&_p3);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_654672_mi_19,_p4,_p4,&_p4);
}

总结:

  • 对于block形参,block不会对形参、实参强引用,调用是通过参数传递实现的(block结构体内部没有成员引用)
  • 和函数调用一样,block内部可以修改形参,并且影响到实参。

block 解析 - 形参变量的更多相关文章

  1. block 解析 - 成员变量

    回顾 在 上一篇 中我们讲了截获变量特性,对于局部变量,变量不加__block修饰符,在block内部是无法修改变量的值.而且 对值类型的修改,如果block初始化后,无法同步到block内部 对于指 ...

  2. block 解析 - 静态变量

    静态变量 上一篇 我们了解了block全局变量的使用,静态变量和全局变量一样,可以直接在block内部使用,也可以在block内部修改 引用官方文档: Global variables are acc ...

  3. 深入研究Block捕获外部变量和__block实现原理

    Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这个新功能“Blocks”.从那开始,Block就出现在iOS和Mac系统各个API中,并被大 ...

  4. iOS中Block的用法,举例,解析与底层原理(这可能是最详细的Block解析)

    1. 前言 Block:带有自动变量(局部变量)的匿名函数.它是C语言的扩充功能.之所以是拓展,是因为C语言不允许存在这样匿名函数. 1.1 匿名函数 匿名函数是指不带函数名称函数.C语言中,函数是怎 ...

  5. Block解析(iOS)

    1. 操作系统中的栈和堆 我们先来看看一个由C/C++/OBJC编译的程序占用内存分布的结构: 栈区(stack):由系统自动分配,一般存放函数参数值.局部变量的值等.由编译器自动创建与释放.其操作方 ...

  6. block捕获自动变量和对象

    一.捕获自动变量值 首先看一个经典block面试题: int val = 10; void (^blk)(void) = ^{printf("val=%d\n",val);}; v ...

  7. block 解析 - 内存

    block结构体相应的也有一个成员引用,这样会增加对局部变量的 _para1引用,在Block销毁的时候引用就释放掉了 我们了解到了用__block修饰的变量,可以在block内部修改,__block ...

  8. block 解析 - 局部变量

    局部变量 block内使用局部变量,一般都是截获变量(只读),截获离block初始化最近的一次的值. 引用官方文档: Stack (non-static) variables local to the ...

  9. block 解析 - 简介

    简介 block 类似标准的c函数,除了一些函数体一些可执行的代码,还可以把变量绑定到自动栈或者托管堆上.....和js里的闭包.c# lambda表达式有些类似,实质是一个函数指针.与函数指针的区别 ...

随机推荐

  1. HDU 2227 Find the nondecreasing subsequences

    题目大意:给定一个序列,求出其所有的上升子序列. 题解:一开始我以为是动态规划,后来发现离散后树状数组很好做,首先,c保存的是第i位上升子系列有几个,那么树状数组的sum就直接是现在的答案了,不过更新 ...

  2. Apache 错误代码配置

    ErrorDocument 400 /error_pages/400.htmlErrorDocument 401 /error_pages/401.htmlErrorDocument 403 /err ...

  3. The Longest Straight(二分,离散化)

     Problem 2216 The Longest Straight Accept: 7    Submit: 14 Time Limit: 1000 mSec    Memory Limit : 3 ...

  4. 2014-CVTE网测部分软件技术测试题及答案

    1.叉树的先序遍历序列和后序遍历序列正好相反,则该二叉树满足的条件是(D) A.空或只有一个结点 B.高度等于其结点数 C.该二叉树是完全二叉树 D.所有结点无右孩子 应该是二叉树的每个结点都只有一个 ...

  5. malloc、calloc、realloc三者的差别

    1.malloc 作用:分配内存块 原型:void *malloc(size_t size);size表示要分配的字节数 返回值:返回一个指向所分配空间的void指针,假设没有足够的内存可用,则返回N ...

  6. 详解iOS开发之自定义View

    iOS开发之自定义View是本文要将介绍的内容,iOS SDK中的View是UIView,我们可以很方便的自定义一个View.创建一个 Window-based Application程序,在其中添加 ...

  7. HDU4451Dressing(计数)

    HDU4451Dressing(计数) 题目链接 题目大意:给你N件衣服, M条裤子, K双鞋子,如今有P个不合理的的搭配(衣服和裤子或者裤子和鞋子),要求不用P中不理的搭配方式来将衣服裤子鞋子三件搭 ...

  8. 建立&修改视图

    一.建立视图 IF OBJECT_ID('Sales.OrderTotalsByYear', 'V') IS NOT NULL DROP VIEW Sales.OrderTotalsByYear; G ...

  9. [译]Stairway to Integration Services Level 14 - 项目转换(SSIS 2008 ~ SSIS 2012)

    介绍 本文中我们会用SSDT把第一个SSIS项目转换为 SSIS 2012, 为什么要升级到2012? 你可能想使用SSIS 2012新的特性. 又或者想使用 SSIS 2012 Catalog. 想 ...

  10. nginx根据条件跳转+跳转规则

    好的参考博文: nginx rewrite规则 自己写的时候参考这两个 Nginx 伪静态Rewrite,重定向Location配置总结(转) nginx rewrite规则语法 一.输入子目录跳转 ...