block基础使用语法
 
一、block与函数的对比
定义函数指针

int (*myFn)();

定义Blocks

int (^MyBlocks)(int,int);

调用函数指针

(*myFn)(10, 20);

l调用Blocks

MyBlocks(10, 20)

 
 

二、Block 语法:

1.作为当地变量:

returnType (^blockName)(parameterTypes) = ^returnType(parameters) { ... ... }

2.作为属性:

@property (nonatomic,copy) returnType (^blockName)(parameterTypes)

3.作为方法参数:

-(void)someMethodThatTakesABlock:( returnType (^)(parameterTypes) )blockName

4.作为方法调用的参数:

[someObject someMethodThatTakesABlock:^returnType(parameters){ ... ... } ];

5.作为typeDef:

typedef returnType(^typeName)(parameterTypes)

TypeName blockName = ^returnType(parameters) { ... ... };

例子:

block要掌握的东西

1> 如何定义block变量

int (^sumBlock)(int, int);

void (^myBlock)();

2> 如何利用block封装代码

^(int a, int b) {

return a - b;

};

^() {

NSLog(@"----------");

};

^ {

NSLog(@"----------");

};

3> block访问外面变量

* block内部可以访问外面的变量

* 默认情况下,block内部不能修改外面的局部变量

* 给局部变量加上__block关键字,这个局部变量就可以在block内部修改

* block访问全局变量时应先把全局变量赋值给局部变量

3.1>循环引用:

block 被copy之后,该block会对他捕获到的对象产生Strong引用,如果self引用的block,block捕获了self,将会造成内存循环

解决方法

__weak weakSelf = self;

__weak typeof(self) weakSelf = self(弱引用);

4> 利用typedef定义block类型

typedef int (^MyBlock)(int, int);

// 以后就可以利用MyBlock这种类型来定义block变量

MyBlock block;

MyBlock b1, b2;

b1 = ^(int a, int b) {

return a - b;

};

MyBlock b3 = ^(int a, int b) {

return a - b;

};

 
 
 
Block底层的关键字提示:函数指针 回调
 
Block内部实现
【浅显的说就是 ->创建Block时,内部就是创建一个对应的函数;调用Block,内部调用了之前封装的函数 它的实质是函数指针 void(*
block)() ,实现的核心就是回调】
利用LLVM编译器 ->clang命令 [打开终端 cd 你的文件 然后clang你需要的.m文件
  • 开始解释正文:

    //举例演示:
    int a = 10;
    __block int b = 20;
    void (^block)() = ^(){
    printf("a = %d\n",a);
    printf("b = %d\n",b);
    };
    a = 50;
    b = 30;
    block();
    //常用的runtime中终端clang命令  clang -rewrite-objc main.m 结果:
    int main(int argc, const char * argv[]) {
    int a = 10;
    //__block修饰,封装到结构体__Block_byref_b_0
    __attribute__((__blocks__(byref))) __Block_byref_b_0 b = {(void*)0,(__Block_byref_b_0 *)&b, 0, sizeof(__Block_byref_b_0), 20};
    //传入到结构体struct __main_block_impl_0 的__main_block_impl_0(...){...}中
    void (*block)() = (void(*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a, (__Block_byref_b_0 *)&b, 570425344);
    a = 50;
    //结构体属性值重新指向
    (b.__forwarding->b) = 30;
    //获取结构体属性FuncPtr。也就是封装后的block方法体。然后传入block实例,执行打印
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    return 0;
    }

-----------> 分析编译出来的C++代码
-->1、

__attribute__((__blocks__(byref))) __Block_byref_b_0 b = {(void*)0,(__Block_byref_b_0 *)&b, 0, sizeof(__Block_byref_b_0), 20};

参数:

 (void*)0
(__Block_byref_b_0 *)&b
0
sizeof(__Block_byref_b_0)
20

把b的值 封装到 Block_byref_b_0结构体中。【block修饰的值装在封装的结构体中】

struct __Block_byref_b_0 {
void *__isa; //当前对象指针
__Block_byref_b_0 *__forwarding; //当前结构体指针,__forwarding 存储自己地址。用__block修饰便执行
int __flags; //标记
int __size; // 结构体大小
int b; // 值
};

-->2、传递到结构体中的方法里

void (*block)() = (void(*)())&__main_block_impl_0(
(void *)__main_block_func_0, &__main_block_desc_0_DATA, a, (__Block_byref_b_0 *)&b, 570425344
);

传递:

(void *)__main_block_func_0   // 存储block方法体【这里就是两条打印】,下文的 *fp
&__main_block_desc_0_DATA // 地址,block的描述数据
a // 值传递
(__Block_byref_b_0 *)&b //传递 b的地址,结构体包装
570425344

到:block的实例方法

struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int a; // 10
__Block_byref_b_0 *b; // by ref //调用这个方法,方法的实现在括号内.上文传递的参数在此赋值
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, __Block_byref_b_0 *_b, int flags=0) : a(_a), b(_b->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp; //执行的代码 打印。__main_block_func_0
Desc = desc;
}
}

