Block剧终:Objective-C中的闭包性和匿名函数 分享0

FPGA实现电机转速PID控制 通过纯RTL实现电机转速PID控制,包括电机编码器值读取,电机速度、正反转控制,PID算法,卡尔曼滤波,最终实现对电机速度进行控制,使其能够渐近设定的编码器目标值。 阅读详情

引用http://www.tairan.com/archives/4557

本文由破船译自xs-labs转载请注明出处!

小引

还记得昨天我给大家推荐的文章吗:Closure and anonymous functions in Objective-C。今天手痒,还想继续敲几个字,索性我就把这篇文章敲出来,以此对block说声代码里见吧。

目录

1、关于
    1.1匿名函数
    1.2闭包性

2、Objective-C中的实现
    2.1将block当做参数来传递
    2.2闭包性
    2.3内存管理
    2.4示例

正文

1、关于

许多脚本语言都支持lambda表达式和匿名函数。这两个概念经常与闭包性(closure)相关。例如在JavaScript、ActionScript或PHP(5.3之后)中都有相关的概念。

其实在Objective-C语言中也提供了这两个概念的实现:叫做block。

自从Mac OS X 10.6之后,就可以使用block了,其实这样归功于Clang。

1.1 匿名函数

就如名字暗示的一样,匿名函数实际上就是一个没有名字或者标示(identifier)的函数。匿名函数只有内容(也可以叫做body),我们可以将其存储在一个变量中,以便之后使用,或者将其当做一个参数传递给另外一个函数使用。

在脚本语言的回调中经常使用到这个概念。

例如,在下面的JavaScript中,有一个名为foo的标准函数,接收一个callback当做参数,在函数中,调用了这个callback:

function foo( callback )
{
    callback();
}

这里有可能是定义了另外一个标准函数, 然后将这个标准函数当做参数传递给上面的函数:

function bar()
{
    alert( 'hello, world' );
}

foo( bar );

不过这样一来,bar函数就会被声明在全局范围内,这就会带来一个风险:被另外一个相同名称的函数覆盖(override)了。

但是别担心,JavaScript语言允许callback函数在调用的时候才进行声明:

foo
{
    function()
    {
        alert( 'hello, world' );
    }
);

在上面,可以看到这个callback实际上并没有标示(identifier)。它也不会存在于全局范围,因此也不会与别的已有函数产生冲突。

我们也可以把callback存储到一个变量中,同样也不回存在于全局范围,不过我们可以通过这个变量对这个callback进行重复利用:

myCallback = function()
{
    alert( 'hello, world' );
};

foo( myCallback );

 1.2闭包性

闭包性这个概念是允许一个函数访问其所声明上下文中的变量,甚至是在不同的运行上下文中。

下面我们再来看看JavaScript的相关代码:

function foo( callback )
{
    alert( callback() );
}

function bar()
{
    var str = 'hello, world';

    foo
    (
        function()
        {
            return str;
        }
    );
}

bar();

上面的代码中,callback被从bar函数的运行上下文中传递给了foo函数,该callback函数返回变量str的值。

不过在这里请注意,变量str是声明在bar函数中的,也就是说这个变量仅存于bar函数中。

而callback是在另外一个不同的函数中被执行的(跟变量str不在一起),我们这是可能会猜测foo函数中什么也不会显示出来。

但是,在这里引入了闭包性这个概念。

也就是说在不同的函数中(运行上下文中),一个函数可以访问到变量所声明上下文中的内容。

因此上面的代码中,callback可以访问到str变量——即使这个callback所在的foo函数不能直接访问这个str变量。

 

2、Objective-C中的实现

实际上闭包性和匿名函数在Objective-C中是可以使用的,只不过Objective-C是构建于C语言之上,属于强类型编译语言,所以跟上面介绍的解释性脚本语言有许多不同之处。

注意:block其实在纯C或C++(以及Objective-C++)中都是可用的。

在标准C函数中,定义block(匿名函数)之前需要先声明原型。

block的语法有一点点棘手,不过要是熟悉函数指针的话,就非常容易理解了。

下面是block的原型:

NSString * ( ^ myBlock )( int );

上面的代码是声明了一个block(^)原型,名字就叫做myBlock,携带一个int参数,返回只为NSString类型的指针。

下面来看看block的定义:

myBlock = ^( int number )
{
    return [ NSString stringWithFormat: @"Passed number: %i", number ];
};

如上所示,将一个函数体赋值给了myBlock变量,其接收一个名为number的参数。该函数返回一个NSString对象。

注意:不要忘记block后面的分号。

