Tag: 编程

高阶功能适用于优雅的高级编码器

(((((()-> {})-> {})-> {})-> {})-> {} 好。 这篇文章有点愚蠢,因为我将使用另一个高阶函数编写一个高阶函数,以便向您展示什么是高阶函数。 我希望我不会犯任何错误。 高阶函数是将函数作为其参数的函数。 好吧,我认为该陈述并不能解释“全部”,但这是我可以向任何非编码者朋友解释的最简单的方法,所以请问。 无论如何,许多编程语言中都存在高阶函数。 我将在本文中使用Swift,但是所有其他语言的概念应该相同。 让我们深入研究。假设我们有一个整数数组。 让数组= [1,2,3,4] 这是将所有元素乘以2的Computer-science-101方法,这是 var newArray = [Int]() 对于0中的i .. <array.count { 让element = array [i] * 2 newArray.append(element) } print(newArray)// [2,4,6,8] 实际上,这里的for循环可以被forEach函数代替,后者是Swift附带的高阶函数。 甜… var newArray = [Int]() array.forEach({ newArray.append($ 0 * 2) }) print(newArray)// [2,4,6,8] 请注意,我们没有将0乘以2。 $ $ 0只是保留的简短形式,表示闭包的第一个参数。 不要问我为什么是$ 0。 […]

iOS的调查见解..第1部分

上周,我进行了一项调查,以更好地了解iOS开发人员的喜好和品味,我的目标是收集信息和反馈,并使用这些数据作为该杂志上未来文章的输入。 看起来有人试图逃避自己的意见,对吗? 除了笑话,总是可以使用更多数据做出决策,这是一种很好的方式,首先可以让听众听到他们感兴趣的内容。 您可以在此处找到有关该调查的更多信息。 免责声明** 首先,我必须说,这个结果没有成为iOS社区声音的幌子,而且它们肯定没有统计上的显着性。 到现在为止(出版时间),只有22个人足够捐出5分钟的时间用于慈善事业。 就是说,我仍然认为,在下面您可以找到很多反馈和见解。 给我看钱..我的意思是见识.. Q1,您喜欢哪种学习形式? 第一个问题是关于学习习惯,以及受众如何喜欢使用iOS内容。 截屏视频占了最大份额,紧随其后的是博客文章和源代码 ,这对博客作者而言是个好消息。 关键见解 如果您要创建包含截屏视频的博客文章,并且要通过GitHub来访问源代码, 那绝对是对的! Q2,您使用什么语言? 第二个问题是关于过去x未来,因为我们都知道swift是一种令人惊讶的语言,它是有史以来使用率最高的语言之一,但是仍然存在普通objc的空间。 关键见解 没有办法从迅捷中退回,为什么有人要这样,对吗? 就是说,很高兴拥有objc的经验。 **此图表可能因行业,应用程序利基和许多其他原因而发生巨大变化。 为了便于讨论,让我们继续关注22个善良灵魂的小宇宙.. =) Q3,哪些书可以帮助我度过难关? 问题三是关于书的。 尽管人们学得不同,但很多时候没有更好的方法来获得最终的20%(80 | 20)。 无论您走到哪里,诸如Clean代码,Big Nerd Ranch书籍,objc.io书籍之类的书都始终显示在顶部,我绝对会建议您看看。 Q4和Q5,好的ios内容在线..在哪里? 问题四和五与在线上出色的ios内容有关。 我们很幸运,可以生活在一个人真正可以成为大师而无需离开家的时代。 社交互动,大学,离线课程等仍然一如既往地重要,但替代方案每天都在增加。 从站点到闲散社区,twitter帐户,github存储库,电子邮件列表,学习平台,udemy等。 列表不断变得越来越好。 Realm.io,objc.io,nshipster,raywenderlich,WWDC会话,natashTheRobot, 一点点可可,iOS开发者每周,appcoda等。这只是在线上可提供的惊人内容的一个示例。 关键见解 在线上有很多很棒的内容,如果您想学习iOS并真正精通它,现在是时候了, 没有更多借口了 ! 简而言之.. 再过几天,我将发布本博文的第二部分,其中包括调查的更多见解和反馈。 下一篇文章将解决以下问题 : –您最喜欢iOS平台什么? –您对iOS开发有什么不满意的地方? –您能告诉我们您在iOS平台上确实不喜欢的东西吗? –您想在iOS课程中看到哪些内容? 更新: 您可以在此处检查第二部分。 与往常一样,任何想法,疑问或反馈都值得欢迎。 […]

