「OC」小白书读书笔记——Block的相关知识(上)

【OC】block的实现 Block语法实际上是作为极普通的C语言代码来处理的。通过支持Block的编译器,含有Block语法的源代码转换为一般C语言编译器能够处理的源代码,并作为极为普通的C语言源代码被编译。这只不过是概念的问题,在实际编译时无法转换成我们能够理解的源码,但clang具有转换成我们可读源代码的功能。通过“-rewrite-objc”选项就能将含有block语法的源代码转换为C++的源代码。说是C++,其实尽是使用了struct结构,其本质是C语言的源代码。clang -rewrite-objc 源代码文件名。 阅读详情

「OC」小白书读书笔记——Block的相关知识(上)

前言

在之前的OC学习之中使用了很多关于Block的内容,包括但不限于网络请求后的回调操作,block的跨界面传值等,但是本人还是对block这个概念比较模糊,于是就在网上学习一些相关的知识进行补充

Block的底层实现

我们在main函数之中写下以下代码

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        void(^block)(void) = ^{
                    printf("block~~~\n");
                };
        block();
    }
    return 0;
}

首先我们进入当前文件之中,使用命令行命令clang main.m -rewrite-objc -o dest.cpp,将我们的main.m转化为c++文件,去除前置性的代码,我们以上的OC代码转化为以下内容

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __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;
  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; 
        void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

我们暂且抛开那些复杂的修饰符,我们先看总体的程序本身

//这一段是构造函数,创建并返回一个对象,相当于OC之中的init
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __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;
  }
};

关于__block_impl我们可以在文件之中找到它的定义

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

看了构造函数本身,再来看看构造函数的调用,我们直接化简得到

struct __main_block_imp1_0 tmp = __main_block_impl_0 ( __main_block_func_0, &__main_block_desc_0_DATA) ;
struct __main_block_imp1_0 *blk = &tmp;

//直接对应void (^blk) (void) - ^(printf ("Block\n*); };

假设我们这个block之中捕获了一个类型为int的age变量,这个block的C语言实现如下

16f8481974bfbfae~tplv-t2oaga2asx-jj-mark-3024-0-0-0-q75

//分装block之中的相关操作语句
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    printf("block~~~\n");
    }

impl->isa:就是isa指针,可见它就是一个OC对象。

impl->FuncPtr:是一个函数指针,也就是底层将block中要执行的代码封装成了一个函数,然后用这个指针指向那个函数。

Desc->Block_size:block占用的内存大小。

age:捕获的外部变量age,可见block会捕获外部变量并将其存储在block的底层结构体中。

在main函数当中:

//调用函数返回block对象
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
//执行创建block之后的FuncPtr方法
 ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

全局变量的捕获

我们给出以下代码

int c = 1000; // 全局变量
static int d = 10000; // 静态全局变量

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        int a = 10; // 局部变量
        static int b = 100; // 静态局部变量
        void (^block)(void) = ^{
             NSLog(@"a = %d",a);
             NSLog(@"b = %d",b);
             NSLog(@"c = %d",c);
             NSLog(@"d = %d",d);
         };
         a = 20;
         b = 200;
         c = 2000;
         d = 20000;
         block();
    }
    return 0;
}

// ***************打印结果***************
2020-01-07 15:08:37.541840+0800 CommandLine[70672:7611766] a = 10
2020-01-07 15:08:37.542168+0800 CommandLine[70672:7611766] b = 200
2020-01-07 15:08:37.542201+0800 CommandLine[70672:7611766] c = 2000
2020-01-07 15:08:37.542222+0800 CommandLine[70672:7611766] d = 20000

通过将代码转化为C++我们可以看到

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int a;
  int *b;
};

block里面打印了四个变量,但是最后却只捕获了两个,这是怎么回事呢?

全局变量的捕获

因为全局变量,无论静态全局变量或者是普通全局变量,在哪里都可以被直接访问,所以在block内部即便是不捕获也是可以直接访问的,所以在我们通过block打印这些变量的值时,就是最新更改的值

静态局部变量的捕获

我们发现定义的静态局部变量b被block捕获后,在block结构体里面是以int *b;的形式来存储的,也就是说block其实是捕获的变量b的地址,block内部是通过b的地址去获取或修改b的值,所以block外部更改b的值会影响block里面获取的b的值,block里面更改b的值也会影响block外面b的值。所以上面会打印b = 200。