在脚本语言中是可以忽略掉分号的,但是在编译性语言(如Objective-C)是必须有的。

如果没有写这个分号,编译器会产生一个错误,当然也不会生成可执行文件。

定义好block之后,就可以像使用标准函数一样使用它了:

myBlock(5);

下面是完整的Objective-C程序源代码:

#import <Cocoa/Cocoa.h>

int main( void )
{
    NSAutoreleasePool * pool;
    NSString * ( ^ myBlock )( int );

    pool    = [ [ NSAutoreleasePool alloc ] init ];
    myBlock = ^( int number )
    {
        return [ NSString stringWithFormat: @"Passed number: %i", number ];
    };

    NSLog( @"%@", myBlock(5) );

    [ pool release ];

    return EXIT_SUCCESS;
}

我们可以用下面的命令来编译(在Terminal中):

gcc -Wall -framework Cocoa -o test test.m

上面的命令会根据test.m源代码文件生成一个名为name的可执行文件。可以用下面的命令来运行这个可执行文件:

./test

如果不把block赋值给变量的话,可以忽略掉block原型的声明,例如直接将block当做参数进行传递。如下所示:

someFunction( ^ NSString * ( void ) { return @"hello, world" } );

注意,上面这种情况必须声明返回值的类型——这里是返回NSString对象。

2.1将block当做参数来传递

之前说过了,block可以当做参数传递给某个C函数。

如下所示:

void logBlock( NSString * ( ^ theBlock )( int ) )
{
    NSLog( @"Block returned: %@", theBlock() );
}

由于Objective-C是强制类型语言,所以作为函数参数的block也必须要指定返回值的类型,以及相关参数类型(如果需要的话)。

其实在Objective-C方法中也是一样的:

- ( void )logBlock: ( NSString * ( ^ )( int ) )theBlock;

2.2闭包性

之前有说过,闭包性在Objective-C中是可用的,只不过其行为跟解释性语言有所不同罢了。

我们来看看下面的程序:

#import <Cocoa/Cocoa.h>

void logBlock( int ( ^ theBlock )( void ) )
{
    NSLog( @"Closure var X: %i", theBlock() );
}

int main( void )
{
    NSAutoreleasePool * pool;
    int ( ^ myBlock )( void );
    int x;

    pool = [ [ NSAutoreleasePool alloc ] init ];
    x    = 42;

    myBlock = ^( void )
    {
        return x;
    };

    logBlock( myBlock );

    [ pool release ];

    return EXIT_SUCCESS;
}

上面的代码在main函数中声明了一个整型,并赋值42,另外还声明了一个block,该block会将42返回。

然后将block传递给logBlock函数,该函数会显示出返回的值42。

即使是在函数logBlock中执行block,而block又声明在main函数中,但是block仍然可以访问到x变量,并将这个值返回。

注意:block同样可以访问全局变量,即使是static。

下面来看看第一点不同之处:通过block进行闭包的变量是const的。也就是说不能在block中直接修改这些变量。

来看看当block试着增加x的值时,会发生什么:

myBlock = ^( void )
{
    x++

    return x;
};

编译器会生成一个错误:大概意思是在block中x变量是只读的。

不过也别担心,为了允许在block中修改变量,也是可以做到的:用__block关键字来声明变量即可。

基于之前的代码,给x变量添加__block关键字,如下:

__block int x;

2.3内存管理

从C语言的角度来看,实际上block是一个结构体,可以被拷贝和销毁的。有两个函数可以使用:Block_copy和Block_destroy()。

而在Objective-C中,block可以接收retain、release和copie消息,这就跟普通对象一样。如果一个block需要被存储下来供以后使用,这些消息是非常重要的(例如,将block存储到一个类的实例变量中)。例如,为了避免错误的使用block,对block进行retain是非常有必要的。

2.4示例

Block可以用在许多不同的环境中,这样可以让代码更加简单,以及减少函数声明的数量。

下面有一个实例:

我们将给NSArrary类添加一个static方法(类方法),该方法通过一个callback,根据另外一个数组中的内容产生一个新的数组。

在PHP程序员眼里,该方法就如一个array_filter()。

首先,需要为NSArray类声明一个category。(通过category可以给已有的类添加新方法)。

@interface NSArray( BlockExample )

+ ( NSArray * )arrayByFilteringArray: ( NSArray * )source withCallback: ( BOOL ( ^ )( id ) )callback;

@end

上面,声明了一个方法,该方法返回一个NSArray对象,另外接收两个参数:NSArray对象,以及一个callback (为block)。

