Tag: 工程

Swift中协议更好的重用标识符

最近,我正在经历设置新的UICollectionView 。 我已经为单元格编写了一个视图模型,并准备了一个UICollectionViewCell子类。 剩下要做的就是实现cellForItem(at:) 。 UICollectionView :如果您以前没有使用过UICollectionView ,而是更像UITableView ,那么您可以将Collection替换为Table ,将Item替换为Row并且该帖子仍然有效。 作为一名负责任的iOS工程师[需要引用],我知道我在这里要做的第一件事就是让我的collectionView出队一个单元。 为此,我必须调用dequeueReusableCell(withReuseIdentifier:for:) ,并传递一个String “重用标识符”。为了使collectionView知道我在说什么,我还必须调用register(_:forCellWithReuseIdentifier:) ,因此它知道将此重用标识符映射到我的UICollectionViewCell子类。 该子类大致如下所示: 最后一个类CustomCollectionViewCell:UICollectionViewCell {//代码等。 除此以外: CustomCollectionViewCell只是一个示例名称。 请不要这样命名类。 我确定此单元格的明智重用标识符为”CustomCollectionViewCell” 。 因此,我使用了它,并调用了这两种方法。 这些调用看起来像这样: //在设置方法中 collectionView.register( CustomCollectionViewCell.self, forCellWithReuseIdentifier:“ CustomCollectionViewCell” ) //在cellForItem(at :)中 collectionView.dequeueReusableCell( withReuseIdentifier:“ CustomCollectionViewCell” 用于:indexPath ) 这显然很糟糕。 我们周围挂着一根魔力绳,而且它不止一个地方。 显然,这需要一些重构,所以这正是我所做的。 第一步只是将字符串移动到CustomCollectionViewCell类的静态常量中。 最后一个类CustomCollectionViewCell:UICollectionViewCell {静态让复用Identifier =“ CustomCollectionViewCell”} 好的,好的开始。 这意味着我们可以使用CustomCollectionViewCell.reuseIdentifier访问代码中的任何位置的标识符。 已经比我们以前有了很大的改进。 但这确实带来了另一个问题。 如果以后更改类名怎么办? 我们可能只记得更改它,但让我们在这里成为现实:我们是人类,我们并不总是记住这样的事情。 即使它正盯着我们看着。 这就是为什么我们需要计算机为我们做这些事情的原因。 这样就很好地引出了下一个问题:我们可以让编译器来帮助我们吗? […]

使用ReactorKit,Quick&Nimble,RxBlocking,Swift 4.1在iOS中进行单元测试

入门 我们将使用RxBlocking来验证Reactor(ViewModel)的状态。 我们还将使用Stubber 模拟我们的网络请求。 最后,您的Podfile应该包含以下内容: def development_pods 吊舱“ ReactorKit” 吊舱“ RxSwift” 豆荚“ RxCocoa” 结束 def testing_pods pod’RxBlocking’ 吊舱“ Stubber” 豆荚“快速” Pod’Nimble’ 结束 简单的测试流程 一个简单的流程可能涉及将一个Action发送到您的Reactor并测试以下内容: 状态更新:在执行操作以验证Reactor逻辑时检查每个状态变量的更新。 执行次数:确保对网络请求和其他函数调用进行了正确的次数。 确保状态发出正确的次数。 初始设置 我将以下文件夹结构用于测试: 存根存储库:存储库是公开公共方法的结构,您可以使用这些方法通过网络请求获取数据。 存根存储库文件夹包含使用存根创建的模拟存储库。 ReactorTests:包含ViewModel / Reactor测试。 存根 使用Stubber模拟您的网络请求非常容易。 您还可以通过使用以下命令来验证存根方法的执行计数 Stubber.executions(signIn).count 单元测试 为了测试Reactor内部的逻辑,我们需要将Reactor视为黑匣子。 我将提供一个动作作为输入,并获得UI状态作为输出。 下面,我使用一些无效参数触发signIn操作,理想情况下,在Reactor中以同步方式进行验证后,理想情况下应该发出error状态。 我将使用RxBlocking阻止代码流,直到可观察到的state发出一个事件为止。 注意使用.delay()运算符。 没有它,在执行第7行的阻塞语句之前,可能会丢失一些事件。 订阅流后, state会发出一个事件,通常是应该跳过的先前状态。 skip(1)可以帮助您。 使用take(1)完成一次发射后的流。 否则,RxBlocking将永远不允许语句失败。 如果状态在5秒钟内未发出,则RxTimeoutException会引发RxTimeoutException,并且测试用例会自动失败。 提取状态后, Nimble用于验证状态变量的值是否符合期望。 在所有期望都得到验证后,流将立即处理掉。 如果有多个国家排放怎么办? […]

为什么viewWillAppear没有被调用?

您为什么期望如此? 最有可能的是-您想知道您的用户将要看到一个屏幕。 有各种各样有用的理由想要这个。 也许您想跟踪分析屏幕视图,或触发数据获取以保持屏幕新鲜。 无论您的目标是什么,有人都可能告诉您检查viewWillAppear -好消息。 它会实现这些目标,但有时会起作用。 * 简单答案 调用viewWillAppear的技术原因很简单。 通知视图控制器其视图将被添加到视图层次结构中。 它不能是任何视图层次结构-它必须是在根目录下具有UIWindow视图层次结构(不一定是可见窗口)。 如果您从一个选项卡跳到另一个选项卡,或者从UINavigationController推送并弹出,那很好。 iOS正在从视图层次结构中删除视图,并每次都将其重新插入。 在所有这些过程中,视图仍保留在内存中,因此不会重复调用viewDidLoad 。 但是,当您开始在当前屏幕上显示视图时会遇到麻烦,因为有时*它将删除基础视图,但有时*不会。 展示您的View Controller 这完全取决于您如何呈现模态视图。 如果可能的话,iOS倾向于删除基础视图(内存很宝贵)。 但是,如果您的设计师坚持要保留该基本视图,则可以要求iOS通过设置正确的.modalPresentationStyle来保留它。 您可以选择以下选项,以及关闭后是否在其父视图上触发viewWillAppear : UIModalPresentationStyle选择 .none的文档说…… “不要使用这种样式来呈现视图控制器。” 他们通过崩溃强制执行此操作。 感谢Apple让我们保持警惕! 备用计划 当下面的视图保留时,关闭叠加视图时将不会调用viewWillAppear 。 要开展业务,您必须在dismiss呼叫中加入完成处理程序。 将引用传递给呈现的视图控制器的最佳方法是什么? 这确实取决于您如何设置应用程序,这超出了本文的范围。 缺失的环节 当我们将视图添加到窗口的视图层次结构时,iOS如何知道要通知哪个UIViewController ? 从UIViewController文档中,我们可以看到它具有对其拥有的view的引用,但是UIView文档中没有任何内容表明它知道哪个UIViewController拥有它。 这些present方法也没有什么特别的事情发生-即使直接添加视图, viewWillAppear调用也会发生。 仅仅因为苹果不告诉我们发生了什么,并不意味着我们就无法做出有根据的猜测。 让我们偷偷摸摸,检查专用API… 查看所有这些额外的属性! 而且只有一种具有我们要寻找的类型…… UIViewController* _viewDelegate; 让我们通过创建2个视图控制器进行测试。 我们将一个注入到另一个view的_viewDelegate中,并将该view添加到窗口的视图层次结构中时,应调用注入的视图控制器的viewWillAppear 。 自己尝试一下! 警告 —请勿使用私有API交付应用程序。 这是一种危险的编码方式。 这些属性是私有的,Apple保留在不通知您的情况下随时更改其基础实现的权利。 […]

Swift中的随机远程映像

在为JAM iOS应用程序开发一项新功能时,我需要模拟出将由我们的API返回的对象。 具体来说,我想要一定尺寸的随机图像。 可以轻松地完成很多工作-我只是结合了不同的现有解决方案来解决我的问题。 我使用随机颜色和placehold.it的组合来模拟图像。 Placeholdit使用以下格式返回特定大小和可选颜色的图像: http://placehold.it/{width}x{height}/{hex_color} : http://placehold.it/{width}x{height}/{hex_color} 。 我需要一个静态的宽度和高度(400×400),并且需要一个随机的颜色。 首先,我利用了已经拥有的CGFloat扩展名: 扩展名CGFloat { 静态函数random()-> CGFloat { 返回CGFloat(arc4random())/ CGFloat(UInt32.max) } } 这使我可以编写CGFloat.random()来获得介于0和1之间的随机浮点数。 接下来,我使用从StackOverflow找到的UIColor扩展来生成随机颜色(使用相同的CGFloat扩展): extension UIColor { static func random() -> UIColor { return UIColor(red: .random(), green: .random(), blue: .random(), alpha: 1.0) } } 这使我可以编写UIColor.random()以获得随机颜色- UIColor.random()酷了! 我需要做的最后一件事是获取该颜色的十六进制代码。 StackOverflow再次解救! var hexString: String { let colorRef = cgColor.components […]

使用迦太基的4个技巧

我已经使用Carthage作为我的依赖项管理器大约6个月了,这里有一些我已经学到的技巧。 如《迦太基安装指南》中所示,要从组中更新特定存储库,请使用以下命令: 迦太基更新 –platform ios 很好,没问题-但是该存储库名称的格式是什么? 查看此示例Cartfile 。 您能为下面的每个依赖关系猜测正确的存储库名称吗? github“ swift / Sugar”“ e081f48892c1234dcgujk5a61892e5088fc544ff” github上的“ airbnb / lottie-ios” == 1.5.2 github“ moretap / PrettyBorders”“大师” git“ git@git.nasa.com:SeanBerry / launch-ios.git“ == 1.2.3 正确的格式是文件名的最后一部分,不包括“ .git”后缀。 因此,以上分别是Sugar , lottie-ios , PrettyBorders和launch-ios 。 如果您使用自己的SDK,则可能是将实验性更改推向实验性分支: git“ git@git.company.com/test.git”“ 86753098675309abcdefg” 有时迦太基会找您一个错误,找不到您的提交。 发生了什么? 作为高级开发人员,当出现问题时,我的第一个直觉是指责自己并质疑我的所有假设。 在这种情况下,这是浪费几个小时的好方法。 事实证明,缓存有时不更新(正如2015年的报道)。 清除它,迦太基将被迫重建对您的依赖的了解: rm -rf〜/ Library / Caches / org.carthage.CarthageKit […]

Turo(iOS)工程师生命中的一天

最近在公司全体会议上提出了一个问题:“工程师每天做什么?”? 我认为这是一个很好的常见问题,因此,我想从iOS团队的角度分享更多有关我们日常工作的信息。 首先,我想介绍一下我们的团队。 成为我们出色的iOS团队的一员,我一直感到非常自豪。 在过去的几年中,核心小组只有5名工程师,但是在过去的6个月中,我们增加了3名新的团队成员。 我们的团队是一个非常多元化的团队,来自不同的国家,不同的专业背景,在不同的办公室工作,从而建立了一个思想开放,尊重和强大的团队。 协同工作 作为iOS工程师,我们与产品和设计团队紧密合作,以构建和发布功能。 在2018年,我们发布了63个应用更新,其中包括Extras,Deluxe / Super Deluxe,UK Peer-to-peer Service,Turo Go,Search Redesign等功能。 “作为工程师,我们不仅解决问题,我们还通过构建工具来创造价值” – Matt(Turo iOS工程师) 我们是创作者。 我们在产品经理,设计师和工程师共享想法的环境中工作,并共同创造产品。 例如,我们最近为Turo Go旅行构建了全新的入住体验。 如果只显示一个,那是工程师最初提出的产品设计图,因此工程师提出了在Turo Go行程中显示哪个位置(预定位置或汽车位置)的困惑。 注意到此问题后,产品经理,设计师和工程师们齐聚一堂,讨论了这些问题,可能性以及客户在查看地图并办理登机手续时的最佳体验。 最后,设计师修改了原始设计,工程师进行了相应的更改。 左侧的屏幕截图是修订版。 突出显示的汽车图钉代表汽车的位置,可帮助用户在查看地图进行登机时找到汽车。 常规图钉可根据需要为用户提供原始的预订位置信息。 为了使我们的产品功能在各个平台之间保持一致,我们还与后端,android和前端团队密切合作。 例如,跨职能工程师聚集在一起讨论API(应用程序编程接口)实现。 我们努力为所有客户提供API级别的业务逻辑,以便所有客户的业务逻辑保持一致。 如果逻辑需要根据业务需求进行更改,则后端更改可以使所有客户都可以完成,并维持旧的应用程序版本。 最后但并非最不重要的一点是,我们的iOS团队成员每天都在同一个项目上互相支持,或者彼此支持。 在某些情况下,我们会合作进行一个大项目,将其分成几部分。 在其他情况下,每个团队成员都是受信任的并且可以独立承担项目,其他团队成员可以通过编写代码审查等方式获得支持。 作为iOS团队,我们尝试尽快检查彼此的请求请求,而不是长时间保持打开请求。 作为一个团队,我们会按时发布高质量的应用程序功能。 保持应用程序无漏洞 除了“应用程序功能”,“应用程序崩溃”,“应用程序错误”,它们可能是用户在谈论应用程序时经常使用的短语。 作为Turo iOS工程师,我们不仅构建了用户友好的功能,而且还非常在意我们的应用质量。 我可以高兴而自豪地说Turo iOS应用程序拥有99.9%的无崩溃用户。 有很多因素可以帮助我们取得出色的结果,例如代码审查,分阶段发布,应用程序性能监视,错误修复等。在这里,我想详细说明编写高质量代码如何对我们有所帮助。 请阅读我的同事Eric的“ iOS版本的新金标准:99.99%无崩溃”以了解更多详细信息。 当我在一个学校项目中工作时,“有效”足以使我感到非常高兴。 加入Turo之后,我了解到这是最基本的心态。 我们团队的惯例之一是编写良好,干净,可读和可重用的代码。 我们不会做“它可以工作,将其交付并在以后进行改进”。 我们尽可能快地发布项目,我们对自己保持着高标准。 例如,我们为Turo […]