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

相关文章

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

Python中连接不同数据库的方法总结

《Python中连接不同数据库的方法总结》在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几... 目录一、连接mysql数据库二、连接PostgreSQL数据库三、连接SQLite数据库四、连接Mo

Git提交代码详细流程及问题总结

《Git提交代码详细流程及问题总结》:本文主要介绍Git的三大分区,分别是工作区、暂存区和版本库,并详细描述了提交、推送、拉取代码和合并分支的流程,文中通过代码介绍的非常详解,需要的朋友可以参考下... 目录1.git 三大分区2.Git提交、推送、拉取代码、合并分支详细流程3.问题总结4.git push

Kubernetes常用命令大全近期总结

《Kubernetes常用命令大全近期总结》Kubernetes是用于大规模部署和管理这些容器的开源软件-在希腊语中,这个词还有“舵手”或“飞行员”的意思,使用Kubernetes(有时被称为“... 目录前言Kubernetes 的工作原理为什么要使用 Kubernetes?Kubernetes常用命令总

Python中实现进度条的多种方法总结

《Python中实现进度条的多种方法总结》在Python编程中,进度条是一个非常有用的功能,它能让用户直观地了解任务的进度,提升用户体验,本文将介绍几种在Python中实现进度条的常用方法,并通过代码... 目录一、简单的打印方式二、使用tqdm库三、使用alive-progress库四、使用progres

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Java向kettle8.0传递参数的方式总结

《Java向kettle8.0传递参数的方式总结》介绍了如何在Kettle中传递参数到转换和作业中,包括设置全局properties、使用TransMeta和JobMeta的parameterValu... 目录1.传递参数到转换中2.传递参数到作业中总结1.传递参数到转换中1.1. 通过设置Trans的

C# Task Cancellation使用总结

《C#TaskCancellation使用总结》本文主要介绍了在使用CancellationTokenSource取消任务时的行为,以及如何使用Task的ContinueWith方法来处理任务的延... 目录C# Task Cancellation总结1、调用cancellationTokenSource.

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用