在callback中会判断根据传入数组参数中的每一个元素。并将返回一个boolean值,以确定当前array中的元素是否需要存储到返回的数组中。

block只有一个参数,代表数组中的某个元素。

我们来看看该方法的具体实现:

@implementation NSArray( BlockExample )

+ ( NSArray * )arrayByFilteringArray: ( NSArray * )source withCallback: ( BOOL ( ^ )( id ) )callback
{
    NSMutableArray * result;
    id               element;

    result = [ NSMutableArray arrayWithCapacity: [ source count ] ];

    for( element in source ) {

        if( callback( element ) == YES ) {

            [ result addObject: element ];
        }
    }

    return result;
}

@end

上面的代码中,首先是创建了一个可以动态改变尺寸的数组:NSMutableArray,然后根据source array的数目来初始化该数组。

然后对source array中的每个元素进行迭代, 如果callback返回值为YES的话,就将该元素添加到result数组中。

下面是使用该方法的一个完整示例:利用callback构建一个数组:该数组中只包含source array中为NSString类型的元素:

#import <Cocoa/Cocoa.h>

@interface NSArray( BlockExample )

+ ( NSArray * )arrayByFilteringArray: ( NSArray * )source withCallback: ( BOOL ( ^ )( id ) )callback;

@end

@implementation NSArray( BlockExample )

+ ( NSArray * )arrayByFilteringArray: ( NSArray * )source withCallback: ( BOOL ( ^ )( id ) )callback
{
    NSMutableArray * result;
    id               element;

    result = [ NSMutableArray arrayWithCapacity: [ source count ] ];

    for( element in source ) {

        if( callback( element ) == YES ) {

            [ result addObject: element ];
        }
    }

    return result;
}

@end

int main( void )
{
    NSAutoreleasePool * pool;
    NSArray           * array1;
    NSArray           * array2;

    pool   = [ [ NSAutoreleasePool alloc ] init ];
    array1 = [ NSArray arrayWithObjects: @"hello, world", [ NSDate date ], @"hello, universe", nil ];
    array2 = [ NSArray
                    arrayByFilteringArray: array1
                    withCallback:          ^ BOOL ( id element )
                    {
                        return [ element isKindOfClass: [ NSString class ] ];
                    }
             ];

    NSLog( @"%@", array2 );

    [ pool release ];

    return EXIT_SUCCESS;
}

本文由破船翻译●转载请注明出处●2013-07-12


在iPad上使用Python进行编程 如果你拥有一台iPad,并且想在上面编写和运行Python代码,你会发现iPad提供了一些适用的工具和应用程序来满足你的需求。安装一个Python解释器应用程序,编写和运行Python代码,使用第三方库和模块,以及存储和共享代码,这些步骤将帮助你在iPad上进行Python编程。要在iPad上运行Python代码,首先需要安装一个Python解释器。这些应用程序提供了一个交互式的开发环境,允许你编写、编辑和运行Python代码。一旦你安装了Python解释器应用程序,你可以开始编写Python代码了。 阅读详情

相关推荐

数字蓝牙功放

数字蓝牙功放(TPA3110+BK8000L),基于D类数字功放芯片TPA3116蓝牙功放,HIFI级带滤波15Wx2蓝牙数字功放,支持有线和蓝牙两种音源输入

runweipa的博客 1420

Block剧终:Objective-C中的闭包性和匿名函数

目录 1、关于     1.1匿名函数     1.2闭包性 2、Objective-C中的实现     2.1将block当做参数来传递     2.2闭包性     2.3内存管理     2.4示例 正文 摘自:移动开发网http://www.mobiledev.cn/?p=12216 1、关于 许多脚本语言都支持lambda表达式和匿名函数。这两

lelelaileabc的专栏 877

PX4飞控CAN总线通信深度配置:从menuconfig到驱动加载的完整指南

本文详细解析了PX4飞控中CAN总线通信的深度配置流程,从menuconfig选项设置到驱动加载的完整指南。涵盖硬件抽象层、驱动层和应用层的配置细节,提供实际验证方法和故障排查技巧,帮助开发者高效实现CAN通信,特别适用于无人机和机器人底盘运动控制等场景。

weixin_30374009的博客 501

Objective-C中的callback之一

OC中的Callback有四种类型:下面是第一种:NSRunloop////  BNRLogger.h//  TOCRunloopa////#import <Foundation/Foundation.h>@interface BNRLogger : NSObject@property (nonatomic) NSDate *lastTime;- (NSString *)lastTim...

李明的博客 1030

普通人如何上岸华为OD-面试总结

