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. C# Winform获取bin目录的路径

    //获取到bin目录的下层路径:bin\Debug\ string aa = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBa ...

  2. 关于使用samba用户的权限设置

    首先要保证你的samba安装并配置好,关于安装和配置samba请参考此文章http://blog.csdn.net/linglongwunv/archive/2010/01/19/5212875.as ...

  3. Bootstrap3.0 栅格系统背后的精妙魔法(Bootstrap3.0的栅格布局系统实现原理)

    这个标题取的有点奇怪,怪我翻译的有问题吧.英文学平有限,有道词典和google翻译齐上阵是必须的.还好翻译的不是小说,对于技术文章,还是能勉强翻过来的. 本文主要讲解了Bootstrap3.0的栅格布 ...

  4. hdu3065 病毒侵袭持续中 AC自动机入门题 N(N <= 1000)个长度不大于50的模式串(保证所有的模式串都不相同), 一个长度不大于2000000的待匹配串,求模式串在待匹配串中的出现次数。

    /** 题目:hdu3065 病毒侵袭持续中 链接:http://acm.hdu.edu.cn/showproblem.php?pid=3065 题意:N(N <= 1000)个长度不大于50的 ...

  5. c#生成rsa公钥和私钥

    c#生成rsa公钥和私钥的类库,包括加密解密,可以用在网站和winform项目 源码地址: http://download.csdn.net/detail/jine515073/8383809

  6. iOS边练边学--九宫格布局

    一.介绍一下ViewController中的结构 二.九宫格设计思路 三.代码实现 // 点击增加按钮 - (void)add:(UIButton *)btn { // 定义一行中的列数(个数) NS ...

  7. JSON教程

    一.什么是JSON 1.JSON指的是JavaScript对象表示法(JavaScript Object Notation). 2.JSON是轻量级的文本数据交换格式,比XML更小.更快.更易解析. ...

  8. SpringMVC & SpringBoot小记

    SpringMVC 1.SpringMVC常用注解 https://blog.csdn.net/lipinganq/article/details/79155072 :@Component.@Serv ...

  9. 关于Cocos2d-x中节点的获取

    方法一: 1.在.h文件的属性里面先声明要使用的节点或者变量. private: Label *scorelabel; 2.在.cpp文件中创建并使用这个节点或者变量. scorelabel = La ...

  10. Oracle-05-SQL语句概述、分类&amp;SQL*PLUS概述(初识insert,desc,list,r,del,a,c,n等命令)

    一.SQL语句概述 (1)SQL全程是"结构化查询语言(Structured Query Language)". SQL是大多数主流数据库系统採用的标准查询语言. (2)SQL语句 ...