Swift 101 —类型别名

这是遍历Swift声明( typealias )的超快速博客。 苹果公司将其描述为: 类型别名声明将现有类型的命名别名引入程序。 简单来说,这意味着您可以命名( 别名 )现有类型,例如String , Int或Bool ,实际上几乎是任何名称(不包括某些swift keywords )。 这可以使您的代码更具可读性。 让我们看一下我们之前使用的示例: //此示例中的购物篮是一个Items数组。 其中项目是字符串的类型别名 typealias项目=字符串 typealias篮子= [物品] var篮子:篮子= [] basket.append(“ Apple”) 这意味着可以将Items添加到Baskets 。 这比将Strings添加到[String]更具可读性。 此处的Items可以与其父类型String完全相同的方式创建。 让项目:项目=“苹果”

功能性Swift-咖喱

在使用Swift时,我在函数式编程环境中进行了越来越深入的研究。 在其他编程语言(例如Python或Haskell)中使用的许多技术可以迅速获得。 今天,我想向您介绍其中一种,称为currying。 Swift是一种出色的编程语言,它利用了函数式编程的优势。 函数式编程的主要好处之一是函数是高阶公民,这意味着迅速使用函数可以执行以下操作之一: 将一个或多个函数作为参数 返回一个函数作为参数 最近,我在函数程序员Curry中发现了一种众所周知的技术。 Currying用于将具有多个参数的函数分解为一系列包含参数的函数。 当您想提高代码的可读性和可重用性时,此技术变得非常有用。 该函数如下所示: 如您所见,咖喱是一个简单的功能。 它以一个函数作为参数( fn ) 首先返回一个函数 ,该函数采用传入参数的函数的第一个参数传递给curry(此处为A ): (a: A) -> (B) -> C 然后,它返回一个函数 ,该函数采用传递给curry的函数的第二个参数(此处为B ): (b: B) -> C 最后,使用参数A和B调用作为参数传递的函数 : fn (a,b) 值得注意的是,函数fn仅在最后一个参数传递给curried方法时才计算 。 在某些情况下,此方法可能有用,其中一种情况是您希望使现有方法更方便或可重复使用: 让我们采用以下日志方法: 使用两个参数调用它可能变得很乏味,使用curry我们可以使它可重用且更明确,而无需创建一个封装参数的新函数。 充分利用高阶函数的优势,我们可以分解logMessage并创建一个变量,该变量是一个将日志消息作为参数的函数,然后将其记录在调试级别。 另一个用途是利用诸如map , forEach等功能性方法。 让我们来看下面的例子: 如您所见,使用currying可以很容易地部分应用任何方法。 (Vincent Pradeilles在我当时所在的CocoaHeads展示了这种用咖喱粉的用例。) 如果您正在使用RxSwift或计划使用它,您可能想知道如何将使用completionBlock的异步代码迁移到一系列Observable。 重构所有代码库只是为了使其可观察而不是(completionBlock /成功和失败块)通常是不可行的。 使用curry和扩展,您几乎不需要代码即可实现。 Rx + FromAsync […]

建筑设计模式:VIPER