普通局部变量的捕获

所谓的普通局部变量就是在一个函数或代码块中定义的类似int a = 10;的变量,它其实是省略了auto关键字,等价于auto int a = 10,所以也叫auto变量。和静态局部变量不同的是,普通局部变量被block捕获后再block底层结构体中是以int a;的形式存储,也就是说block捕获的其实是a的值(也就是10),并且在block内部重新定义了一个变量来存储这个值,这个时候block外部和里面的a其实是2个不同的变量,所以外面更改a的值不会影响block里面的a。所以打印的结果是a = 10。

至于为什么使用一个变量直接存取,而不是跟静态局部变量一样用一个指针存储呢?其实道理很简单,就是普通局部变量出了main函数就会被释放。

那为什么静态局部变量一直都不会被释放,那block为什么还要捕获它,直接拿来用不就可以了吗?这其实就是在作用域外,我们无法直接从外面去访问这个静态局部变量。

变量捕获小结

  • 全局变量–不会捕获,是直接访问。
  • 静态局部变量–是捕获变量地址。
  • 普通局部变量–是捕获变量的值。

那么我们来判断一下,以下代码中的block是否捕获了self

- (void)blockTest{
    
    // 第一种
    void (^block1)(void) = ^{
        NSLog(@"%p",self);
    };
    
    // 第二种
    void (^block2)(void) = ^{
        self.name = @"Jack";
    };
    
    // 第三种
    void (^block3)(void) = ^{
        NSLog(@"%@",_name);
    };
    
    // 第四种
    void (^block4)(void) = ^{
        [self name];
    };
}

其实要回答这个问题,实际上就是探究self究竟是局部变量还是全局变量。我们可以联想到我们学习OC方法调用之中的objc_msgSend,比如我调用[self blockTest],它转成C语言后就变成了objc_msgSend(self, @selector(blockTest))。其实就不难看出我们是通过传参才能够使得方法能够正确获取调用对象。作为函数参数,self 存储在栈帧中,只在方法调用期间存在,并在方法执行完毕后自动销毁。

这个问题解决了,那上面几种情况就简单了,这4中情况下block都会捕获self。

block类型总结

前面我们知道,block的结构体之中时候isa指针的,这其实意味着,block其实是作为一个类存在的,那我们就来探究一下block的类。

以其他人博客之中为例子:

- (void)test{
    int age = 10;
    
    void (^block1)(void) = ^{
        NSLog(@"-----");
    };
    NSLog(@"block1的类:%@",[block1 class]);
    
    NSLog(@"block2的类:%@",[^{
        NSLog(@"----%d",age);
    } class]);
    
   NSLog(@"block3的类:%@",[[^{
       NSLog(@"----%d",age);
   } copy] class]);
}

// ***************打印结果***************
 block1的类:__NSGlobalBlock__
 block2的类:__NSStackBlock__
 block3的类:__NSMallocBlock__

image-20250220233000621

__NSGlobalBlock__

如果一个block之中没有访问任何变量,那这个block就是__NSGlobalBlock__。__NSGlobalBlock__类型的block在内存中是存在数据区的(也叫全局区或静态区,全局变量和静态变量是存在这个区域的)。__NSGlobalBlock__类型的block调用copy方法的话什么都不会做。其实就是相当于一个单例。我们简单的探究一下这个类的继承链

- (void)test{
    void (^block)(void) = ^{
        NSLog(@"-----");
    };
    NSLog(@"--- %@",[block class]);
    NSLog(@"--- %@",[[block class] superclass]);
    NSLog(@"--- %@",[[[block class] superclass] superclass]);
    NSLog(@"--- %@",[[[[block class] superclass] superclass] superclass]);
}

// ***************打印结果***************
--- __NSGlobalBlock__
--- __NSGlobalBlock
--- NSBlock
--- NSObject

__NSStackBlock__

如果一个block里面访问了普通的局部变量,那它就是一个__NSStackBlock__,顾名思义,它在内存中存储在栈区,栈区的特点就是其释放不受开发者控制,都是由系统管理释放操作的,所以在调用__NSStackBlock__类型block时要注意,一定要确保它还没被释放。

