“アプリ开発の工数の8割はTableViewに使われている”と言われることもある,アプリUIの花形TableView。荒れがちなTableView周りの设计について,ペイモでのリファクタリング事例を绍介します。 Controllerイモでは,共通のViewController ・ Presenterに分岐を书いてデータや机能に差分にTableViewでも无理やり复数画面で使い回していました。开発初期はこれでもよかったのですが,机能拡张に伴い特に使いしがの界界を迎えたため,今回绍介する设计へリファクタすることとなりました。 同じようなデータを表示するTableViewが复数ある。 各TableViewごとに微妙に机能差分(検索の有无,セル选択时の挙动の违い等)がある。 一つのTableViewに复数种类のデータを表示する(「ユーザ情报」と「お知らせ」など)。 や仮ータの过滤器や仮名のインデックスなど,共通化したいロジックがある。 倾向于として,ペイモではClean Architectureを采用しています。 ViewController→演示者→UseCase→存储库 清洁建筑に则ってAPIコールします。 存储库→UseCase→数据模型 APIの取得结果をドメイン层の责务范囲で整形してDataModelに积み,Presenterに返却します。 数据模型→演示者→ViewController Presenterは,UseCaseから返却されたDataModelからその画面の表示に必要なデータを取得してDataSourceを作成し,ViewControllerに引き渡します。 枚举协议。 ///セル用のデータ种别 通讯协定CellRenderable { //种别判定关数(TableViewのDelegateメソッドでの型判定に使用します) func getType()-> CellDataType } ///种别「A」のセル用データ class CellTypeAData:CellRenderable { func getType()-> CellDataType { //自身のデータ种别を返します 返回.a } //このデータ种别固有のプロパティ群 var hoge:字符串? } ///种别「B」のセル用データ class CellTypeBData:CellRenderable { func getType()-> CellDataType { 返回.b } //このデータ种别固有のプロパティ群 var hoge:字符串? } ///主持人にデータを引き渡すモデル […]
从概念管理器的依赖注入 (Inyeccióndedependencias)和依赖倒置 (Inversióndedependencias)中获取信息。 从遗漏的概念到美国,再到美国。 Imagina que tienes uncódigocomo este: 消费者依赖于基础数据库的数据 (包括具体的注释),而无需咨询任何产品。 消费者可购买的物品已被测试 。 Seríaalgoasí: ?Fácil,不? 布宜诺斯艾利斯,洛杉矶测试单位(Ademásde otrascaracterísticas)。 Imagina que nuestro objeto 数据库临时项目(tiene que leer del disco等…)。 实际生产的基础设施。 ¿Quéhacemos? 要在理想的情况下从数据库中删除数据库 ,请在问题上进行以下测试: 消费者在 数据库中存储的即时数据。 Para solucionarlo vamos a inectecta ladependencia (en este caso,构造函数中位数de la clase)。 Elcódigoquedaríatal queasí: 是依赖注入: 消费者的构造函数,即构造函数的遍历消费者和实例。 Ahora,Yapodríamoshacer lo siguiente en el测试: 佩罗…? 布宜诺斯艾利斯,布宜诺斯艾利斯 Podemos […]
在几乎每个应用程序中,都有一段时间我们必须进行一些格式化。 有时我们需要将Bool转换为可读的字符串,更经常的是将Date对象转换为文本文字,这对于使用我们的应用程序的人来说是可以理解的,而不是说用逗号/点号将数字四舍五入到两个空格(取决于国家/地区或操作系统设置)或在数字的千分之一之间放置分隔符。 Apple满足了这一要求,并创建了可在我们的应用程序中使用的格式化程序集。 苹果开发人员的意图是创建非常清晰的API,该API将是独立于国家/地区的,而且也非常可定制。 他们为此做得很好。 例如,要创建DateFormatter以在屏幕上的单个标签中打印不带时间的Date ,我们必须: var date:Date = // … 2001-01-02 func setupDate(){ 让dateFormatter = DateFormatter() dateFormatter.dateStyle = .mediumStyle dateFormatter.timeStyle = .noStyle dateLabel.text = dateFormatter.string(来自:日期) } 这将根据iOS或OS X语言首选项显示不同的字符串。 如果我们使用英语作为默认语言,它将显示Jan 2, 2001,对于法语,我们将显示2 janv. 2001 2 janv. 2001 ,对于日语,我们得到2001/01/02 。 其余的格式化程序具有非常相似的API。 我们可以使用枚举根据语言偏好来定义行为,但是我们也可以使用字符串格式来创建独立于系统配置的格式化程序。 当我们将日期作为字符串发送到REST服务时,我们可以将格式器定义为: func getCurrentDateStringForRest()->字符串{ 让dateFormatter = DateFormatter() dateFormatter.dateFormat =“ yyyy-MM-dd HH:mm:ss” 返回dateFormatter.string(来自:Date()) }
作为兼职/业余编码员,我可能曾经是Apple的目标程序员:敏锐,充满活力,但如果我要真正实现目标,则迫切需要帮助。 Apple提倡Model-View-Controller应用程序设计的变体已经不是什么秘密了,但值得庆幸的是,他们没有像这样推销它。 它们只是为您提供了所需的所有工具,模板以及自动完成功能,可让您在单个文件(具体来说就是UIViewController)中构建第一个应用程序。 不用离开该文件就可以做一些很棒的事情,但是如果您冒险进入另一个很好的场景,只需将另一个UIViewController放在StoryBoard上,创建一个序列就可以了。 现在,您有一个功能丰富的应用程序,可以做的事,只需要担心两个文件。 简单性令人迷惑,这意味着任何人都可以制作应用程序并在App Store上出售。 但是后来我开始制作具有4个视图,然后是5个,6个的应用程序。然后我想使它在iPad上看起来与众不同。 方向呢? 哦,当然,我希望一切都可以连接并流通。 我开始严重失去控制权,并想知道MVC的含义是什么,因为我似乎只有ViewControllers才多,但幸运的是,播客来帮助我,并向我展示了另一条路线。 Garric Nahapetian的Swiftcoders:第38集与KrzysztofZabłocki
当您查看代码并几乎不了解它应该做什么或它需要这么多行时,每个开发人员都会意识到这一点。 这并不意味着您必须完全从头开始,但是对重构代码的一部分开放很重要。 重构的目的是使您的代码更易于理解,测试和/或更新。 这是许多文章的第一篇,我将分享我的应用程序We To Too的重构过程,以及沿途学习的模式,库和工具。 四年前,当我第一次开始学习iOS开发时,我学到的设计模式是MVC,它代表Model View Controller。 下图以MVC模式显示了用户交互: 如果您正在学习iOS并依赖Apple的文档,您会注意到它们遵循MVC模式。 随着时间的推移,随着应用程序的增长,很容易将应用程序的所有逻辑写入视图控制器,从而导致难以测试和理解的超大型类(通常称为Massive View Controller)。 MVVM是最近流行的另一种设计模式,它代表Model-View-ViewModel。 视图模型允许业务逻辑与视图控制器分离。 这样,我们的视图控制器就变得很小,只专注于UI。 视图模型通常不导入UIKit,并且不了解视图或视图控制器。 这使视图模型可以进行单元测试。 该模型通常是表示数据的结构或简单类。 遵循MVVM模式并不意味着您的代码将是完美的。 正如您可以拥有大量的视图控制器一样,您也可以拥有大量的视图模型。 您不必在整个应用程序中使用一种设计模式,这取决于哪种功能最适合您要实现的功能。 在上面的MVVM图中,有诸如“数据和用户操作绑定”,“更新”和“通知”之类的术语。 您如何实际在MVVM中实现这些关系? 许多开发人员通过反应式编程为这些关系建模。 响应式编程是软件开发中已经存在了数十年的范例,它使开发人员可以编写专注于异步数据流的声明性代码。 查看Andre Staltz撰写的这份出色的文档,其中有更多解释。 响应式扩展(Rx)是响应式编程如何特别是在移动开发中普及的方式。 为什么我要学习Rx? 用户期望现代应用程序能够响应。 将所有内容都视为带有输入和输出的流,可以确保始终对发生的任何更改(无论是用户操作还是网络请求)做出反应。 响应式编程使用观察者设计模式,订户“侦听”流(可观察)。 有关反应式编程和RxSwift的更多信息,请观看Shai Mishali的精彩演讲或阅读文档。 我之前写过关于可测试视图模型的信息,但是我们将如何测试它们呢? 我决定使用John Shore创建的Red green重构方法。 这样可以确保在编写代码时遵循TDD思维方式。 在逻辑完成之前编写测试, 然后编写逻辑以符合测试要求。 测试通过后,您将找到无需破坏测试即可改进代码的方法。 Kickstarter在其代码库中遵循此方法,您可以观看此视频以了解其工作原理。 他们使用ReactiveSwift并编写了自己的测试助手。 我正在使用RxSwift,发现了一个非常有用的Cocoapods库,称为RxExpect。 现在,我们已经为理解MVVM和反应式编程的基础奠定了基础,让我们开始重构我的应用程序We Read Too的重构,该应用程序全部用Swift编写。 我们也阅读是一款具有以下功能的图书目录应用程序: 集合视图显示按年龄类别过滤的书籍 按作者,标题或描述搜索 详细信息视图,显示书的详细信息以及从Goodreads提取的数据,并允许用户共享书或在Safari / […]
更新(2018年12月): 向Mark Moeykens大喊大叫,他制作了一段受本文启发的视频:https://www.youtube.com/watch?v=6Om91KRQCiM&feature=youtu.be。 他在自己的YouTube频道上有一些有关iOS开发的精彩内容,如果你们喜欢这个,那么您绝对应该检查一下该频道。 在制作iOS应用程序时,我们需要一些标识符,例如可重用的UITableViewCells或UICollectionViewCells ,segues, UIStoryboards , UIViewControllers等。我们如何管理所有这些在源代码中只是字符串的标识符? 作为一个初学者(一年前),我的方法是简单地跟踪UI组件并将标识符复制并粘贴到我需要的位置。 但是,我很快意识到,随着应用程序的扩展,这种方法会使我的生活变得更加艰难,而且我还有更多的选择, UIViewControllers , UIStoryboards等。如果您在团队中工作,那么我强烈建议重构标识符! 1. UITableViewCells和UICollectionViewCells标识符: 本部分介绍了可重用的单元格,该单元格需要一个标识符来重用并将其注册到相应的容器视图,即UITableView或UICollectionView 。 当您创建一个新的自定义类时(我以UICollectionViewCell为例,它应该对UITableViewCell应用相同的方式),它看起来像这样: 现在,我们更新自定义单元格类以包含静态常量。 该名称具有名称标识符并存储我们的标识符,在本例中为MyCell 。 该行看起来像这样…… static let identifier = “MyCell” 。 但是,如果它与类名相同,那么我认为我们可以做得更好。 我们可以使用描述性的String初始值设定项来获取类的名称…… static let identifier = String(describing: MyCell.self) 。 如果我们使每个自定义单元格的标识符与类名相同,那么我们可以通过扩展UICollectionViewCell和UITableViewCell类来进一步泛化它! 我知道命名单元标识符与类名称相同可能会有例外。 这是我针对该异常的解决方案,而不是使标识符成为static var而不是使其成为static var class var ,这为我们提供了在自定义单元格类中覆盖identifier变量并分配自定义String的优势。 这增加了一个额外的步骤,但是我们仍然享受自动完成的好处。 更新后的代码如下所示: 此方法使源代码中没有字符串,可以帮助开发人员利用自动完成功能,并且易于维护和更新。 下一步:Segue标识符。 2. Segue标识符 这种类型的标识符非常凌乱,并且随着项目的扩大而变得非常混乱。 将标识符从相同的UIViewController重复到不同的UIViewControllers是非常容易的,尤其是当您在更大的团队中工作时。 此外,四处查看您的源代码并检查我们是否已经使用了标识符很不方便。 […]