ReactiveCocoa 入门指导

实战:利用 Agent Harness 自动化 PPT 制作 本文将带你从零开始,用轻量级Agent编排框架,结合主流大模型(GPT-4o、通义千问、文心一言等),搭建一套全自动化的PPT生成工作流:从用户输入自然语言需求,到需求解析、大纲生成、内容填充、数据匹配、排版美化、导出成品,全程不需要手动操作,最快10分钟就能产出符合要求的PPT。我们不会讲晦涩的Agent理论,所有步骤都有可直接运行的代码示例,哪怕你只有基础的Python语法基础,也能跟着一步步做出能用的自动PPT工具。 阅读详情

原文地址:http://www.teehanlax.com/blog/getting-started-with-reactivecocoa/


       在先前的文章中,介绍一了ReactiveCocoa概念,ReactiveCocoa是Objective-C中用于声明式编程的类库。接下来在这里会介绍一些ReactiveCocoa中的模式,讨论一些最佳实践,并指出一些常见的陷阱。ReactiveCocoa的学习需要时间,让我们慢慢来。


模式

      在ReactiveCocoa中有三种基本的模式:责任链、分割和组合模式(chaining, splitting, and combining)。之前的文章时稍微介绍了责任链和组合模式,接下来的会更深入。


        回顾一下:在ReactiveCocoa中的核心是signal:(信号),它表示不断变化的状态。当我们使用chain、split和combine时,实际上我们就是在操作这些signal。


       Chaining是在ReactiveCocoa最常用的模式:将一个已有的signal转换为一个新的signal。常用的操作是创建一个新的signal,再对它使用filter:、map:或startWith:等方法。例:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. RAC(self.textField.text) = [[[RACSignal interval:1] startWith:[NSDate date]] map:^id(NSDate *value) {  
  2.     NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:value];  
  3.       
  4.     return [NSString stringWithFormat:@"%d:%02d", dateComponents.minute, dateComponents.second];  
  5. }];  

       在这个例子中,我们将textFiled的text属性绑定为三个串连的signals的结果。首先,我们创建一个间隔信号,这个信号每隔一秒钟就发送当前时间。间隔信号在没有启动的时候是不会有值的,所以我们使用startWith:启动起来。最后,使用map:将signal的NSDate值转换为一个NSString字符串,这个字符串将会被赋值到textField的text属性上。




        Chaining是最常用的操作,而且它通常不使用局部变量,而是像上面那样串连起来操作。下面的代码与上面的代码是等同的。

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. RACSignal *intervalSignal = [RACSignal interval:1];  
  2. RACSignal *startedIntervalSignal = [intervalSignal startWith:[NSDate date]];  
  3. RACSignal *mappedIntervalSignal = [startedIntervalSignal map:^id(NSDate *value) {  
  4.     NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:value];  
  5.       
  6.     return [NSString stringWithFormat:@"%d:%02d", dateComponents.minute, dateComponents.second];  
  7. }];  
  8.    
  9. RAC(self.textField.text) = mappedIntervalSignal;  

       Splitting与chaining比较类似,也是将signal转换为其它的sginal,不同之处在于,Splitting会重复使用中间的signals。Splitting看起来要复杂些,其实也就是一个signals使用多次罢了。例:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. RACSignal *dateComponentsSignal = [[[RACSignal interval:1] startWith:[NSDate date]] map:^id(NSDate *value) {  
  2.     NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:value];  
  3.     return dateComponents;  
  4. }];  
  5.    
  6. RAC(self.minuteTextField.text) = [dateComponentsSignal map:^id(NSDateComponents *dateComponents) {  
  7.     return [NSString stringWithFormat:@"%d", dateComponents.minute];  
  8. }];  
  9.    
  10. RAC(self.secondTextField.text) = [dateComponentsSignal map:^id(NSDateComponents *dateComponents) {  
  11.     return [NSString stringWithFormat:@"%d", dateComponents.second];  
  12. }];  


        在上面这个例子中,创建了一个串联signal,即局部变量:dateComponentsSignal。接着再用dateComponentsSignal创建两个新的signal,并将它们分别与两个textfield的text属性进行绑定。





       第三种常用模式是combining。combining就是将几个signal结合起来创建出一个新的signal。比如“登录”按钮,只有在“用户名”与“密码”输入框中的文本长度都超过6时才能被点击,否则处于不可用的状态。那么我们可以为“登录”按钮的enabled状态创建一个signal,这个signal则是由“用户名”与“密码”框它们两个自己的signal组合起来:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. RAC(self.submitButton.enabled) = [RACSignal combineLatest:@[self.usernameField.rac_textSignal, self.passwordField.rac_textSignal] reduce:^id(NSString *userName, NSString *password) {  
  2.     return @(userName.length >= 6 && password.length >= 6);  
  3. }];  


         在这里,我们将“登录”按钮的enable状态绑定到使用combineLatest:reduce:方法创建的signal上。这个方法的第二个参数是一个block,这个block的参数是combineLatest中的参数的最新值的组合。我们将两个文本框的text signal一起传到combineLatest,在reduce的block中,该block也就会接收到两个NSString的参数,这个block的工作就是将两个参数值组合起来生成一个值,然后返回。该方法的说明:

// +combineLatest:reduce: takes an array of signals, executes the block with the

// latest value from each signal whenever any of them changes, and returns a new

// RACSignal that sends the return value of that block as values.





Combining常用于两种情况:

1、需要同时满足多种条件。

2、在多个signal中进行选择。


       重点在于这种线性逻辑(linear flow of logic)的思维,如何将这些signals进行串联、分割或组合。看看这些基本操作能让你对这些模式更加熟悉。

最佳实践

        我们已经介绍了ReactiveCocoa模式的基本知识,接下来看看最佳实践。


        ReactiveCocoa通过移除状态使我们写程序更容易。然而,即使是在一个“完成反应(completely reactive)”式的应用中,我们还是得写些非ReactiveCocoa的代码,比如像table view的delegate方法。RACSubjects则充当了非reactive和 reactive代码的桥梁。


        RACSubject是能够手动发送新值的signal。比如,gesture recognizers并不是ReactiveCocoa的一部分——这时我们可以用两个RACSubject属性:一个用于接收gesture recognizer:事件,标识这个recognizer是否正在处理;另一个用来记录它当前的位置。

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. self.gestureRecognizerIsRunningSubject = [RACSubject subject];  
  2. self.gestureRecognizerValueSubject = [RACSubject subject];  
  3.    
  4. RAC(self.someView.frame) = [self.gestureRecognizerValueSubject map:^id(NSValue *value) {  
  5.    CGPoint location = [value CGPointValue];  
  6.    
  7.    CGFloat size = 100.0f;  
  8.    
  9.    return [NSValue valueWithCGRect:CGRectMake(location.x - size/2.0f, location.y - size/2.0f, size, size)];  
  10. }];  


      我们将一个view放到gesture recognizer的最后位置的中心。


      发送这些subjects事件非常简单,只要简单实现一个gesture recognizer方法即可(注:该方法可放到代理方法-gestureRecognizer:shouldReceiveTouch:中调用):

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. -(void)gestureRecognizerReceivedTouch:(UIPanGestureRecognizer *)recognizer {  
  2.    if (recognizer.state == UIGestureRecognizerStateBegan) {  
  3.        [self.gestureRecognizerIsRunningSubject sendNext:@(YES)];  
  4.    }  
  5.    
  6.    else if (recognizer.state == UIGestureRecognizerStateChanged) {  
  7.        [self.gestureRecognizerValueSubject sendNext:[NSValue valueWithCGPoint:[recognizer locationInView:self.view]]];  
  8.    }  
  9.    
  10.    else if (recognizer.state == UIGestureRecognizerStateEnded) {  
  11.        [self.gestureRecognizerIsRunningSubject sendNext:@(NO)];  
  12.    }  
  13. }  


        虽然RACSubjects是非reactive代码与ReactiveCocoa代码的桥梁,但过分滥用也是有风险的。当我们能够通过chaining signals完成任务的话,就不要依赖于RACSubjects的值。


        ReactiveCocoa的设计就是让我们的程序尽可能地减少各种状态,这种减少状态的逻辑使得我们要少用执行副作用(perform side-effects)。比如基于上面的代码,我们希望在table view的手势事件完成时,闪烁一个滑动条,让用户知道已经滑到哪里了。我们可以调用subscription:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. [[self.gestureRecognizerIsRunningSubject filter:^BOOL(NSNumber *gestureRecognizerIsRunning) {  
  2.    return !(gestureRecognizerIsRunning.boolValue);  
  3. }] subscribeNext:^(id x) {  
  4.    [self.tableView flashScrollIndicators];  
  5. }];  

        这里我们过滤掉手势正在运行的事件,只在滑动完成时subcribe。这时,在subscribeNext: bloc中,我们执行了副作用。


        虽然subscriptions很有用,执行副作用也是必要的,但要小心过度使用。它们就是可变的变量、状态,这些正是ReactiveCocoa所避免的。在能够通过绑定属性映射signals完成任务的时候,就不要使用RACSubjects。