总共有3道算法题,100分值的两道,200分值的一道,不同的毕业院校和专业,通过机试的分值不一样,最少需要150分通过,提前和hr联系,了解自己需要多少分通过。重中之重:哪怕你是背的题库,也请你一定不要直接抄原来的,最好是变更下方法名,否则会判定你重复率过高,从而失去后面的面试机会(实在是不会做再用此方法,凑分数所用,面试官能看到你的代码,会影响你的面试评价)本人女,所以还问道了婚育计划,有对象这点可以说,没有问题,但是如果可以的话,生孩子的时间,可以给hr说这几年不考虑。如果说没有难题,直接就挂了。

weixin_47767264的博客 5455

unity打包流程整理-Windows/Mac/Linux平台

1.Platform(平台)功能: 选择目标构建的目标平台选项PC, Mac & Linux Standalone: 适用于 Windows、Mac 和 Linux 平台2.Target Platform(目标平台)功能: 选择具体的操作系统版本选项Windows: 针对 Windows 操作系统Mac: 针对 macOS 操作系统Linux: 针对 Linux 操作系统3.Architecture(架构)功能: 选择应用程序的目标处理器架构选项x86: 针对 32 位系统。

weixin_42333247的博客 5139

匿名函数

匿名函数 匿名函数是没有名字的函数 是高级语言发展出来的新特性 一些实现了匿名函数的高级语言: 1. C++ : lambda表达式(C++11) 2. Java :lambda表达式(Java8) 3. object-c :块 匿名函数的好处在于精简程序的设计 在代码的逻辑中,可能存在一些只需要调用一次或几次的函数 C语言中的做法是命名一个函数来实现它 但这样显得太繁琐 引入匿名函...

sliver.chen的博客 1103

feko金属球远场RCS双站

feko金属球远场RCS双站

a264672的博客 6912

面试题:关于Objective-C中的回调机制

一、协议协议主要是提供接口,在iOS中模拟多继承,他的核心意义在——约定! 优点: 实现简单,容易理解 强类型检查 缺点: 建立了比较强的耦合关系 有可能需要较长期保存委托以进行回调。如果保留的委托需要有独占性,可能会给单件模式、以及多线程带来麻烦 类只能通过一个方法完成一种类型的回调。代码逻辑很容易集中到一个方法中。 大部分回调使用实际无需通过协议暴露给外部。 二、BlockBlock是OBJC

TEL_小超的博客 1007

多智能体强化学习MASAC算法:从原理到PyTorch实战详解

深度强化学习通过智能体与环境的交互试错来学习最优策略,是解决复杂序列决策问题的核心技术。其核心原理在于利用价值函数或策略梯度来最大化累积奖励,在机器人控制、游戏AI等领域展现出巨大技术价值。当面对多个智能体需要协同或竞争的复杂动态环境时,单智能体算法因环境非平稳性而面临挑战,多智能体强化学习应运而生。Multi-Agent Soft Actor-Critic (MASAC) 算法融合了SAC的稳定高效与中心化训练去中心化执行的范式,通过维护中心化Critic网络和独立策略网络,有效解决了多智能体协作中的信用

weixin_30080745的博客 334

RK3588 平台部署实战:OpenCV + LibTorch + FFmpeg 环境搭建与深度学习推理全流程解析

现在,你已经掌握了在RK3588上搭建OpenCV+LibTorch+FFmpeg环境的完整流程,也完成了深度学习模型的部署测试。不妨从一个具体的应用场景入手(如检测自家宠物的品种),亲手打造属于你的第一个边缘智能应用——当你看到模型在RK3588上精准输出结果时,你会发现:嵌入式深度学习的门槛,其实并没有想象中那么高。这些依赖是编译OpenCV、FFmpeg的基础,安装过程中若提示权限不足,可在命令前加。若能输出预测的类别索引,则说明环境搭建成功,模型推理流程通畅。文件,实现模型加载、图像预处理与推理。

FJN110的博客 536

Object-C高级编程读书笔记(1)——Block的基本概念

在OC中,引入了Block的概念,同时也有很多具体的应用。其功能类似于C语言中的函数指针,可将函数作为变量保存,传递,执行。 Block的声明方式 ^返回值类型 参数列表 表达式 例如 ^int(int count){ return count + 1;} Block变量 返回类型(^变量名称)(参数列表) 例如, 一个叫做blk1的block变量 int(^blk1)(int)

无忘无往 1473

模型预测控制(MPC)算法介绍