- (void)test{
  	int age;
    void (^block)(void) = ^{
        NSLog(@"----%d",age);
    };
    NSLog(@"--- %@",[block class]);
    NSLog(@"--- %@",[[block class] superclass]);
    NSLog(@"--- %@",[[[block class] superclass] superclass]);
    NSLog(@"--- %@",[[[[block class] superclass] superclass] superclass]);
}

// ***************打印结果***************
--- __NSStackBlock__
--- __NSStackBlock
--- NSBlock
--- NSObject

__NSMallocBlock__

一个__NSStackBlock__类型block做调用copy,那会将这个block从栈复制到堆上,堆上的这个block类型就是__NSMallocBlock__,所以__NSMallocBlock__类型的block是存储在堆区。如果对一个__NSMallocBlock__类型block做copy操作,那这个block的引用计数+1。那其实就是一个在堆区指向栈区内存的指针

__NSMallocBlock__的继承链是:__NSMallocBlock__ : __NSMallocBlock : NSBlock : NSObject。

以下四种操作自动将栈上的 block 复制到堆上

1. Block 作为函数/方法的返回值时

当一个 block 作为返回值从一个方法返回时,编译器会自动复制它到堆上。例如:

typedef void (^MyBlock)(void);

- (MyBlock)createBlock {
    int a = 10;
    return ^{
        NSLog(@"****** %d", a);
    };
}

说明:

  • 虽然代码中看起来直接返回的是一个栈上 block,但因为它是返回值,所以编译器会在返回前自动调用 copy 操作,将其从栈复制到堆上。

2. 将 Block 赋值给强引用(strong)时

如果你将一个栈上的 block 赋值给一个使用 strong 修饰符的变量,编译器同样会自动复制到堆上。例如:

- (void)test {
    int a = 10;
    // 定义一个 block,并赋值给一个强指针变量 myBlock
    void (^myBlock)(void) = ^{
        NSLog(@"a = %d", a);
    };
    myBlock(); // 调用 block
}

说明:

  • 当 block 被赋值给一个 strong 类型的变量时,ARC 会确保 block 的内存安全,因此自动将其复制到堆上。

3. 当 Block 作为参数传给 Cocoa API 时

许多 Cocoa API 都要求传入的 block 必须是堆上的 block。如果你传入一个栈上的 block,系统会自动对其进行复制。例如:

[UIView animateWithDuration:1.0f animations:^{
    // 这里传入的 block 会被自动复制到堆上
}];

说明:

  • Cocoa 框架内部会对传入的 block 做 copy 操作,从而保证异步动画执行期间 block 不会失效。

4. 当 Block 作为参数传给 GCD(Grand Central Dispatch)API 时

GCD 的 API 也要求 block 必须在堆上,这样才能在异步执行中长期有效。例如:

dispatch_async(dispatch_get_main_queue(), ^{
    // 传递给 GCD 的 block 会自动从栈复制到堆上
});

说明:

  • 在调用诸如 dispatch_async 等 GCD API 时,编译器会自动将 block 复制到堆上,以便在调度队列中安全使用。

区别

我们想要分清_NSConcreteGlobalBlock和_NSConcreteStackBlock,小白书还给出了一个有趣的例子

例子 a:捕获自动变量
typedef int (*blk_t)(int);
for (int rate = 0; rate < 10; ++rate) {
    blk_t blk = ^(int count) {
        return rate * count;
    };
}
  • 解释:
    在这个例子中,Block 内部使用了 rate 这个变量。由于 rate 是 for 循环的局部变量,每次循环时 rate的值不同,所以每个 Block 实例都需要捕获当前的 rate 值。
  • 结果:
    尽管 Block 的语法看起来一样,但因为捕获了不同的局部变量值,所以在每次循环中生成的 Block 实例都是不同的,它们属于 _NSConcreteStackBlock 类型(或者当被复制到堆上后,可能是 _NSConcreteMallocBlock)。
例子 b:不捕获自动变量
typedef int (*blk_t)(int);
for (int rate = 0; rate < 10; ++rate) {
    blk_t blk = ^(int count) {
        return count;
    };
}
  • 解释:
    这个例子中,Block 内部没有使用任何外部的自动变量(如 rate),因此不需要捕获任何上下文。
  • 结果:
    这种 Block 的内容在编译时就已经固定下来,可以放置在程序的数据区中,与全局变量类似。整个程序中,只需要一个 Block 实例,这个 Block 的类别为 _NSConcreteGlobalBlock。

