Blocks学习笔记总结

2024-02-18 19:48
文章标签 学习 总结 笔记 blocks

本文主要是介绍Blocks学习笔记总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文是对Apple的《Blocks Progromming Gude》学习的笔记总结。

  对象时C级别的语法和运行时特性。和标准C函数很类似,但除了可执行代码外,还可能包含了变量自动绑定(栈)或内存托管(堆)。所以一个block维护一个状态集(数据),可以在执行的时候用来影响程序行为。Block用来作为回调特别有用。

  你可以在MAC OS 10.6及其以后版本、IOS 4.0及其以后版本上使用Blocks.

  Blocks运行时是开源的,可以再LLVM's compiler-rt subproject repository(LLVM的RT编译器的子项目)里面找到他。

1.声明一个Block

复制代码
1 int (^myBlock) (int) = ^(int num){
2     return num * num; 
3 }
4 说明:
5 int:返回值类型,如果没有返回值则为void
6 (^myBlock):块定义需要有一个^标记,myBlock是块名称
7 (int):参数类型列表,如果没有参数则为void
8 ^(int num):以^开头的参数列表,如果没有则为void,也可以省略
9 {}:block体(相当于函数体)
复制代码

2.使用block

1 printf("%d",myBlock(7));

3.很多情况下不需要对block进行生命,而是直接使用内联的block

复制代码
1 char *myCharacters[3] = {"TomJohn","George","Jim Green"};
2 
3 qsort_b(myCharacters,3,sizeof(char *),^(const void *l,const void *r){
4     char *left = *(char **)l;
5     char *right = *(char **)r;
6     return strncmp(left,right,l);
7 });
复制代码

4.在Cocoa frameworks中有一些方法使用block作为参数,通常不是执行对一个对象的集合的操作就是在操作完成的时候作为回调使用。例子中显示了如何通过NSArray的sortedArrayUsingComparator:使用block.

复制代码
 1 -(void) sort{
 2     NSArray *stringArray = [NSArray arrayWithObjects:@"Java网络编程",@"Java开发实战经典",@"研磨设计模式",@"iPhone开发秘籍",@"自己动手写网络爬虫",@"Cocos2d 游戏开发实战",@"Oracle宝典",@"Java Web开发实战",nil];
 3     static NSStringCompareOptions options = NSCaseInsensitiveSearch |
 4                 NSNumericSearch |
 5                 NSWidthInsensitiveSearch |
 6                 NSForcedOrderingSearch;
 7     NSLocale *currentLocale = [NSLocale currentLocale];
 8     NSComparator sortBlock = ^(id string1,id string2){
 9         NSRange string1Range = NSMakeRange(0, [string1 length]);
10         return [string1 compare:string2 options:options range:string1Range locale:currentLocale];
11     };
12     NSArray *sortedArray = [stringArray sortedArrayUsingComparator:sortBlock];
13     NSLog(@"array:%@",sortedArray);
14 }
复制代码

5、Blocks默认不能修改相同作用域范围内的变量,但是如果这个相同作用域的变量如果使用了__block关键字进行修饰,则可以通过blocks进行修改。

6、一个block就是一个匿名的内联代码集合体:

  • *和函数一样拥有参数类型
  • *有推断和声明的返回值类型
  • *可以捕获它的声明所在的相同作用域的状态,可以和其它定义在相同作用于范围的bolcks进行共享更改
  • *在相同作用域范围被销毁后持续共享和更改相同作用域范围的状态

7、Blocks通常代表一个很小、自包的代码段。因此他们作为封装的工作单元在并发执行或者一个集合项上或者当其他操作执行完毕时的回调的时候非常使用。

Blocks作为传统的回调函数的一个实用的替代方法有以下两个原因:

  它们可以让你在调用的地方编写代码实现后面将要执行的操作。因此Blocks通常作为Frameworks 方法的参数

  它们允许你访问局部变量,而不是需要使用一个你想要执行操作时继承所有上下文信息的数据结构来进行回调。你可以直接简单的访问局部变量。

8、blocks和一个函数指针很相似,除了使用^来代替*。下面的都是合法的block的声明:

1 void (^blockReturningVoidWithVoidArgument)(void);
2 int (^blockReturningIntWIthIntndCharArguments)(int,char);
3 void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
4 
5 Blocks还支持可变参数(...).一个没有使用任何参数的block必须在参数列表上用void标明。

9、可以把一个bolcks强制转换成任意类型,反之亦然,但是不能通过*修饰符来解引用一个block,因此一个block的带笑傲是无法在编译的时候计算的。你同样可以创建block的类型,挡在多个地方使用同一个给定签名的block的时候,这通常被认为是最佳的方法:

1 typedef float (^MyBlockType) (float,float);
2 MyBlockType myFirstBlock = ...;
3 MyBlockType mySecondBlock = ...;

10、创建一个Block

复制代码
1 int (^oneFrom) (int);
2 oneFrom = ^(int anInt){
3     return anInt - 1;
4 };
5 如果咩有显式的给一个block表达式声明一个返回值,它会自动的从block内容推断出来。如果返回值是推断的,而且参数列表也是void,那么你同样可以省略参数列表的void。如果或者当出现多个返回状态的时候,它们必须是完全匹配的(如果有必要可以使用强制类型转换)
复制代码