模型预测控制(Model Predictive Control,MPC)是一种先进的控制策略,广泛应用于工业过程控制、机器人控制、电力系统等领域。它基于系统的模型,通过滚动优化来预测系统未来的行为,并据此确定当前的最优控制输入。

AI的内部世界的博客 7175

C语言中闭包的探究及比较

这是一篇技术分享,并且之前发表在酷壳上,http://coolshell.cn/articles/8309.html,现在发布到自己的博客上。 下文是直接从酷客复制过来的,这里偷了个懒,没有再次对格式做很仔细的整理,只有稍微整理。汗。 这里主要讨论的是C语言的扩展特性block。该特性是Apple为C、C++、Objective-C增加的扩展,让这些语言可以用类Lambda表达式的

JasonLee的专栏 2万+

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

关于OC中的Block,Swift中的闭包,C++11中的lambda表达式等匿名函数详解

Hello,大家好啊!逗比老师又来给大家逗比啦!今天咱们逗比的内容,就来围绕一个比较棘手的问题——匿名函数。我有一个朋友在学习做iOS开发,他最近就在被这个Block缠绕弥漫,感觉云里雾里,所以希望我来详细讲解一下相关的内容。相信不止他一个,遇到此类问题的人一定不占少数,所以,今天逗比老师就来给大家分享一下这个部分我个人的详细见解。 我们先把视野拉回到C语言中。在C语言中定义一个函数,相信是一件...

fl2011sx的博客 2428

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

C/C++语言中闭包的探究及比较

C/C++语言中闭包的探究及比较 2012年9月20日Jason Lee发表评论阅读评论9,413 人阅读     (感谢投稿人 @思禽饮霜 ) 这里主要讨论的是C语言的扩展特性block。该特性是Apple为C、C++、Objective-C增加的扩展,让这些语言可以用类Lambda表达式的语法来创建闭包。前段时间,在对CoreData存取进行封装时(让开发

hnhbdss的专栏 7334

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Infer 的 BLOCK_PARAMETER_NOT_NULL_CHECKED 检查器:Objective-C Block 参数空值检测与修复指南

> 本文基于 Infer 官方问题文档 [BLOCK_PARAMETER_NOT_NULL_CHECKED.md](https://link.gitcode.com/i/3c3908daaf1cfcf0bbcf0a8678bf085d),并结合检查器源码、测试用例与配置文件,系统讲解该告警的触发条件、底层检测原理、三种修复方案(nil 判空、nonnull 注解、安全执行宏),以及对应的命令与配置

gitblog_00841的博客 267

OC中block的底层实现和具体运用(转)

原文地址:点击打开链接 这段时间一直忙着开发,好久没来博客了,人气稀少了不少,准备持续更新一个专题,主要谈谈OC底层的一些实现机制,并会对一些经典的面试题进行分析,感兴趣的可以持续关注,第一讲的主题是: BLock的实现和运用    我们一起来看看,经Clang编译后的block结构如下: 1 struct Block_literal_1 { 2 vo

Cj的专栏 864

谈Objective-C block的实现

大神写的,我转过来大家和大家一块分享,写的太好,太底层了,话不多说,快看 文章目录 1. 前言2. 实现方式 2.1. 数据结构定义2.2. 研究工具:clang 3. NSConcreteGlobalBlock 类型的 block 的实现4. NSConcreteStackBlock 类型的 block 的实现5. NSConcreteMallocBlo

学如逆水行舟 551

iOS中block实现的底层探究2

这是一篇技术分享,并且之前发表在酷壳上,http://coolshell.cn/articles/8309.html,现在发布到自己的博客上。 下文是直接从酷客复制过来的,这里偷了个懒,没有再次对格式做很仔细的整理,只有稍微整理。汗。这里主要讨论的是C语言的扩展特性block。该特性是Apple为C、C++、Objective-C增加的扩展,让这些语言可以用类Lambda表达式的语法来创建闭包。前段

bolu的专栏 694

Infer 静态分析之 STRONG_SELF_NOT_CHECKED:Objective-C Block 中 weakSelf/strongSelf 未判空使用的检测与修复

本文聚焦 Facebook Infer 静态分析器中的 `STRONG_SELF_NOT_CHECKED` 问题类型(Error 级别,隶属 `SelfInBlock` 检查器):当 Objective-C Block 捕获弱引用 `weakSelf`,在块内将其赋值给局部强引用 `strongSelf` 后、未经判空就直接使用该指针时,Infer 会报告潜在的空指针解引用风险。阅读完本文,你将理

gitblog_00083的博客 352
上一篇: iOS通知用法
下一篇: macosx 上安装lua
CekineLin
博客等级 码龄15年 1粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值