Block 属性在 MRC 与 ARC 下的写法区别

在 MRC 环境下
  • 建议使用 copy
    因为在 MRC 中,栈上的 block 不会自动复制到堆上,所以在定义 block 属性时必须使用 copy 关键字:

    @property (copy, nonatomic) void(^block)(void);
    

    原因:

    • 只有 copy 属性能确保 block 被复制到堆上,否则可能会出现因栈内存释放而导致的崩溃或未定义行为。
在 ARC 环境下
  • copy 与 strong 均可
    在 ARC 环境中,无论你使用 copy 还是 strong 修饰 block 属性,编译器都会自动将栈上的 block复制到堆上:

    @property (strong, nonatomic) void (^block)(void);
    @property (copy, nonatomic) void (^block)(void);
    

    说明:

    • 两种写法都能保证 block 在赋值时正确复制到堆上,因此在 ARC 下二者效果相同。不过,为了表明语义(即 block 需要复制),我们还是仍然倾向于使用 copy。

总结

本文大致讲了一些block在OC底层用C的实现,用了例子大致的了解了block捕获变量的底层机制,以及block三种类型的具体区别。

因为小白书之中的block内容大多数都是探究其OC的底层实现,不太熟悉,还是有些费时费力,先将一部分整理出来,巩固一下再总结下半部分的笔记吧

参考文章

OC中block的底层实现原理

OC底层知识点之 - Block底层原理

oc block详解 oc block详解 我们知道在Block使用中,Block内部能够读取外部局部变量的值。但我们需要改变这个变量的值时,我们需要给它附加上__block修饰符。__block另外一个比较多的使用场景是,为了避免某些情况下Block循环引用的问题,我们也可以给相应对象加上__block 修饰符。今天为大家详细讲解Block实现的详细过程 block的实际结构 block的类型 block是如何捕捉变量 阅读详情

相关推荐

重学OC第二十三篇:block