抱歉,延迟了,但是在阅读了文章之后,我意识到NasaAPOD应用程序的当前安装方式对于实施VIPER并不是很有趣。 应用程序内部需要进行更多的交互,因此我回到了MVC,MVVM和MVP来全面实现相同的功能。 我所做的是添加了“收藏夹”功能,该功能只是将您的收藏夹移到表视图的顶部(实际上并没有保存任何内容)。 因此,至少MVP和VIPER现在更加有趣了。 我不确定的一件事是如何为单元设置演示者/交互者。 似乎应该有一个presenter / interactor组件,因为它还可以处理图像缓存。 但是我不能完全考虑如何确保我没有制造大量或可能泄漏的材料。 auth0.com教程肯定有很大帮助,所以我的VIPER应用程序很大程度上基于它。 我发现有些奇怪,但根据以前的工作是很正常的,是当用户点击某些内容时,它会通过演示者而立即返回视图。 例如,用户点击信息图标,视图告诉演示者用户点击,演示者返回查看告诉其发生点击并显示详细信息。 auth0网站还建议您不要手动创建所有文件(我做了🙃),他们建议使用工具为您生成文件。 因为我决定手动创建所有文件,所以我确实很难考虑应用程序所需的每个文件的所有交互和协议。 如此之多,以至于我把它抽了出来。 我所做的一件事有些不同,那就是该应用程序如何设置演示者和交互者。 auth0站点将这些变量公开,但是我想尽可能地保持所有私有。 所以我添加了attachView(viewInteractor:) , attachInteractor(interactor:)和attachPresenter(presenter:)函数。 您可以在下面看到完整的应用程序。 ashleyng /建筑设计模式 通过在GitHub上创建一个帐户来为ArchitectureDesignPatterns开发做出贡献。 github.com 到目前为止,这是最有趣的学习模式,并且肯定有很多设置需要使它起作用。 话虽如此,我现在不认为VIPER是我的选择。 我仍然不太了解Router部分,但是如果没有Router ,也许还有VIPER的味道? 比较MVVM和Viper架构:何时使用一种或另一种 TL; DR:设计良好的体系结构对于长期保持项目可维护性很重要。 在这篇文章中… auth0.com 视图,交互器,演示者,实体和路由器 视图 —界面层(UIKit文件)。 视图负责显示演示者要求他们执行的操作,并将用户输入回传给演示者 Interactor —负责从模型层(使用网络或本地数据库)获取数据,并且其实现完全独立于用户界面。 演示者 —查看逻辑以格式化要显示的数据。 这是MVVM中ViewModel完成的工作的一部分。 演示者从交互器接收数据,创建视图模型并将其携带到视图。 还对用户输入做出反应,请求更多数据或将其发送回交互器 实体 -模型层职责的一部分。 没有业务逻辑的纯数据对象。 由交互者管理。 路由器 -应用程序的导航逻辑。 示例:如果必须在iPad应用程序中重用相同的iPhone视图,则唯一可能改变的是视图的显示方式。 这使您的其他图层保持不变。 示例应用 视图 […]

SceneKit中的自定义几何

作为高级3D渲染框架,SceneKit允许我们通过简单地从3D建模软件导入3D对象来渲染它们。 它具有一些内置的原始形状( SCNPlane , SCNBox , SCNSphere等),使我们能够以非常简单的方式在屏幕上绘制3D几何形状。 然后,我想知道是否有可能以编程方式生成自定义几何,因为我觉得在可视化复杂数据方面可能很有用。 在SceneKit的文档中,答案是肯定的,可以通过SCNGeometrySource和SCNGeometryElement 。 这让我很兴奋,所以我继续上网,发现了一个简单的几何图形,而八面体的SceneKit并没有提供这种几何图形(就像两个金字塔粘合在一起)。 在3D计算机图形学中,3D对象通常由多个三角形表面组成。 我们将需要两组数据来绘制这些曲面,它们是3D对象角(也称为顶点)的位置以及将这些顶点连接以创建三角形曲面的序列。 在编写代码之前,让我们取一个八面体,并为其每个顶点赋予一个从零开始的数字。 当我们稍后在代码中定义顶点时,顶点0将是第一个顶点,顶点1将是第二个顶点,依此类推。 接下来,确定3D空间中所有顶点的坐标。 我估计了如下图所示的坐标,您可以将它们调整为任意的值。 接下来,我们需要定义八面体的表面,这也是这些顶点之间的连接顺序。 由于八面体的所有表面均为三角形,因此我们不必将表面分解为多个三角形。 但是,定义序列可能会有些棘手,因为大部分时间只绘制表面的一侧(正面)。 因此,如果您看着表面的背面,它将是透明的。 您可能会问SceneKit如何知道哪一侧是正面。 好吧,我们通过定义序列的方式告诉它。 如果曲面的顶点是正面,则以逆时针顺序定义。 因此,您将获得如下序列: 如果顺序不同,也可以,只要按逆时针顺序定义曲面即可。

使用NSUndoManager获得乐趣和收益