11、全局Blocks

在文件级别,可以把block作为全局标示符:

1 #import <stdio.h>
2 
3 int GlobalInt  = 0;
4 int (^getGaobalInt)(void) = ^{return GlobalInt;};

12、在block的主体代码中,变量可以被使用五种方法来处理。可以引用三种标准类型的变量,就像在函数里面引用一样:

全局变量:包括静态局部变量

全局函数:在技术上说这不是变量

封闭范围内的局部变量和参数

*在函数界别是__block变量。这些在block里面是可变的,并且任何引用block的都被保存一份副本到堆里面。

*引用const

*最后在实现方法里面,blocks也许会引用Objective-C的实例变量。

在Blocks里面使用变量遵循以下的规则:

全局变量可以访问,包括在相同作用域范围内的静态变量

传递给block的参数可以访问(和函数的参数一样)

程序里面属于同一作用域范围的堆变量作为const变量(只读)。它们的值在程序里面的block表达式内使用。在嵌套block里面,该值在最近的封闭范围内被捕获。

属于同一作用域内并被__block修饰符标识的变量作为引用传递因此是可变的。

属于同一作用域范围内的block的变量就和函数的局部变量操作一样。

example:使用本地非静态变量

1 int multipiler = 7;
2 int (^myBlock)(int) = ^(int num){
3     return multipiler * 7;
4 };
5 如果在block体内修改multipiler的值将会发生错误。

13、可以通过__block修饰符指定引入的变量是可以更改的,此种类型的变量保存在变量共享的作用域范围内,所有的blocks和block副本都声明或者创建在和变量的作用域相同的范围内。你可以指定引入一个变量为可更改的,即读-写的,通过应用__block存储类型修饰符。局部变量的__block的存储和register、auto、static等存储类型相似,但它们之间不兼容。 __block变量保存在变量共享的作用域范围内,所有的blocks和block副本都声明或创建在和变量的作用域相同范围内。所以,如果任何blocks副本声明在栈内并未超出栈的结束时,该存储会让栈帧免于被破坏(比如封装为以后执行)。同一作用域范围内给定的多个block可以同时使用一个共享变量。 作为一种优化,block存储在栈上面,就像blocks本身一样。如果使用Block_copy拷贝了block的一个副本(或者在Objective-C里面给block发送了一条copy消息),变量会被拷贝到堆上面。所以一个__block变量的地址可以随时间推移而被更改。

使用__block的变量有两个限制:它们不能是可变长的数组,并且它们不能是包含有C99可变长度的数组变量的数据结构。

 

复制代码
1 __block int x = 123; // x lives in block storage
2 void (^printXAndY)(int) = ^(int y) {
3 x = x + y;
4 printf("%d %d\n", x, y);
5 };
6 printXAndY(456);
复制代码
复制代码
 1 下面的例子显示了blocks和其他几个类型变量间的交互:
 2 extern NSInteger CounterGlobal;
 3 static NSInteger CounterStatic;
 4 {
 5 NSInteger localCounter = 42;
 6 __block char localCharacter;
 7 void (^aBlock)(void) = ^(void) {
 8 ++CounterGlobal;
 9 ++CounterStatic;
10 CounterGlobal = localCounter; // localCounter fixed at block creation
11 localCharacter = 'a'; // sets localCharacter in enclosing scope
12 };
13 ++localCounter; // unseen by the block
14 localCharacter = 'b';
15 aBlock(); // execute the block
16 
17 // localCharacter now 'a'
18 }
复制代码

14、在引用计数的环境里面,默认情况下当你在block里面引用一个Objective-C对象的时候,该对象会被retain。当你简单的引用了一个对象的实例变量时,它同样被retain。但是被__block存储类型修饰符标记的对象变量不会被retain

注意:在垃圾回收机制里面,如果你同时使用__weak和__block来标识一个变量,那么该block将不会保证它是一直是有效的。 如果你在实现方法的时候使用了block,对象的内存管理规则更微妙:

这篇关于Blocks学习笔记总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/722256

相关文章

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Nginx Location映射规则总结归纳与最佳实践

《NginxLocation映射规则总结归纳与最佳实践》Nginx的location指令是配置请求路由的核心机制,其匹配规则直接影响请求的处理流程,下面给大家介绍NginxLocation映射规则... 目录一、Location匹配规则与优先级1. 匹配模式2. 优先级顺序3. 匹配示例二、Proxy_pa

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

MySQL基本查询示例总结

《MySQL基本查询示例总结》:本文主要介绍MySQL基本查询示例总结,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Create插入替换Retrieve(读取)select(确定列)where条件(确定行)null查询order by语句li

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

Linux区分SSD和机械硬盘的方法总结

《Linux区分SSD和机械硬盘的方法总结》在Linux系统管理中,了解存储设备的类型和特性是至关重要的,不同的存储介质(如固态硬盘SSD和机械硬盘HDD)在性能、可靠性和适用场景上有着显著差异,本文... 目录一、lsblk 命令简介基本用法二、识别磁盘类型的关键参数:ROTA查询 ROTA 参数ROTA

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)