陷阱

       任何一种新的东西,对于新手来说总会有些陷阱。比如下面的代码,当我们从一个属性创建一个新的signal,在someString的值改变之前,其实是什么也不会发生的。

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. RAC(self.label.text) = RACAble(self.someString);  
[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.   

        如果想要立即发送someSting当前的值,可以用RACAbleWithStart。这个“starts”的signal会将someString的当前的值也与之绑定。

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. RAC(self.label.text) = RACAbleWithStart(self.someString);  

        与之类似,当使用interval:安排一个周期定时器时,这个定时器不会立即启用走到这个传来第一个interval,有点像用NSTimer。还记得第一个例子不?我们将text field的text值与当前时间绑定,我们是手动使用startWith:并传当前时间来开启的。如果我们不这么做的话,text field在第一个间隔时间的前一秒是空的。


        关于interval:还有一个重点需要注意的时,这个方法的将它的结果传递到高优化级的调度中(类似于GCD队列)。也就是说之前的代码实际上有一个微秒的BUG的:不能直接执行更新UI的代码。可以将interval: signal的结果传递到主线程调度中结果这个问题:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. RAC(self.textField.text) = [[[[RACSignal interval:1] startWith:[NSDate date]] map:^id(NSDate *value) {  
  2.    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:(NSMinuteCalendarUnit|NSSecondCalendarUnit) fromDate:value];  
  3.    
  4.    return [NSString stringWithFormat:@"%d:%02d", dateComponents.minute, dateComponents.second];  
  5. }] deliverOn:[RACScheduler mainThreadScheduler]];  

       这样就好点了。


       这篇文章介绍了一些常用模式,最佳实践还有一些陷阱。希望能帮助你利用ReactiveCocoa构建声明式应用程序。

UNet改进(6):基于注意力机制的多尺度医学图像分割方法 本文提出了一种集成多尺度注意力机制的UNet改进模型UNetWithAttention,用于提升医学图像分割性能。该模型在标准UNet架构基础上,设计了并行3×3、5×5、7×7卷积核的多尺度注意力模块,通过特征拼接和Sigmoid激活生成注意力权重,实现了对不同尺寸病变的自适应关注。模型采用分离式设计,将特征提取与特征选择解耦,在编码器-解码器各阶段嵌入注意力模块。实验表明,该方法在视网膜血管分割和肺结节检测任务中优于标准UNet,Dice系数和IOU分别提升2.6%和4.1%,同时保持计算效率。 阅读详情

相关推荐

手把手拆解DGX GB200 NVL72:1个机柜如何塞进72块GPU?详解NVLink Switch铜缆背板设计

本文深度解析英伟达DGX GB200 NVL72系统如何通过NVLink Switch铜缆背板设计,在标准42U机柜中集成72块B200 GPU,实现1800GB/s的超高带宽。文章详细介绍了模块化架构、铜缆互连技术、液冷散热方案和高密度供电系统等核心创新,为AI算力需求提供突破性解决方案。

red88的博客 1579

RxSwift之UI控件UIGestureRecognizer扩展的使用

RxCocoa 同样对 UIGestureRecognizer 进行了扩展,并增加相关的响应方法。现在以滑动手势为例做具体说明,其它手势用法也是一样的。 当手指在界面上向上滑动时,弹出提示框,并显示出滑动起点的坐标,效果如下: 响应回调的示例一: // 添加一个上滑手势 let swipe = UISwipeGestureRecognizer() swipe.direction = .up self.view.addGestureRecognizer(swipe) // 手势响应 swipe.r.

