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. 未能加载文件或程序集Office,Version=11.0.0.0

    关于"未能加载文件或程序集“Office, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”或它的某一个 ...

  2. spi 总线协议记录

    摘抄至: http://blog.csdn.net/skyflying2012/article/details/11710801 概述: SPI, Serial Perripheral Interfa ...

  3. 支持向量机(SVM)(三)-- 最优间隔分类器(optimal margin classifier)

    在之前为了寻找最有分类器,我们提出了例如以下优化问题: 在这里我们能够把约束条件改写成例如以下: 首先我们看以下的图示: 非常显然我们能够看出实线是最大间隔超平面,如果×号的是正例,圆圈的是负例.在虚 ...

  4. 关于c# 发射的调用并进行缓存

    private static object CreateObject(string AssemblyPath, string classNamespace) { object objObject = ...

  5. Hibernate- QBC查询方式

    QBC查询方式 01.基本查询 02.组合查询 03.关联查询 04.分页查询 05.QBE查询 06.离线查询

  6. Framework 7 之 Smart select 选择后自动隐藏

    Framework 7官网地址:Framework 7(英文版) Framework 7(中文版) 给“smart-select”添加属性  data-back-on-select="tru ...

  7. glob函数 循环遍历子目录下的文件

    <?php foreach (glob("ueditor\php\upload\image\*\*.png") as $filename) { echo "$fil ...

  8. CMutex、CCriticalSection、CSemaphore、CEvent、WaitForSingleObject 的小例子

    一.CMutex CMutex mutex; mutex.Lock(); // 互斥的动作 // mutex.Unlock(); 二.CCriticalSection CCriticalSection ...

  9. e1087. try/catch语句

    The try/catch statement encloses some code and is used to handle errors and exceptions that might oc ...

  10. if、for、while、do 等语句自占一行

    if.for.while.do 等语句自占一行,执行语句不得紧跟其后.不论 执行语句有多少都要加{}.这样可以防止书写失误. #include <iostream> /* run this ...