block内的方法封装到这里

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_b_0 *b = __cself->b; // bound by ref
int a = __cself->a; // bound by copy
printf("a = %d\n",a);
printf("b = %d\n",(b->__forwarding->b));
} struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};

-->3、

a = 50;
(b.__forwarding->b) = 30;
//这里的b 是 __Block_byref_b_0 b
//在结构体中获得属性__forwarding,并给它指向值 30;

//特别提醒:
使用__block 就是传地址 / 不使用就是传值
反编译成C++ 后发现,当使用了__block 修饰对象的时候,都会封装成一种类型的结构体。

block的简单实用:http://blog.csdn.net/u014536527/article/details/50378586

block的高级:http://blog.devtang.com/2013/07/28/a-look-inside-blocks/

block基本使用和底层的更多相关文章

  1. Block详解二(底层分析)

    Block专辑: Block讲解一 MRC-block与ARC-block Block详解一(底层分析) 今天讲述Block的最后一篇,后两篇仅仅是加深1,2篇的理解,废话少说,开始讲解! __blo ...

  2. Block详解一(底层分析)

    本篇博客不再讲述Block的基本定义使用,最近而是看了很多的block博客讲述的太乱太杂,所以抽出时间整理下block的相关底层知识,在讲述之前,提出几个问题,如果都可以回答出来以及知道原理,大神绕过 ...

  3. block的那些事(从懵懂到使用)

    从大学开始自学iOS,在iOS岗位已经两年了,遇到传值等操作,代理和block二选一的话,以前我会毫不犹豫选择代理.久而久之,入职到大公司之后,发现处处是block的天地,才慢慢的了解block并爱上 ...

  4. IOS并发编程GCD

    iOS有三种多线程编程的技术 (一)NSThread  (二)Cocoa NSOperation (三)GCD(全称:Grand Central Dispatch) 这三种编程方式从上到下,抽象度层次 ...

  5. MIT jos 6.828 Fall 2014 训练记录(lab 5)

    源代码参见我的github: https://github.com/YaoZengzeng/jos File system perliminaries 我们开发的是一个单用户的操作系统,只提供了足够的 ...

  6. IOS多线程(GCD)

    简介 Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首次 ...

  7. iOS - Threads 多线程

    1.Threads 1.1 进程 进程是指在系统中正在运行的一个应用程序.每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 比如同时打开 QQ.Xcode,系统就会分别启动两个进程. ...

  8. GCD常用剖析

    介绍:Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首次 ...

  9. IOS 多线程编程之Grand Central Dispatch(GCD)介绍和使用 多线程基础和练习

    介绍:前面内容源自网络 Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式 ...

随机推荐

  1. PPP点到点协议&pap验证

    RA RB

  2. 实战入侵(突破FCK+安全狗上传)

    PS:有点尴尬,二次上传突破FCK,免杀马儿过狗. 刚开始和超霸一起弄,TMDGB.弄到四点多,早上尼玛七点多的又去考试,虽然考试还是睡着了,但是TMDGB感觉日子好充实啊! FCK上传地址如下所示: ...

  3. git工作流教程

    简介:在用git进行开发时,需要规范化,这时用git工作流来规范化,软件开发过程 https://github.com/oldratlee/translations/blob/master/git-w ...

  4. LeetCode103 BinaryTreeZigzagLevelOrderTraversal(二叉树Z形层次遍历) Java题解

    题目: Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from lef ...

  5. Yarn NodeManager restart

    一.介绍默认Yarn NodeManager重启后会断开所有当前正在运行的container的状态,这意味着重启后需要重新启动container进程,该特性的作用就是把NM的状态临时保存到本地,重启后 ...

  6. nginx日志分析利器GoAccess(转)

    面试的时候一定会被面到的问题是:给出web服务器的访问日志,请写一个脚本来统计访问前10的IP有哪些?访问前10的请求有哪些?当你领略过goaccess之后,你就明白,这些问题,除了考验你的脚本背诵记 ...

  7. 去掉iPhone、iPad的默认按钮样式

    只要在样式里面加一句去掉css去掉iPhone.iPad的默认按钮样式就可以了!~ input[type="button"], input[type="submit&qu ...

  8. oracle DataGuard 主从 踩过坑的

    一.主机描述 dbprimary: 192.168.1.57 主机名称db1    dbstandby: 192.168.1.58 主机名成db2    SID: orcl 二.配置tns,配置好的文 ...

  9. xss 防止攻击,恶意用户将输入的信息当成html或js代码执行,办法是将用户输入的信息改为text格式,或特殊符号转义

    xss 防止攻击,恶意用户将输入的信息当成html或js代码执行,办法是将用户输入的信息改为text格式,或特殊符号转义 XSS攻击的防范 XSS攻击造成的危害之所以会发生,是因为用户的输入变成了可执 ...

  10. NODE_PATH的疑难杂症(转)

    nodejs 中的 NODE_PATH 在使用 nodejs 开发中我们都免不了要去安装一些第三方模块. 那么你或多或少的遇到过以下一些问题 再继续阅读之前,我们先来弄清楚一个概念. npm inst ...