文章目录一、Block是什么?1.1 __block二、Block源码分析 一、Block是什么? int main(int argc, const char * argv[]) { int a = 0; void (^aBlock)(void) = ^{ NSLog(@"%d", a); }; aBlock(); } 用clang转为cpp Block是带有自动变量(局部变量)的匿名函数,但在OC中Block本质上就是一个对象(__main_block_impl_0结构体类比obj

Rain and Tears 899

OC - Block 详解

1.Block 的使用 Block 是什么? 块,封装了函数调用以及调用环境的 OC 对象, Block 的声明 // 1. @property (nonatomic, copy) void(^myBlock1)(void); // 2.BlockType:类型别名 typedef void(^BlockType)(void); @property (nonatomic, copy) BlockT...

weixin_42350379的博客 1472

用Origin快速拟合荧光寿命、PL Decay (TRPL)数据分析处理

用Origin快速拟合荧光寿命、PL Decay (TRPL)数据分析处理

A20802013的博客 2万+

OC底层探索(二十三)Block用法及原理

Block的使用 return_type表示返回的对象/关键字等(可以是void,并省略) blockName表示block的名称 var_type表示参数的类型(可以是void,并省略) varName表示参数名称 return_type表示返回的对象/关键字等(可以是void,并省略) blockName表示block的名称 var_type表示参数的类型(可以是void,并省略) Block声明及定义语法 varName表示参数名称 return_type (^blockNam

正在注销账号的博客 1107

五子棋AI实战:极大极小搜索、Alpha-Beta剪枝与禁手实现

博弈树搜索是双人零和博弈AI的经典决策框架,其核心思想是假设对手最优应对,通过递归遍历走法空间寻找最优解。极大极小搜索配合Alpha-Beta剪枝,能在不影响决策结果的前提下将搜索量降至平方根级别,大幅提升搜索效率。在五子棋场景中,还需处理黑棋禁手规则,包括双三、双四和长连判定,并将其融入搜索框架。评估函数基于棋型识别对局面打分,走法排序和迭代加深进一步优化剪枝效果。这些技术共同构成了一个可运行的五子棋AI,适用于棋类AI入门与博弈搜索实践。

weixin_29054399的博客 125

Redis简介和项目应用

内存优先架构简介Redis的读写操作都是在内存中执行的,计算机内存的读写速度极快,比机械硬盘的读写快很多,因此也会比MySql采用机械读写的方式性能更高。但是这样会产生一个问题,当Redis重启之后,内存中的数据就会丢失,为了保证数据不会因为服务器重启而丢失,Redis实现了数据持久化的机制,这个机制会把数据存储到磁盘中,当服务器重启的时候,能够从磁盘中恢复原有的数据。

人工智能、机器学习 757

OC之block

一、block定义 用来保存一段代码,方便程序随时调用,标志符为^ 苹果推荐的类型,效率高,在运行中保存代码。用来封装和保存代码,有点像函数,block可以在任何时候执行。 二、基本使用     1.定义block变量 int (^SumBlock)(int, i

VicenteZ 528

Codex CLI 接入智谱 GLM-5.1 完整教程

Codex CLI 是 OpenAI 推出的命令行 AI 编程工具,支持自主读取文件、执行命令、编写代码等操作,是目前最火的终端 AI 编程工具之一。通过 CLIProxyAPI 代理,我们成功将 Codex CLI 与智谱 GLM-5.1 模型对接,核心在于解决 Responses API 与 Chat Completions API 的协议转换问题。✅成熟稳定:CLIProxyAPI 社区活跃(4.7k fork),持续维护✅完整兼容:支持流式/非流式、function calling✅低成本。

u011831527的博客 2572

OC基础 Block

什么是Blocks Blocks是C语言的扩充功能。可以概括为:带有自动变量(局部变量)的匿名函数。 所谓的匿名函数,就是没有名字的函数,在C语言中是不允许的。 在计算机科学中,这种概念也称为:“闭包Closure”、“lambda计算”等。 而且一般而言,函数或者方法里是不能又出现一个函数的,但是Blocks作为一种数据类型,是可以的。通常Blocks用于封装代码。因为即便是写在函数体内部,不去调用它,就不会执行。 Blocks的声明 //无参数 无返回值 void (^block1)(void)

乐事派的专栏 2071

FC游戏Hack实战:从零开始修改游戏数据

本文以《忍者神龟3》为例,详细介绍了从零开始进行FC游戏Hack的完整实战流程。通过使用FCEUX模拟器和调试器,结合“递减法”精准定位生命值内存地址,并利用十六进制编辑器修改关键指令,最终实现“无限生命”效果。文章旨在引导读者理解游戏数据修改的核心原理与操作技巧,重温经典的同时深入计算机程序运行机制。

weixin_28366353的博客 356

UReport2 报表设计器 在线表格

UReport2官网 一、UReport2报表设计器 UReport2是一个开源的可视化报表设计器,功能强大,操作简单,可以实现复杂的报表统计,有各种各样的导出和打印功能,支持导入Excel表格! 1、报表设计器 2、设计一个简单的用户列表展示 二、可编辑表格 扩展了layui的表格,支持多元化数据编辑(单选,多些、日期、下拉联动),开发简单、高效、便捷。有了它就可以轻松开发类似进销存系统的表格录入功能了,用户拿来即用! 三、主从表录......

ejinxian的专栏 2万+

「OC」小白书读书笔记——Block的相关知识(下)

前面我们说到block当中捕获变量的底层原理,以及block对应的各种不同的类,现在开始讲一下block在大括号之中生成,却能够超出变量存在域可存在原因,我们看一下下面的例子如同上图所示这个被copy到堆上的block就是类,一般来说,在需要持有 block 时,只需要执行一次 copy 操作就足够了,多次调用 copy 不会导致重复复制,只是增加引用计数。

aa2002aa的博客 1371

AndroidKiller之APK 编译失败,无法继续下一步签名【BUG解决】【App反向解析】

文章目录项目场景:问题描述原因分析:解决方案:BUG解决 项目场景: AndroidKiller: 在反向解析APP包时报错:APK 编译失败,无法继续下一步签名。 网上很多方法都是无效的哈,我追究原因发现,这个bug的出现大部分情况都是因为Apktool的问题。 此方法:百分之百解决此bug! 错误如下: 问题描述 APK 编译失败,无法继续下一步签名! 原因分析: Apktool版本不适配的问题,现在的技术更新换代太快,我们安装AndroidKiller的时候,有时候不是官方渠道的话,他的版本是非常

一键难忘的博客 2万+

iOS OC基础知识笔记

iOS OC基础知识笔记 一个NSObject对象占用多少内存? 系统分配了16个字节给NSObject对象(通过malloc_size函数获得) 但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数获得) #import <objc/runtime.h> #import <malloc/malloc.h&...

WJ的博客 1484

CAN总线入门(硬件部分)

这篇博客讲述CAN总线入门知识。

记得诚 1万+

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Object-C高级编程读书笔记(2)——Block的实质

按照OC高级编程书中所说,所谓Block实质就是Object-C对象。 如何理解这句话呢?应该从OC的类对象所拥有的特征入手,如果Block同样拥有这些特征,那么Block当然也就是OC的对象。 Object-C对象 在OC中,我们可以用id类型来统一代表所有的OC对象类型。那OC运行时又是如何知道id所指向的对象类型具体是那种呢? 我们知道,在OC中,基本上所有的类,最终都有一个相同的父

无忘无往 2432

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

zblock 结构_OC 的 Block 简析1 - 三种类型

本文主要介绍 Block 的三种类型。一、Block 是什么?Blocks are Objective-C objects, which means they can be added to collections likeNSArrayorNSDictionary.As an optimization, block storage starts out on the stack—just ...

weixin_39555415的博客 413

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

浅谈OC中Block的本质

Block简介 block是将函数及其执行上下文封装起来的一个对象 在block实现的内部,有很多变量,因为block也是一个对象 其中包含了诸如isa指针,imp指针等对象变量,还有储存其截获变量的对象等 原文博客地址: 浅谈OC中Block的本质 定义和使用 block根据有无参数和有无返回值有以下几种简单使用方式 // 无参数无返回值 void (^ BlockOne)(void) =...

RunningKing 1426

OC面试题 - block相关汇总

block出现之后除了官方原有,几乎很少人再用delegate模式了,很多api也扩展了block模式,block最常见的面试分为: 1.block的基本使用方式 2.block的原理,本质上block是个啥 3.衍生出来的循环引用问题产生的原因以及解决方式 4.__block和__weak的区别 5.block捕获机制 ...

yokan_de_s的博客 459

OC中Block相关问题总结

1.Block中相互引用问题解决方案: __weak ThirdViewController *weakSelf = self; __weak typeof(self) weakSelf = self; 2.为什么Block使用copy而不用strong @property(nonatomic, copy)void (^block

ft6206的博客 312

认识OC中的Block

block是什么? block本质是一个OC对象,内部也有isa指针 block是封装了函数调用以及函数调用环境的OC对象 (block内部用到block外部对象也会封装到block内部) 在main.m中写一个block,并在arm64下编译成c++代码。 #import <Foundation/Foundation.h> int main(int argc, const ch...

Max_Zeong的博客 354

OC总结 【OC基础语法相关知识】

m是OC源文件扩展名,入口点也是main函数,第一个OC程序: 1 #import <Foundation/Foundation.h> 2 3 int main(int argc, const char * argv[]) 4 5 { 6 7 theme manager 8 9 @autoreleasepool { 1...

dehuai19940321的博客 356

oc总结 --oc基础语法相关知识

来源:http://www.cnblogs.com/wellsoho/p/4351042.html m是OC源文件扩展名,入口点也是main函数,第一个OC程序: #import int main(int argc, const char * argv[]) { theme manager     @autoreleasepool {

Hugo.Lee的博客 683

oc——block

oc——block

mardax的专栏 440

OC 的 block 学习 3,__block

吹牛逼:

dengjiangszhan的博客 116

OC中的block

Block是将(函数)及其(执行上下文)封装起来的(对象) // MCBlock.m - (void)method { int multiplier = 6; int (^Block)(int) = ^int(int num) { return num * multiplier; }; Block(2); } 源码解析,使用 clang -rewrite-objc file.m 命令查看编译之后的文件内容 结构体构造函数中第一个参数是函数指针,第二个参数block的描述,第三个参数是blo.

More reading and learning to become excellent 546
上一篇: 「OC」__bridge关键字的使用
下一篇: 「OC」小白书读书笔记——Block的相关知识(下)
小鹿撞出了脑震荡
博客等级 码龄3年 1107粉丝 97原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值