我今天要谈论的主题是RxSwift应用程序的单元测试。 这是我的系列文章“如何在MVVM中使用RxSwift”的最后一部分,在该系列中,我们通过实现Friends应用程序学习了如何使用RxSwift。 剩下的唯一事情就是对应用程序进行单元测试。 RxSwift应用程序的单元测试与普通swift应用程序的单元测试非常相似。 再一次,最大的变化是我们与观察者一起处理所有的回调和数据更新。 在这篇文章中,我们将看到如何: 处理可观察对象并订阅事件。 模拟网络层以进行单元测试。 在单元测试中处理数据验证。 我们将测试的所有代码都在视图模型内部,因此您还将学习如何对视图模型进行单元测试。 如果您对单元测试的概念不太熟悉,建议您阅读我以前有关单元测试视图模型的文章。 您将获得单元测试的所有基本信息,并友好地提醒您为什么应该始终对应用程序进行单元测试! 😄 我们将通过对称为Friends的应用程序进行单元测试来学习这些知识。 Friends应用程序是我使用MVVM模式实现的应用程序。 使用“朋友”应用,您可以下载朋友列表,并使用UITableView将其显示给用户。 您还可以使用该应用创建,更新和删除朋友。 这是一个简单的应用程序,具有足够的功能,可以处理开发iPhone应用程序时遇到的许多基本问题。 我首先编写了不带RxSwift的Friends应用程序,然后想看看如果我使用RxSwift会更改多少代码。 如果您想进一步了解纯MVVM应用程序的实现,请查看我有关Swift应用程序的MVVM模式的文章。 如果您想了解我们今天测试的应用程序是如何实现的,请查看这篇文章:如何在MVVM中使用RxSwift。 所有代码都可以从GitHub下载。 只要记得签出RxSwift分支即可。 但是现在,让我们开始吧! 我们将从检查如何对FriendsTableViewViewModel进行单元测试FriendsTableViewViewModel 。 这是处理向用户显示朋友列表的类。 由于FriendsTableViewViewModel发出网络请求,因此我们要做的第一件事是模拟网络层以进行测试。 通常,我们不希望单元测试发出网络请求,因为: 从服务器获取答案可能需要一些时间,这会使测试运行缓慢。 由于网络或服务器,测试可能会失败,这使得无法可靠地验证结果。 通过模拟网络层,我们可以为当前测试用例返回合适的答案。 AppServerClient是处理应用程序中所有网络的类。 如果打开该类,我们将看到它具有一个名为getFriends的函数。 这是我们要在第一个测试中覆盖的功能。 它下载朋友列表,然后我们向用户显示该列表。 函数定义如下所示: 我们可以定义一个协议,该协议具有与AppServerClient相同的所有功能定义。 然后,我们可以使AppServerClient和模拟实现都符合该协议。 但是由于我们还没有可用的协议,因此我们将使用良好的旧继承。 MockAppServerClient继承自AppServerClient而我们已经覆盖了getFriendsFunction 。 我们在函数内部所做的第一件事是,我们创建了一个从函数返回的Observable 。 我们为create函数传递一个块,并将Switch用于名为getFriendsResult的变量。 getFriendsResult是用于定义网络请求的不同结果的变量。 成功的情况下,它包含一个朋友列表;失败的情况下,它包含一个错误。 稍后,我们将检查如何为测试定义值。 在switch语句中,我们定义了.success和.failure情况, .onNext订阅者发出带有朋友列表的.onError或带有错误值的.onError 。 我们已将getFriendsResult定义为Optional因为我们不想为模拟类定义初始化程序。 这就是为什么我们还需要在函数中定义.none大小写的原因。 最后,我们将Observable.create需要的虚拟一次性对象作为返回值返回。 RxSwift应用程序单元测试的第一步已经完成! […]
这是从代码而不是从故事板启动单页iOS应用程序的简单分步操作。 在XCode中创建一个新的单视图应用程序。 在项目导航器中删除Main.storyboard文件。 从导航器中选择info.plist文件,然后删除“ Main Storyboard File base name”主键。 编辑AppDelegate.swift,以使应用程序didFinishLaunchingWithOptions方法如下所示: func application(_ application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplicationLaunchOptionsKey:Any]?)->布尔{ 窗口= UIWindow(框架:UIScreen.main.bounds) 窗口?.rootViewController = ViewController() 窗口?.makeKeyAndVisible() 返回真 } 上面的代码将实例化该窗口,设置根视图控制器并使该窗口可见。 这就是全部!
Table,TableViewのCellはどのように管理していますか? 愚直に実装して,后から追加の要件が降って来たときに,DataSourceが目も当てられない状态になっていませんか? ではの记事では,TableViewのCellを良い感じに取り回すためのグッドプラクティスについてサンプルを交えて绍介したいと思います。 叩きとなるサンプルとして,TODOアプリを作成することを考えましょう。 要件 一番上にプロフィールのセクションを表示 カテゴリごとのTODOタスクを并べる 各カテゴリにはヘッダーを设ける この要件のTODOアプリを, 単纯に実装 中间表现を作成 抽象化 という3Stepで见ていきたいと思います。 単纯に実装していくと,以下のようになるかと思います。 表示するタスクの配列をプロパティとして持つDataSourceを作る 科の数 部ごとの行の数 科のヘッダータイトル 各行に表示する单元格 こんなにシンプルな要件なのにもう70行ですね… 辛いこと DataSourceのそれぞれのメソッドで开关文(或其他文)が乱立してしまい,DRYじゃない 查看のレイアウトが変わった际の影响范囲が大きい そこで,表示されるデータと表示するTableViewの间の中间表现として, 各节,行でTableViewに何を表示するかを表现する 二重配列 (外侧がsection,构成がrowを表す入れ子配列)を定义することで,上记の辛いことを解消していきたいと思います。 表示するタスクを二重配列として持つDataSourceを作る これにより, numberOfSections numberOfRowsInSection titleForHeaderInSection cellForRowAt で毎回indexPathによる分岐を作る必要がなくなりました。 科の数 部ごとの行の数 科のヘッダータイトル 各行に表示するCell 分岐の处理が共通化されて70行→ 55行とだいぶスッキリしましたね。 TableViewの状态を表す中间表现を二重配列として切り出すことができました。 Data,他の全てのDataSourceにおいて同じような处理を何度も书いていくのも面倒なので,これらを抽象化した衬底クラスStructuredTableCellDataSourceを作ります。 Table,TableViewの剖面,行を表す构造体を定义します。 TableCellSection.swift TableCellRow.swift そして,二重配列として表现していたTableViewの状态を, TableCellSectionの配列として持つStructuredTableCellDataSource を定义します。 表示するタスクをTableCellSectionの配列として持つStructuredTableCellDataSourceを作る UITableViewDataSourceの处理を共通化していきます。 (このあたりは先ほどとやっていることはほとんど同じですね) 科の数 部ごとの行の数 科のヘッダータイトル Cell,Cellの构成处理はまるっと抽象化できないので,次のように少し工夫してあげる必要があります。 […]
问:如何在Swift中实现排序。 它使用哪种算法? Google —如何在Swift中实现排序 单击解释它的stackOverflow链接。 单击答案中的源代码链接以转到实现排序的确切文件。 想知道.gyb是什么东西? 以及文件中的所有%是什么? Google什么是gyb 找到这个很棒的帖子 了解什么是gyb以及如何使用它。 cd您最喜欢的代码实验目录 mkdir和swift-stdlib一起玩&& cd和swift-stdlib一起玩 curl -O https://raw.githubusercontent.com/apple/swift/master/utils/gyb.py 触摸swift.sort.gyb 打开-a Sublime \文本swift.sort.gyb 复制第3点中文件的粘贴内容 python ./gyb.py — line-directive = -o sort.swift sort.swift.gyb 打开sort.swift 花费剩下的时间理解700余行代码 有一些☕️
如何在带有源代码树的swift项目中使用gitignore? 在这个故事中一步一步地显示出来。 保持冷静并阅读。 首先,开放源码树并正常添加项目,但“您不对源代码提交任何东西” 。 然后,按右上方的设置按钮。 接下来,选择“高级”,然后按“编辑”按钮。 很好,“。gitignore文件”显示在您的面前,但此处没有任何内容。 不用担心,我们将在上面找到一些东西。 然后,访问“ github / gitignore / Swift.gitignore”(https://github.com/github/gitignore/blob/master/Swift.gitignore)并复制所有这些内容。 接下来,返回到源代码树中的.gitignore文件。 将Switf.gitignore粘贴到其中并保存文件。 最后关闭设置弹出菜单,然后首先提交您的项目。 不错! 很简单,对吧?
我们已经通过iOS中的事件传递系统结束了旅程。 在介绍目标动作模式如何工作以及如何使用某些相同的API沿响应者链发送自定义事件之前,让我们回顾一下到目前为止所涵盖的内容。 在第1部分中,我们研究了UIKit如何通过点击测试处理触摸事件以及手势识别器在系统中的位置。 我们还简要地研究了响应者链如何处理这些触摸事件,包括它们遵循的到达视图和视图控制器层次结构的路径。 在第2部分中,我们介绍了UIResponder中定义的其余事件,以及有关Responder Chain如何运行的更多信息。 目标行动 UIKit大量使用目标动作模式。 它在UIControl中定义。 让我们看一看UIControl标题的代码段。 NS_CLASS_AVAILABLE_IOS(2_0)@interface UIControl:UIView —-剪断—- -(void)addTarget:(nullable id)目标动作:(SEL)ControlEvents的动作:(UIControlEvents)controlEvents; -(void)removeTarget:(nullable id)目标动作:(nullable SEL)针对ControlEvents:(UIControlEvents)controlEvents的动作; -(NSSet *)allTargets; -(UIControlEvents)allControlEvents; -(nullable NSArray *)actionsForTarget:(nullable id)target for ControlEvent:(UIControlEvents)controlEvent; -(void)sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event; -(void)sendActionsForControlEvents:(UIControlEvents)controlEvents; —-剪断—- 这些方法定义了目标动作模式。 该模式使我们可以定义要处理的事件,接收事件的目标以及要发送到目标的动作(消息)。 事件和动作的这种分离还使我们可以为一个或多个动作定义多个收件人。 有关UIControl和目标动作模式的更多信息,请查看Apple的UIControl文档。 那么,这与活动交付相适应吗? 当前, UIControl使用带有类似于以下内容的调用跟踪来发送操作: 框架#0:-[BPXLTableViewCell cellButtonTapped:] 框架#1:-[UIApplication sendAction:to:from:forEvent:] 框架2:-[UIControl sendAction:to:forEvent:] 框架#3:-[UIControl _sendActionsForEvents:withEvent:] 框架4:-[UIControl touchesEnded:withEvent:] 框架5:_UIGestureEnvironmentSortAndSendDelayedTouches —剪- 这里重要的API调用是-[UIApplication […]
您好,我亲爱的开发人员, 查看代码时,我有3种状态,每分钟对应的WTF数量从最坏到最好: 30…无限->我想杀死一个向世界介绍THAT的人,他是最坏的人,即使是最血腥的独裁者,例如斯大林,波尔布特或希特勒,也比他更幼稚。 10 .. 我喜欢那个家伙/女孩,(他)他很聪明,我们可以一起工作并仍然生存,但是,是的,每个人都有他/她自己的缺点。 0 .. 那位开发人员很棒,我想向他/她学习并承受他/她的孩子。 第一类代码的完美示例是我在过去的iOS 3中见过的“小”类,该类从API下载了一些内容,对其进行了解析并返回了结果。 很简单,不是吗? 没有人不能破坏这样一个简单的代码,对吗? 错误。 实施是可怕的。 您是否认为该人使用了ASIHTTPRequest(据我所记得,当时还没有AFNetworking或AlamoFire)? 不? 您是否认为此人在NSURLConnection周围使用了包装器? 不。 但是他当时使用了什么? 好吧,他使用UIWebView从API下载JSON。 我可以承认,手上沾满了鲜血,所以我在等待警察被监禁。 但是前段时间还有另一种情况,当时这个家伙刚刚达到31 WTF / m。 一切都差不多,除了一件事,他热衷于编写类似于以下代码的代码: 那太可怕了。 试想一下,忘记放置beginUpdates或endUpdates,或者只是在重构期间将其删除。 这将导致一些麻烦,特别是如果我们将多个更新嵌套在一起。 此外,在整个项目中,有几个这样的代码部分,出于自身的利益,我们可以将其视为重复。 但是请不要害怕,好老的Oleksa对您有建议,它是从基督世世代代以来传给我的家人的,现在我很慷慨地与您分享(tssssh,别告诉其他人):“使用类别/扩展名和闭包”: 此扩展名是完全可重用的,可以从一个项目拖到另一个项目,也可以直接装上荚(抱歉,这里没有迦太基,Artsy和Cocoapods是最好的,我是他们的忠实拥护者)。 这些神圣的知识也可以应用于协议: 我们在Swift中使用了协议扩展,在ObjC中使用了一些很棒的宏(尽管这值得商de,有些开发人员可以很容易地带着我坐在里面把我的车烧掉,只是要提一下它们,如果有兴趣的话,请看一下: IDPLocking),可以解决NSLock的问题: 再次提供与UITableView相同的便利。 而且没有忘记解锁的风险。 而且,由于有了协议扩展,我们可以在所有符合NSLocking的对象中免费获得该行为。 而且我们甚至更进一步,现在我们实际上可以在不使用外部变量的情况下获得函数的结果。 为什么行得通? 因为Swift中的Void是一个值,所以它等于空tuple () 。 尽管可以在扩展中以多种方式应用相同的想法。 由于此方法只是使用函数注入行为,因此您可以尝试将其用于扩展之外的其他方面。 就是这样,伙计们。 祝您有美好的一天,无论您身在何处,都要保持干燥。
我刚从2018年1月29日在巴黎举行的dotSwift会议回来,之后直接与Daniel Steinberg进行了为期2天的Swift编程语言强化培训,我想分享一些关于此次活动的想法。 演讲视频将通过多镜头拍摄很快以高清质量提供。 来自活动的图片已经可用。 在技术社区中,有一种关于会议格式被破坏的话题。 的确,在活动后可以免费观看高清晰度的演讲视频以及在GitHub中免费共享代码的时代,参加此类活动的价值是什么? DotSwift确实尝试并在这方面有所不同:场地是巴黎市中心美丽的剧院,而且演出类似于深夜演出。 灯光舒适诱人,不像医院那样开满灯。 我们是移动开发人员,我们知道细节很重要。 最重要的是,整个晚上由杰出的主持人Daniel Steinberg主持,他向演讲者进行介绍,然后跟进有针对性的问题。 这没有观众的参与,但是我们知道问题是切题的。 无论讲座和会议的形式如何,大多数参与者似乎都认为,正是网络和在休息时分享的经验真正弥补了它的不足,尽管尽管是短暂的活动,但dotSwift确实创造了交流多个休息的机会。 这是人们可以了解场景中实际发生的事情的时间,因为Twitter和其他平台中的脉动往往是捏造的。 与真实的人喝酒聊天往往会揭示出该领域状况的另一幅更真实的肖像。 很高兴地发现,Swift 4本身似乎已经使Swift变得成熟了,Apple的Swift核心团队成员Ben Cohen的演讲为Swift的近期开发计划提供了一些启示(可以是随后是Swift进化网站),也介绍了迄今为止取得的成就。 正如Peter Steinberger所暗示的那样,尽管ABI的稳定性将不得不等待,但这似乎使得在Swift中开发库仍然没有吸引力。 尽管社区中知名演讲者的定期演讲水平很高,但我发现闪电演讲是当晚最令人鼓舞的。 他们各不相同,也很丰富,觉得这次会议不仅仅针对该领域的著名明星。 此外,我发现Ellen Shapiro关于协议扩展功能的演讲非常出色。 自从在有关传说中的面向协议的编程的传奇式演讲中将Crusty引入开发人员社区以来,关于协议的讨论已经很多了,Ellen总结了免费实现的强大功能以及需要注意的陷阱。 萨利·谢泼德(Sally Shepard)谈到了可及性,以及她在信号处理方面的背景如何在为视力障碍创建解决方案时有用。 当丹尼尔·斯坦伯格(Daniel Steinberg)提出疑问时,“是否应该跟踪用户对可访问性功能的使用?”,她的回答很温和但坚定。 最好让用户尽早参与设计过程,而不是不诚实地秘密跟踪他们。 最终结果是一种更好的产品,通过尊重用户的隐私获得用户的信任。 接下来几天,丹尼尔·斯坦伯格(Daniel Steinberg)进行的培训使学生对Swift在MVVM架构模式中的通信使用方法,用于编译时安全的类型的强大功能以及filter,map,reduce和flatMap的内部等方面的课程感到失望。深入Swift中的函数式编程方面。 保罗·哈德森(Paul Hudson)在会议上和丹尼尔·斯坦伯格(Daniel Steinberg)在培训中都强调了这一点,即使您可以在Swift中进行函数式编程,该语言也不是要完全起作用。 相反,正是结合了过程,面向对象和功能范例的能力,Swift才能发挥巨大的作用来表达对复杂问题的简洁,可读的解决方案。
在情节提要中还是在代码中创建视图? 作为iOS开发人员,我们非常清楚这个问题。 他们两个都有优点和缺点,但是最近我越来越喜欢用代码创建的视图。 什么是架构? 我曾经将MVVM与RxSwift一起使用,这基本上意味着控制器是通过结合Storyboard , ViewController和ViewModel来创建的。 如果我们删除Storyboard界面,则在哪里构建视图的正确位置? 让我介绍一下ViewBuilders。 考虑一下当我们构建一个称为HomeViewController控制器时的情况。 让我们创建一个名为HomeViewBuilder的帮助程序结构,该结构最终返回HomeView ,该抽象使我们能够访问组件(等效于插座)。 因此,我们最终得到以下架构: HomeViewBuilder的结构: 也许您已经猜到我们要通过管道化一些操作(例如添加/设置适当的组件)来构建此视图。 让我们定义一个简单的ViewBuilder协议: 我们还定义实现ViewBuilder HomeViewBuilder 。 当然,最重要的部分是buildView函数。 我故意向您展示了此方法的最终版本 。 这是唯一可以从外部访问的公共方法,这是一种梦想,我们现在要实现。 首先 ,让我们介绍流行的管道和函数组合运算符,这些运算符允许我们组合函数和对象: 管道运算符用于buildView函数中,其基本外观如下: 组成从类型Builder功能到Builder 将此转换应用于创建的构建器 好的,看起来不错,但是这些 install / setup 功能 如何 工作? 如果您对镜头了解不多,则一定要观看一些视频,了解这种模式的工作原理。 我在这里使用它们来编写单独的小段代码,并使它们可重用。 让我们考虑使用vertical轴创建UIStackView并将translatesAutoresizingMaskIntoConstraints标志设置为false 。 我们将在项目中使用多少个? 当然很多 我创建了一些项目全局的Style结构,该结构定义了常用的样式,这些样式是(View) -> View类型的转换函数。 这里有些例子: 因此,让我们构建使用其中一种样式的UIStackView 。 这是典型installer功能的实现: 多亏了镜头组成,它看起来很清晰,我们在应用程序中获得了很多可重用性。 但是,等等,我们错过了重要的约束设置…… 问题 通过使用锚,我们可以很容易地通过将一个锚连接到另一个锚来生成约束。 但是在这里,我们失去了像镜头所使用的流程那样通用和通用的功能。 解决方案:让我们定义另一个构建器。 我创建了一个名为FunctionalBuilders的库,该库包装了约束构建并使其使用起来更加美观。 […]
我一直希望并有一段时间为开放源代码社区做出贡献,部分原因是我的大部分工作基于免费工具,并且免费共享给我,我很感激。 但是主要原因是我很少从事有意义的软件工作。 我的意思是,如果您从蓝色大理石的角度看待这个世界,那么帮助一些公司出售更多产品并不是您的目标,甚至不是目标。 该应用程序的Open Sourcing部分使您感觉自己在处理比出售更多东西的应用程序还要大,有用且…好。 将组件分离,将软件与可重用和通用模块组合在一起只是好的设计,如果这些部分经过了实战测试并且质量很高,为什么不与所有人共享它? 我怀疑你们每个人都想与所有人共享一些简洁的代码。 我知道这对我们许多人来说都是显而易见的,但是-在这里相信我-并非所有人。 为什么是微型图书馆? 专注和做一件事情的能力 单一(简单)责任 较小的精力准备发布 (很多)更容易维护 挑战(为什么不经常这样做?) 老实说,作为工程师,我很少经常考虑法律。 那并不意味着我不知道著作权法。 当您将工作中的工作开源时,您必须征求所有者(您的老板,客户等)的批准。 有时很难,人们(尤其是企业类型)会提出一些异议。 有些是有效的(客户不会理解什么是开源),有些是纯BS,例如“现在有人可以免费制作我的应用吗?”。 在开始进行项目之前,这要容易得多。 您应该说或最好写这样的电子邮件: “在制作软件的过程中,我可能会确定一个或多个组件可以成为开放源代码库的候选对象,我可以在自己的私人时间内发布它,然后将其用作外部依赖项。 我花在此功能上的计费时间不会增加,但是您可能希望代码和软件质量更好。” 最终客户应了解并获得您的同意-带有批准的电子邮件回复就足够了。 有时,您将不得不解释什么是开放源代码,并且别忘了提到您使用的普通应用程序中有多少百分比基于开放源代码。 🌃失眠 https://github.com/ochococo/失眠 如何防止屏幕锁定我的应用程序? 这个想法很简单,如果您忽略.disabled ,则有三种模式以及两种模式: always -只要一个Insomnia实例在内存中,iOS就不会超时也不会消失 whenCharging —如果设备连接到电源,失眠的行为将类似于always模式。 用法示例: 最后一个类AppDelegate:UIApplicationDelegate { 私人让失眠=失眠(模式:.whenCharging) } 下一版本功能? 除了模式之外,我想称其为Rule -当设备电源状况发生变化时调用闭包。 将提供一些预定义规则,以使其更易于使用该库。 学分 Artur Martynowski失眠的标志设计—检查他的运球资料,他真的很棒!