Why Reactive(Cocoa)?-时间线、输入、输出、复杂性、异步、状态、聚合
To put it another way, the output at any one time is the result of combining all inputs. The output is a function of all inputs up to that time.
摘要:
1、It can remove a significant amount of complexity from our programs and make our code easier to reason about.
2、The problem is that we rarely (read: never) are updating our output based on just one input/event. I can’t put it any better than the way Josh stated it:
“To put it another way, the output at any one time is the result of combining all inputs. The output is a function of all inputs up to that time.”
3、In addition, these inputs are littered up and down our source file, all with slightly different interfaces for the developer to remember. We now have many related inputs looking very unrelated in our code, making the work of mentally mapping out their relationships difficult. In other words, it makes it hard to reason about our code.
4、Basically, we program in linear fashion;Our asynchronous callbacks and other events are still occurring in a linear fashion.
5、Whenever one of these events happens, we likely need to generate output. To do that, we need to combine the new information from this event with all the information from previous events relevant to this particular output.
6、We want to define the relationship between events (inputs), define their subsequent outputs, and then let the computer react appropriately whenever those events occur. State still exists somewhere in this event system, but it’s largely abstracted away from our day to day work. That’s a big win. The paper tape still exists, but it’s all under the hood.
Why
Anyone who builds things for a living should always be striving to improve their skillset. This means investigating new ways of doing and thinking whenever possible. As programmers one of the hardest things we have to do on a regular basis is to be able to reason about our code1; to have a mental map of the implementation used to solve a complex requirement. To me, this is the biggest gain provided by the reactive model of programming. It can remove a significant amount of complexity from our programs and make our code easier to reason about.
For a more authoratative read about reactive programming, you should go read the article “Inputs and Outputs” by Josh Abernathy, one of the creators of ReactiveCocoa. It’s an extremely well written article that I can only hope to supplement with a slightly different explanation. (I’ll be rehashing a bit of what he’s covered there.)
Inputs and Outputs
So what does Josh mean when he says it’s all Inputs and Outputs? The entirety of our job, the meat and potatoes of what we are doing when we build an app, is waiting for events to happen that provide some sort of information (inputs), and then acting on some combination of those inputs and generating some kind of output. Inputs come in all kinds. They provide us with varying levels and types of information:
This is just a sampling of the different kinds of inputs we deal with daily. The information they provide can be as simple as “This event happened”, or be accompanied by a lot of detail about the event such as “The user entered these new characters in the text field”. There are certainly reasons for all the different patterns above, not the least of which is the evolution of our craft and tools; but when it comes down to it they are ALL just telling us some event happened, and sometimes providing extra information about that event.
Outputs can be anything, but a few typical examples include updating a value on a server, storing something in core data; or most importantly, and most typically, updating the UI.
The problem is that we rarely (read: never) are updating our output based on just one input/event. I can’t put it any better than the way Josh stated it:
“To put it another way, the output at any one time is the result of combining all inputs. The output is a function of all inputs up to that time.”
I will add one point pertinent to this article. We often don’t really care what order these inputs came in from an application design perspective, but from an implementation perspective it’s something we are constantly dealing with. In addition, these inputs are littered up and down our source file, all with slightly different interfaces for the developer to remember. We now have many related inputs looking very unrelated in our code, making the work of mentally mapping out their relationships difficult. In other words, it makes it hard to reason about our code.
Paper Tape Computing (Linear Programming)
The issue here is one of time, or more accurately, the timeline of execution. Basically, we program in linear fashion, never wandering all that far from the way things were done on paper tape computers or punch cards. We have an understanding that there is a run loop, and that our code is going to be placed on a timeline and executed in order (ignoring multiple processes for the sake of argument.) Even our awesome block callbacks and delegates are just giving us another snippet of time on the timeline where we can execute code. In fact, all our code is driven by inputs (events) just giving us another chance to insert some paper tape, as shown in this beautiful (and super simplified) diagram.
Our asynchronous callbacks and other events are still occurring in a linear fashion. The period of time in which the data from these events is available to us is limited to a small spot on our linear execution timeline (scope).2 Even if all these events occurred at the same exact millisecond, the CPU would still have to handle one at a time. Our code is stuck executing in single file, with no knowledge of what happened before it.
Whenever one of these events happens, we likely need to generate output. To do that, we need to combine the new information from this event with all the information from previous events relevant to this particular output. Our blocks and delegate calls may be asynchronous, but we still have to deal with the consequence of when they occured on our timeline.
But how do we do that? The information from those previous events isn’t available in the same scope as the current event we’re dealing with.3 There’s no elegant mechanism provided for accessing past events, or combining the information from all relevent events. Since these inputs are essentially isolated from each other in this linear style of programming, we have to imperatively (directly) go and check the status of any dynamic information that other inputs could have changed beforehand. That is to say any time there is an event (input), and we’re given a chance to run some more paper tape, we do a lot of this type of thinking in code:
“Ok lets check what we’ve got here. User tapped a button eh? Well we’re going to want to show the menu then, but a couple things first: Is this user logged in? Good they are. And has the data for this menu loaded in or are we still pulling that from the server? Ahh good we already have that. Finally, the menu isn’t already showing is it? Ok it isn’t, in which case I’m going to go ahead and show it. Let’s write down that it’s showing now, so I know in the future.”
Basically anytime we get the opportunity to run a bit more code via some event, we are doing so with the memory of a goldfish.4 Each time we start with no idea what’s happened previously and have to go check a bunch of statuses to build enough context to correctly generate the output we need. The system is “dumb” and doesn’t know what information we might need for that particular output, so it can’t track it for us. We are left to our own devices to come up with a solution, and end up tracking any possibly relevant inputs ourselves using state.
STATE
State is what makes our job as programmers VERY hard sometimes. To be honest, I didn’t recognize this. That is to say, I knew when I had lots of different events and variables affecting my UI that it became really hard to manage; but I didn’t recognize it in a philosophical, definable way. It’s so ingrained in me that I just thought it was part of the deal with programming, and that maybe I wasn’t the best programmer for constantly struggling with it.
This is not the case. Everyone sucks at managing state. It is the source of an endless amount of bugs and blank stares. “I understand WHY it crashed. I just don’t understand how the user could have possibly gotten it in that state.” ← Programmer adds another state check.
So what is state? Are we just talking about enums and state machines like TCQuestionDetailViewControllerState
? Nope. This is all state:
That should have made you cringe. I’m SURE you’ve seen (and written) similar code. If not you are a WAY better programmer than I am. UI’s are often very complex in code even when they appear simple to the user. In fact, the very reason a user may LOVE your app is the amount of power it delivers in an extremely simple interface.
Value is created by swallowing complexity for the user. - CEO of my first startup
The problem here is that every time you add another state, you are increasing the possible number of combinations in an EXPONENTIAL manner. And that’s assuming your states are just BOOLs. I had an “aha!” moment when I saw a slide in a talk by Justin Spahr-Summers.
I looked at my code, like the interface above, and realized I was giving myself an unbelievably difficult task, requiring super-geek like abilities to pull off (to the tune of 4000+ different combinations I needed to handle if they were all relevant to the output). Obviously this is HIGHLY error prone.
To make matters worse, this type of code will often produce UI only bugs that are incredibly hard, if not impossible, to identify in any automated way. After a few times through this wringer, we’ve probably all ended up writing centralized update methods that check a bunch of properties and update things accordingly. We end up with methods like this littered throughout our code: updateViewCommentStatus
updateChangeAnswerButtonText
. Any time we add another event (input), we make sure it’s updating all the relevant states (e.g. properties) and call the appropriate centralized update methods.
We are expending an awful lot of mental energy dealing with the consequences of this linear code execution thing, this modern version of the paper tape computer. Despite the power of computers today, we are still doing a heck of a lot of work on their behalf. We’re programming to the way the computer hardware works; to the way that the run loop is creating a timeline and the cpu is processing bits in a single file. We are architecting our code around low level implementation details of computing. What if we were to harness the power of the computer, let it do more of the work, and allow ourselves to think and design our apps in a more sane manner?
What if we abstract away the whole pesky notion of linear code execution, explain to the computer what combinations of inputs we are interested in for a particular output, and let the computer track state over time for us? Seems like something the computer would be good at; and we’re certainly awful at it.
Compositional Event System (Non-Linear Programming)
I’m not a classically trained, CS Degree wielding programmer. I did a lot of multimedia before ending up programming for my day job. In that time I’ve seen a lot of tools make the jump from linear to a non-linear style of thinking and working. I’ll talk about tools in another post, but even auto-layout is a great example of moving towards a non-linear (and reactive) approach. Instead of waiting for certain events to occur, then checking the status of a bunch of views and imperatively updating frames, you just describe what the relationships between all the views are ahead of time and let the computer do the work.
In the discussion about the correct terminology to describe RAC and similar styles of programming, the term “Compositional Event System” has been brought up. I think it fits really well. Much like the shift in the multimedia tools I mentioned, what we really want to do is remove (for the most part) the need to account for the timeline of when events (inputs) happen, and therefor the need to manually keep track of them with state. We want to make the computer do that for us.
We want to define the relationship between events (inputs), define their subsequent outputs, and then let the computer react appropriately whenever those events occur. State still exists somewhere in this event system, but it’s largely abstracted away from our day to day work. That’s a big win. The paper tape still exists, but it’s all under the hood.
When you think about it, this concept is actually very simple, and not entirely foreign. Inputs and outputs 5:
ReactiveCocoa
So how does ReactiveCocoa abstract away the timeline for us and step into the world of Non-Linear Programming? It does this by wrapping all those types of input from above (delegate, KVO, completion blocks, etc) in one unified interface called a Signal (RACSignal
).
Think of a signal as a representation of future values from your input. It’s similar to a promise/future which you may have used, but more robust in that it can continually send values (it isn’t limited to just one). While this is similar to a KVO block repeatedly being executed as it observes changes, the difference here is that we now have an object representing those future values. We can take that representation and combine it with other signals to build relationships among our events, and describe how data will flow through our app. This is done with powerful operators that can transform and filter our data into new signals, eventually arriving at the data we need for our output.
http://www.sprynthesis.com/2014/06/15/why-reactivecocoa/
Why Reactive(Cocoa)?-时间线、输入、输出、复杂性、异步、状态、聚合的更多相关文章
- 模拟n个人参加选举的过程,并输出选举结果:假设候选人有四人,分别用A,B,C,D表示,当选某候选人时,直接输入其编号(编号由计算机随机产生,若输入的不是A,B,C,D则视为无效票,选举结束后按得票数从高到底输出候选人编号和所得票数.
模拟n个人参加选举的过程,并输出选举结果:假设候选人有四人,分别用A,B,C,D表示,当选某候选人时,直接输入其编号(编号由计算机随机产生,若输入的不是A,B,C,D则视为无效票,选举结束后按得票数从 ...
- H面试程序(1)编写一个函数,要求输入年月日时分秒,输出该年月日时分秒的 下一秒
编写一个函数,要求输入年月日时分秒,输出该年月日时分秒的下一秒. 如输入 2004 年 12 月 31 日 23 时 59 分 59 秒,则输出 2005年 1 月 1 日 0 时 0 分 0 秒. ...
- qemu:///system 没有连接驱动器可用;读取数据时进入文件终点: 输入/输出错误
原因 1. KVM的相关包 装少了 2KVM的相关包 重新安装 3 May 31 15:22:55 localhost libvirtd: 2019-05-31 07:22:55.554+0000: ...
- [HMLY]9.深入浅出-iOS Reactive Cocoa的常见用法
简介 今天的主角是Reactive Cocoa,聊聊Reactive Cocoa的常见使用:KVO.Target.Delegate.Notification. Reactive Cocoa 是一个重量 ...
- iOS-Reactive Cocoa的常见用法
今天是周末,临近年底,工作上遇到不可抗力,会有点一些变动!这多少会让人有一点静不下来,但需克制,Reactive Cocoa是今天的主角! 废话不多说,今天聊聊Reactive Cocoa的常见使用! ...
- 设计Twitter 时间线
「design Twitter」是 LeetCode 上第 335 道题目,不仅题目本身很有意思,而且把合并多个有序链表的算法和面向对象设计(OO design)结合起来了,很有实际意义,本文就带大家 ...
- 输入/输出系统的四种不同工作方式对CPU利用率比较
程序控制工作方式:输入/输出完全由CPU控制,整个I/O过程中CPU必须等待其完成,因此对CPU的能力限制很大,利用率较低 程序中断工作方式:CPU不再定期查询I/O系统状态,而是当需要I/O处理时再 ...
- [转]C语言文件输入/输出ACM改进版(freopen函数)
C语言文件输入/输出ACM改进版(freopen函数) 2009年5月27日 10:379,457 浏览数发表评论阅读评论 文章作者:姜南(Slyar) 文章来源:Slyar Home (www. ...
- ubuntu12.04软件中心打开错误和 ubuntu 包管理之“:E: 读错误 - read (5: 输入/输出错误) E: 无法解析或打开软件包的列表或是状态文件。”的解决
执行ubuntu软讲中心时打不开.老是崩溃,从终端也下载不了软件. 执行包管理的update或者search等等会报错: E: 读错误 - read (5: 输入/输出错误) E: 无法解析或打开软件 ...
随机推荐
- 【7】.net WebAPI Owin OAuth 2.0 密码模式验证实例
1.OAuth密码模式 2.在VS中创建WebAPI项目 在nuget中安装: Microsoft.AspNet.WebApi.Owin Microsoft.Owin.Host.SystemWeb 这 ...
- WPF月视图控件
简介 在做一个应用时,需要做成日历月视图的形式.自己做较麻烦,于是上网找找看,在CodeProject上发现了这个Quick and Simple WPF Month-view Calendar,可是 ...
- 七、curator recipes之阻塞队列SimpleDistributedQueue
简介 Java在单机环境实现了BlockQueue阻塞队列,与之类似的curator实现了分布式场景下的阻塞队列,SimpleDistributedQueue 官方文档:http://curator. ...
- java:模拟栈操作
import java.util.ArrayList; public class MyStack { private ArrayList<Object> arrayList; public ...
- fuzhou 1692 Key problem ***
Problem 1692 Key problem Accept: 103 Submit: 553 Time Limit: 1000 mSec Memory Limit : 32768 KB ...
- C# 调用C/C++动态链接库,结构体中的char*类型
用C#掉用C++的dll直接import就可以之前有不同的类型对应,当要传递结构体的时候就有点麻烦了,这里有一个结构体里边有char*类型,这个类型在C#中调用没法声明,传string是不行的默认st ...
- JS 变量 命名规范 oDiv aDiv 等
l命名规范及必要性 l可读性--能看懂 l规范性--符合规则 l匈牙利命名法 l类型前缀 类型 前缀 类型 实例 数组 a Array aItems 布尔值 b Boolean bIsComplete ...
- Vuex2.0边学边记+两个小例子
最近在研究Vuex2.0,搞了好几天终于有点头绪了. 首先vuex概念比较多,一定要搞懂里面的概念,可以参考官网Vuex2.0概念,我写此文的目的是希望能对前端爱好者提供个参考,加深对vuex2.0各 ...
- vmware 虚拟机导入OVF出现路径错误
现状: 需要将原有数据中心的VM虚拟机导出本地OVF模板,然后迁移至新的机房虚拟化环境后从新导入. 问题: 导入OVF时候,先出现错误问题1,修复完成后,出现错误问题2 1. OVF迁移至本地以后,导 ...
- 《Linux命令行与Shell脚本编程大全第2版》读书笔记
公司说不准用云笔记了,吓得我赶紧把笔记贴到博客上先..... 近3年前的了,只有一半的章节,后面的没空记录了.... 第1章 可以cat /proc/meminfo文件来观察Linux系统上虚拟内存的 ...