在现实世界中,现实世界仅限于计算机软件领域,撤消操作是一种普遍现象。 在考虑撤消操作时,通常会想到的用例是生产力应用程序(例如文档编辑器)或创造力应用程序(例如照片编辑器)。 确实,在LIVEOP X iOS应用程序中,绘图组件也是我们与NSUndoManager的第一次接触。 在LIVEOP X中,生产力起着关键作用。在紧急情况下,没有错误,误解或“试图打开和关闭”的空间。 如果应用程序没有响应用户期望的响应,则用户将简单地放弃该应用程序,将平板电脑存放起来并提供急救,而无需提供应用程序必须提供的所有基本信息。 为避免这种情况并达到为用户创造价值的目标,我们必须在生产力和应用程序性能方面设定最高标准。 这始于开发,有时我们会发现自己从意外来源获得了一些帮助。 在我们的GEO工具中,第一响应者会得到一个油漆桶,以在地图上绘制说明并与他人共享。 手绘指令在地图上的所有缩放级别上实时呈现,就像它们从一开始就存在。 该工具特别有用,它可以为仍在飞行中的设备勾勒出进场路径,或评估潜在有毒气体云的影响区域。 绘图工具的一部分是撤消按钮,用于撤消先前绘制的线段。 下面给出一个例子。 在代码中看起来如何? 很简单的。 在将线段添加到地图的同时,我们使用单个NSUndoManager为完全相同的线段注册了撤消操作。 -(void)addHandDrawnAnnotations:(NSArray *)annotations { for(注释中的id注释){[self.mapController addAnnotation:annotation];} [self.undoManager registerUndoWithTarget:self选择器:@selector(removeHandDrawnAnnotations 🙂 object:annotations];} NSUndoManager的API使其非常易于使用。 实际上,它在代码库中的适用性和适用性远远超出了前面所述的典型用例。 在明确的用户环境之外撤消操作 在我们的GEO配置门户中,客户可以定义自定义动作并将其附加到地图图层。 然后,只要在iOS应用程序中选择了属于地图图层的注释,便会执行为该图层配置的动作。 动作可能是选择其他地图图层,或显示其他UI元素。 动作只是一个描述,告诉应用程序当用户选择注释时该怎么做。 当操作在服务器配置中发生更改时,我们只需重新创建代表该操作的视图模型即可。 这些动作仅运行一次。 但是,无论是通过编程方式还是由用户取消选择地图图层,或者从同一地图图层中选择新注释时,我们都希望使先前执行的动作的影响无效:所有动作均采用纯净状态。 最初认为,这将需要大量的代码来检查已执行了哪些操作,在应用程序中查找结果并将其与结果匹配,然后将其丢弃。 但是,将结果(例如,由于操作而添加的额外UI)与操作视图模型耦合在一起是不可行的,因为视图模型是动态创建的。 NSUndoManager在这里形成了一个很好的解决方案。 另外,总的来说,我们希望尽可能避免冗长的代码。 在地图层视图模型上,我们定义了一个带有一组的NSUndoManager 。 创建时会打开该组。 然后,每当我们要撤消图层的操作时,我们都会关闭该组,调用-undo ,然后打开一个新组。 我们使用分组以便一次摆脱所有动作。 撤消操作在执行操作的同时注册。 如果是向UI添加按钮的操作,则如下所示: 这里的model是地图图层视图模型。 请注意, NSUndoManager提供了两种注册撤消操作的方法。 如果撤消选择器只有一个参数,则可以使用registerUndoWithTarget:selector:object 。 对于更复杂的撤消处理,我们可以求助于registerUndoWithTarget:handler: […]

使用Swift 4编码和解码JSON

Apple上周在圣何塞举行的WWDC 2017主题演讲和国情咨文中宣布了Xcode 9以及Swift4。使它成为Swift 4标准库的最重要的变化之一就是一系列编码,解码和解码协议。类型实例的序列化,允许用户与JSON以及与本地磁盘进行相互转换。 这些协议(最著名的是Codable , Encodable和Decodable旨在作为Swift的本机答案,以解决开发人员在Swift 3或更早版本中序列化对象时遇到的一些限制。 这些协议仅在一个星期前就已经流行了,但是Apple可以在线获取一些出色的文档。 我花了一些时间对这些API进行试验,以进一步了解它们的工作原理,可能的功能以及在生产代码库中使用它们可能遇到的一些优点和缺点。 到目前为止,Swift社区中最大的开放问题之一是“您使用哪个第三方框架对JSON反序列化? 还是你自己滚?”。 自从我第一次开始编写Swift以来,我已经尝试了几种第三方框架并开发了自己的框架。 我经常对此感到沮丧的是,每个框架都带来了自己独特的方法,但是它们似乎都误选了可选内容,缺乏强大的错误处理能力,并且使用了不直观的自定义运算符。 Swift 4的Codable协议现在为解决该问题提供了一种通用且推荐的方法,因此我根据一些我经常会遇到的关键用例进行了实验。 反序列化 假设您有一个结构Product并且想从网络请求中收到的JSON响应中反序列化实例。 确保Product和任何自定义属性类型均符合协议Codable (如果不序列化回JSON,则仅Decodable )。 在要将Data对象反序列化为Product模型的那一点上,初始化JSONDecoder对象,然后调用decoder.decode(_: from:) 。 如果解码操作失败,则此函数将引发错误,因此您可能需要将其包装在do,try catch语句中。 就是这样。 假设Product模型上的所有属性名称与您要反序列化的JSON结构中的字段名称完全对应,Swift将处理初始化模型实例所需的所有工作。 序列化 将Product序列化回JSON仅需要模型及其所有自定义属性类型符合协议Codable (如果您不从JSON反序列化,则仅Encodable )。 在您想要将Product实例序列化为要在网络请求或其他任何地方发送的Data ,请初始化JSONEncoder对象,然后调用encode(_:) 。 如果编码操作失败,此函数也会引发错误,请随意将其包装起来,然后尝试再次捕获。 嵌套类型 在Swift 4中,对具有同样也是Codable类型的属性的Product模型进行反序列化变得非常容易。非常简单,只需确保每个嵌套类型都符合Codable (或者在需要时仅Encodable / Decodable )。 就像您期望的那样, JSONDecoder将以与解码顶级对象相同的方式来处理嵌套属性的解码。 自定义属性名称 当然,使用JSON从未如此简单。 作为移动工程师,我们经常无法控制我们正在使用的Network API,并且想要为要从JSON有效负载解码的属性定义自定义字段名称。 重要的是要了解,默认情况下,Swift会自动使用您定义为字段名称的属性名称来从JSON进行解码。 在Codable类型上为属性定义自定义字段名称就像在对象CodingKeys上定义一个枚举一样简单,该对象的rawValue类型为String并符合CodingKey协议。 您需要为模型上的每个属性定义一个案例。 然后,将每种情况的RawValue用作要从JSON解码的JSON字段名称。 自定义键路径 在我尝试使用更复杂的键路径和JSON结构进行的简短介绍中,似乎Swift的处理这些方法需要一些习惯,并且涉及很多样板。 […]

了解一些Lambda毕业生!

我们选择了一些顶尖的学生与您分享。 我们每个学生都有独特的背景和经验。 我们的合作伙伴对这种独特的组合赞不绝口,这些独特的组合产生了一些顶尖的初级开发人才。 让我们知道您是否有兴趣与以下任何候选人交谈,我们将设立电话! Andrew Dahn:iOS Swift,Objective-C,Python和C 位置偏好:华盛顿特区,向弗吉尼亚州和马里兰州开放 目前四月/五月开始面试 安德鲁·达恩(Andrew Dahn)曾经是一名医生。 直到他上大学三年级并在厄瓜多尔进行外科实习之后,他才意识到这不是他的道路。 医学是反应性的,安德鲁想成为积极健康解决方案的一部分。 高三时,他参加了一些设计课程和CS课程,这引起了他的浓厚兴趣。 安德鲁(Andrew)喜欢拥有一个技能组来建立自己脑海中浮现的创意的想法。 大学毕业后,他把自己在加利福尼亚的生活连根拔起,直奔波士顿。 他在一家可持续食品初创公司工作,在那里他亲眼目睹了健康饮食是主动关爱自己健康的重要难题。 安德鲁(Andrew)被工程师创建了一个现场菜单板,该菜单板反映了餐厅库存的新鲜食品。 从头开始创建可以帮助人们日常生活的东西的想法变得越来越有吸引力。 安德鲁目前正在开发一个食谱书iOS应用程序,该应用程序将鼓励健康的饮食习惯,并且很快将其添加到他的产品组合中。 他对iOS开发的创作充满热情,这源于他对艺术的热爱。 关于他想工作的公司,他说:“在我职业生涯的每个阶段,我都想学习。 如果我不学习,那那对我来说不合适。 Linh Bouniol:iOS Swift和Objective-C 地理位置偏好:加利福尼亚州洛杉矶 目前四月/五月开始面试 Linh是Lambda学校坚定而勤奋的毕业生,现在正在iOS软件工程领域寻找职业。 Linh具有药理化学的背景,喜欢复杂的想法和解决问题的方法,她对细节的专注。 在本科期间,Linh通过与一名从事应用程序开发的同学对编程非常感兴趣。 琳(Linh)最初是自学成才,但随着她的兴趣达到顶峰并且越来越着迷,渴望获得更多知识。 她决定研究进一步发展iOS开发方面的知识。 她已经将药理化学的许多必要技能完美地转移到了这一新的职业道路上。 Linh决定就读于Lambda学校而不是药房。 她的创意头脑细致入微,使她在Lambda School的整个旅程中熠熠生辉。 在iOS群组中,Linh是第一个使用自己构建的应用程序在App Store中发布的人。 从头开始构建应用程序,这对她周围的社区既有帮助又有用,令Linh兴奋,并使她为自己选择的职业道路感到自豪。 Linh不会回避困难的任务,并且会很快学习新事物。 她决心并致力于编程实践,并准备面对提出的任何挑战。 琳(Linh)对成功,好奇心和不断寻求更多的教育充满热情和激情,并将成为任何团队的重要成员。 Linh目前正在从事她的Smart ASL项目,您可以在这里查看YouTube概述,我们的Lambda School CEO在这里发布推文。 Brock Rohloff:全栈WebDev HTML,CSS,Javascript,Python,C 地理位置偏好:犹他州,但愿意搬迁到任何地方 目前四月/五月开始面试 布罗克(Brock)的冒险精神和尝试新事物的能力确实促使他在成年时代尝试各种大学课程和各种工作。 直到Brock在一家小型Web开发初创公司上班之前,他才知道软件工程适合他。 在这家初创公司中,他能够担任项目经理一职,并能体会到对技术行业做出的贡献。 […]

自动进行复杂的表格视图状态更改

这不是我的编程博客,但我无法抗拒发表此帖子。 我想为正在处理复杂(尤其是动态)表视图布局的iOS程序员提供帮助。 我也喜欢Kitchen Stories应用程序,很高兴看到他们在iOS开发中发表的帖子。 他们做登录屏幕的方式对我来说似乎很棒。 不过,还有改进的空间。 处理动态布局可能很困难。 这就是为什么发明了诸如响应式功能编程 (或FRP)之类的技术的原因。 如果您不知道什么是FRP,我建议您先看Ash Furrow的精彩演讲。 基本思想是,您以称为Observable 的值流的形式定义所有内容。 它可以包含任何内容:用户输入的文本,API的响应,通知。 您可以通过组合和绑定这些可观察对象来编写代码。 这些硬布局的一种情况是动态表视图。 关于它们的讨厌的事情是表具有状态 。 这意味着,如果要对表进行更改(并且希望这些更改看起来很整洁),则必须手动删除并插入行和节。 想象一下,您的表有很多状态。 您必须为状态之间的每个过渡指定插入和删除。 kes 厨房的故事做出了正确的决定,并使用了一个库来帮助他们自动计算两种状态之间的差异。 让我印象最深的一件事是,他们已经定义了声明式的状态,但仍然以命令式的方式对他们的观点进行操作。 但是,为什么不更进一步呢? 为什么我们必须编写所有这些deleteRowsAtIndexPath ? 我将使用RxSwift和RxDataSources的功能来实现一个解决方案。 第一个是Swift中FRP的实现,第二个是使用表视图和集合视图执行复杂操作的库。 给我看看代码! 好的,首先让我们在表格视图中显示一些东西 。 如果只想显示相同的数据会更容易,但是在这种情况下,我们必须对其进行动画处理,因此我们将不得不编写一些样板来定义我们的部分。 是时候弄脏我们的双手了! 是的,它有效! 我保证,我们仍然没有更改tableView,但是我们真的很接近。 我们现在要做的是1)定义状态 表视图中的2)提供了在它们之间切换的方法,3)将状态绑定到我们的表示形式。 做吧,这很容易! 首先是状态。 看起来确实如此! 但是等等,动画不是我们想要的。 让我们修复它。 看起来更好。 我们还希望显示正确的按钮标题,因此我们也要这样做以提高我们的反应能力。 是的,它有效! 恭喜,我们做到了。 在枚举中定义状态有一件很棒的事情:如果添加更多状态,则也将不得不更改变量定义,并且您不会错过任何事情。 您可以在这里做很多事情。 我们没有更改注册/登录按钮的标题,可能应该使用关联的值来完成,因此我们的枚举不再具有原始值。 我还将在实际应用程序中使用Drivers而不是Observables (它是用于开发UI的特殊Observable,您可以在此处阅读有关它们的信息)。 另外,您可以实施即时表单验证并相应地启用/禁用按钮。 使用FRP是一项非常容易的任务! 在这个简单的教程中,Rx似乎是一个过大的功能,但是我可以向您保证,我正在做非常复杂的表视图并进行了许多更改,直到使用RxDataSources时我才失败。 […]