╰つ栺尖篴夢ゞ 1384

开关电源环路稳定性分析(01)-Buck变换器

这篇文章主要是根据Buck变换器的拓扑结构,利用欧姆定律,基尔霍夫定律,积分微分,这些我们所熟悉的理论推导出了开关电源输入和输出关系的表达式,我相信看完这篇文章,应该是可以自己推导一次。在后面的文章中,我们同样会按照这样的风格,尽量使用大家都已经掌握的知识,来一步一步的拆解晦涩难懂的环路稳定性的问题,在前面先把积木搭起来,后面综合分析的时候就不会显得那么困难!

D_Katter的博客 3833

iOS手势UIGestureRecognizer

UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,它有6个子类处理具体的手势: 1.UITapGestureRecognizer (任意手指任意次数的点击) // 点击次数 numberOfTapsRequired // 手指个数 numberOfTouchesRequired    [plain] v

723

风光储互补微电网在偏远地区的应用实践:从建模到仿真全解析

本文深入解析了风光储互补微电网在偏远地区的应用实践,从系统设计到仿真建模全流程。通过Simulink等工具进行动态仿真,验证了系统在多种工况下的可靠性,并结合实际案例展示了其显著的经济和环保效益。文章为从业者提供了从技术路径到实施优化的全面指导。

weixin_29047545的博客 270

单细胞monocle3分析流程再整理

定义root cell, 推断拟时方向# 结合先验知识自定(示例数据)# 可视化示例数据,起点是随便点的。

zfyyzhys的博客 2101

RAC笔记

//signal1,signal2有任何一个被订阅,即x等于一个RACTuple RACSignal *signal1 = [RACSignal defer:^RACSignal *{         NSLog(@"aaaa");         return [RACSignal return:@"hello111"];     }];   

CodeMachine的专栏 2394

BambuStudio学习笔记:GCode 类

关键成员解析 核心配置组件 状态跟踪系统 功能模块集成 核心方法剖析 主输出管道 实现多阶段处理: 分层处理流程: 实现智能路径规划: 关键特性: 实现模板故障检测: 采用三级流水线: 支持扩展类型: 实现多通道输出: 采用: 实现: 支持: 支持模块化编译: 典型流程: 实现功能:

zzzkk2009的专栏 927

RAC简单使用

简介 RAC-ReactiveCocoa 响应式编程,它可以用来代替系统的一些事件(点击,通知kvo,定时器等等)。用它可以更方便的处理系统事件。往往MVVM中用它处理kvo。其实mvc或者mvp或者mvvm等都可以用rac来处理事件,只不过mvvm用rac来代替kvo更方便而已。 示例代码 - (void)viewDidLoad { [super viewDidLoad]; ...

qq_17190231的博客 382

coze开发-5、给智能体添加“技能”

中间编排与技能组件 中间编排的定义 中间编排是指在智能体的构建过程中,使用一些工具对智能体进行协调和管理。通过这些工具,我们能够更好地实现智能体在特定业务场景中的应用。

andyyah晓波的博客 527

深度学习与西储大学轴承数据集(一)

西储大学数据集介绍

weixin_50642818的博客 1万+

ReactiveCocoa入门教程,以及MVVM模式

ReactiveCocoa入门教程,以及MVVM模式

lover0920的专栏 1002

使用GBIF获取生物多样性数据与GIS的结合

随着全球生物多样性的重要性日益凸显,越来越多的研究人员和保护机构开始利用地理信息系统(GIS)来分析和可视化生物多样性数据。GBIF(全球生物多样性信息设施)作为一个全球性的生物多样性数据库,提供了大量的物种分布和分类信息,为研究人员和保护工作者提供了宝贵的数据资源。本文将介绍如何使用GBIF API获取生物多样性数据,并将其与GIS技术相结合,以便更好地理解和研究生物多样性。利用GIS的强大功能,我们可以在地理空间上可视化物种分布、分析物种多样性的空间格局,并为保护生物多样性提供科学依据。

BnxBackend的博客 1763

ReactiveCocoa入门教程二

上一篇文章我们使用ReactiveCocoa搭建了一个简单的登录页面,这一次我们来搭建注册页面。 本篇代码在https://github.com/Ekulelu/ReactiveCocoaRegister Account和password的有效规制还是和之前一样,长度必须大于5,否则输入框背景色是红色的,这一步直接用

Ek的博客 706

Statistics and Machine Learning Toolbox

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

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

ReactiveCocoa入门教程一

ReactiveCocoa框架是Github开源的一个应用于iOS和MacOS开发的新框架,使用它能大幅度改变在“苹果体系”里面的编程习惯。所以如果是有一些iOS编程经验的人来看这个框架的使用方法可能倒会觉得不习惯。这里不想从比较两种编程的区别来引入ReactiveCocoa,因为这样会让人觉得更混乱。希望读者能把iOS的编程套路忘记后来看这篇文章,以免造成不习惯或混乱,毕竟ReactiveCoco

Ek的博客 1100

老版QQ原生表情gif动态

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

ReactiveCocoa入门教程——第二部分

转自:http://benbeng.leanote.com/post/ReactiveCocoaTutorial-part2 本文翻译自RayWenderlich  ReactiveCocoa Tutorial – The Definitive Introduction: Part 2/2   ReactiveCocoa是一个框架,它能让你在iOS应用中使用函

Dogg 282

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

ReactiveCocoa入门教程

前言 很多blog都说ReactiveCocoa好用,然后各种秀自己如何灵活运用ReactiveCocoa,但是感觉真正缺少的是一篇如何学习ReactiveCocoa的文章,小编看了很多篇都没看出怎么使用ReactiveCocoa,于是决定自己写一遍关于学习ReactiveCocoa的文章,本文主要针对如何从零开始学习ReactiveCocoa,这里非常感谢3个人(支点的雷纯锋,camera360

wsh的专栏 381

ReactiveCocoa入门(一)

ReactiveCocoa 其实所谓的 RAC 指的就是 RactiveCocoa ,Github的一个开源框架。简单的说,他是一个函数响应式编程的框架。

一点点积累 734

ReactiveCocoa入门

概述 为什么要使用RAC? 一个怪怪的东西,从Demo看也没有让代码变得更好、更短,相反还造成理解上的困难,真的有必要去学它么?相信这是大多数人在接触RAC时的想法。RAC不是单一功能的模块,它是一个Framework,提供了一整套解决方案。其核心思想是「响应数据的变化」,在这个基础上有了Signal的概念,进而可以帮助减少状态变量(可以参考jspahrsummers的PPT),使用MVVM架构,

有志者事竟成-程序员也可以创造优雅的艺术 567

ReactiveCocoa入门教程:第一部分

本文翻译自RayWenderlich,原文:ReactiveCocoa Tutorial--The Definitive Introduction: Part 1/2 作为一个iOS开发者,你写的每一行代码几乎都是在相应某个事件,例如按钮的点击,收到网络消息,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation)。但是这些事件都用不同的方式来处理,比如action

ruglcc's blog 1137

ReactiveCocoa 和 MVVM 入门

翻译自ReactiveCocoa and MVVM, an Introduction. 文中引用的 Gist 可能无法显示。为了和谐社会, 请科学上网。 MVC 任何一个正经开发过一阵子软件的人都熟悉MVC,它意思是Model View Controller, 是一个在复杂应用设计中组织代码的公认模式. 它也被证实在 iOS 开发中有着第二种含义: Ma

江湖两把刀的技术博客 1841

ReactiveCocoa框架菜鸟入门 系列

ReactiveCocoa框架菜鸟入门(一)——CocoaPods添加ReactiveCocoa             ReactiveCocoa框架菜鸟入门(二)——MVVM架构与ReactiveCocoa框架        ReactiveCocoa框架菜鸟入门(三)——信号(Signal)与订阅者(Subscriber)

ruglcc's blog 1076
上一篇: iOS上的ReactiveCocoa响应式编程
下一篇: ReactiveCocoa基本组件:理解和使用RACCommand
kintan哥
博客等级 码龄12年 11粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值