Tag: 软件开发

SOLID Swift:第一部分

什么是SOLID? SOLID是一组原则,简称。 父亲是(许多人可能认识他)鲍勃叔叔。 我听到您的问题: 什么是SOLID? 好问题。 SOLID由五项原则定义: 单一责任 打开关闭 里斯科夫替代 接口隔离 依赖倒置 在几篇文章中,您将了解他们的全部知识! 要记住的重要一点是,这五个原则不是严格的规则。 有时候,您会否决原则,并根据需要对其进行调整。 本文 总共将有三篇关于SOLID原理的文章。 这是第一个:这里将解释单一责任和开放/关闭 。 下一篇文章将讨论Liskov替代和界面隔离 。 上一篇文章将涉及依赖倒置,因为这是一个很大的主题,需要适当的解释。 单一责任 SOLID的第一个字母是单一职责 ,归结为确保任何类别仅具有一个职责。 例如:一个可以自己draw()并计算其area()的Rectangle类有两个职责。 无论您如何轻松地发现Rectangle类的两个职责,都可能很难发现。 当您有一个需要requestOrders() , parseOrders()和saveOrders()的OrderService类时,这样做可能很自然,但事实并非如此。 您能看出这堂课有多少责任吗? 至少三个:调用API,解析数据并保存。 您将要在这里划分职责。 您可以创建一个额外的OrderParser来解析订单,甚至可以创建一个带有save()方法的OrderDataSource 。 这样可以确保您可以更轻松地独立测试OrderParser , OrderDataSource和OrderService 。 使用Swift protocol实现时,您甚至可以在测试过程中切换出实现并完全控制。 最终,您可以在一个类中使用Service,Parser和DataSource(例如) 将来,当业务逻辑发生变化时,您还可以更轻松地创建任何协议的新实现。 例如,如果API从v1更改为v2,则可以轻松添加OrderV2DataSource: OrderDataSourceProtocol {}并逐步淘汰OrderV1DataSource 。 打开关闭 编写易于维护的类是打开/关闭原则的关键。 有两个条件: 可以扩展 :您应该能够轻松地更改或扩展类的行为。 已关闭进行修改 :您必须能够扩展类而不更改实现。 归结为编写不需要每次更改需求都必须更改的代码。 […]

处理缓慢的Swift构建时间

我们从2016年4月开始我们的项目,并决定将其作为纯粹的快速代码库。 随着项目的发展,越来越多的快速文件被添加,我们开始注意到构建时间约为2-3分钟。 几个月后,我们得知该项目将花费大约7分钟的时间来构建 。 到处搜寻,我们发现了一些有趣的链接。 使用适用于Xcode 7.3.1的出色的Xcode分析器插件,我们试图摆脱项目中的头号罪魁祸首,并合并了一些拉取请求,从而将构建时间减少了3–6秒。 但是这些PR并没有真正影响整个构建时间。 仍然花了7分钟才能完成。 我们希望当Apple发布swift 3时,在构建时间上也会有所改进。 尽管编译器有所改进,但在构建项目时我们并未真正注意到任何改进。 更糟的是,当Xcode 8.0发布时,它曾经进行了完全重新编译,而不是进行增量构建,因此更改任何文件中的简单常量都将触发整个项目的重建。 (此问题稍后在Xcode 8.2中修复) 由于进行了这些重建,团队中的开发人员感到沮丧。 再次谷歌搜索,我们想到了Stack Overflow上的这个宝藏。 解决方法以加快构建速度 事实证明,将此简单标志添加到我们的项目设置中,可将编译时间从7分钟减少到1分钟。 只需在“项目设置”中转到目标的“构建设置”,然后单击搜索栏左侧的+按钮即可。 选择添加用户定义的设置 并将此文本粘贴到文本字段中 SWIFT_WHOLE_MODULE_OPTIMIZATION 并将相应的值设置为YES(对于调试版本)和“ NO(否)”。 启用“整体模块优化”后,Xcode会将所有swift文件编译为一个大文件,而不是单独编译每个文件。 通常,您会注意到据说可以对发布版本启用“整体模块优化”,这是因为如果编译器可以一次看到所有文件,则可以推断出优化并将其应用于您的代码库。 因此,请确保针对发行版配置将此设置为“否”,然后上传到appstore,以便获得swift编译器可以提供的编译时间优化。 作为附带说明,您可以参考此答案以了解在xcode中构建项目所花费的时间。 结论 容易忘记,Swift才2岁,许多贡献者仍在努力构建这种语言。 尽管构建时间一直是造成挫败感的很大原因,但是“整体模块优化”技巧为我们节省了很多麻烦,并允许我们继续编写越来越多的快速代码。 在Twitter上关注Practo Engineering进行定期更新。 如果您喜欢这篇文章,请给我们鼓掌。 这将帮助其他中级用户找到它。 我们也在寻找kickass开发人员。 如果您有兴趣,请访问这里。

一种精巧的模式,可在Swift中制作高效缓存功能

Swift是在移动设备上很好地使用的一种语言,其中一些在(非常)有限的计算能力下运行—例如,以较旧的iPhone或Apple Watch为例。 在这种情况下,每个CPU周期都非常重要,精心设计的应用程序将充分利用它们。 减少应用程序占用空间的一种已知方法是通过缓存。 缓存通常被认为是一项棘手的业务。 当将诸如网页之类的外部资源放入缓存时,这是正确的,但是当我们仅考虑缓存纯函数的结果时,事情就容易得多。 如果某个函数始终为给定的输入返回相同的值,而不会产生任何副作用,则认为该函数是纯函数。 缓存纯非递归函数的结果 对于此类功能,功能编程是透明地提高其缓存效率的指定工具。 考虑以下代码: cached函数将一个函数作为参数,并返回一个新函数,该函数将计算与原始函数完全相同的结果。 但是,一旦第一次计算出一个值,它将被存储在缓存中。 因此,使用相同输入进行的任何后续调用将不再需要执行任何计算以得出正确的结果。 考虑到您正在编写2D游戏的代码,现在可以轻松使用标准三角函数的缓存有效版本: 如果您的游戏经常对相同的值进行三角函数计算,那么现在怀疑这种方法是否会对性能产生重大影响? 递归函数的问题 上面讨论的技术是如此易于使用,以至于人们可能认为它有一个陷阱! 确实有一个限制,或者说是一个限制。 当您使用非递归函数时,一切都很好,并且已cached函数就像一个符咒一样工作。 但是,如果您尝试将其传递给递归函数,例如: 您不会注意到性能的提高,并且实际上对于大于20的n值,该函数仍将花费大量时间返回-请记住,此函数在不缓存中间结果的情况下具有指数级的时间复杂度。 为什么会这样? 嗯, fib是一个递归函数,因此它在自己的体内进行调用。 确实,当您将fib放入cached函数中并调用生成的函数时,将进行缓存查找。 但是之后,对fib的递归调用仍将指向原始fib ,因此将不再发生缓存查找。 为了允许相同的缓存机制与递归函数一起使用,将需要其他工作。 编写高效的缓存递归函数 首先,我们将无法创建现有功能的缓存版本。 但是我们可以提供一个框架来轻松编写具有缓存效率的递归函数。 我们需要解决的关键问题是递归调用。 我们需要一种透明地将一些代码包装在递归调用周围的方法,以便在实际执行缓存查找之前执行它。 解决方案在于以下类型签名: ((In) -> Out, In) -> Out – In和Out是泛型类型。 此签名描述了一个带有两个参数的函数: 递归函数 递归函数的输入 通过这种类型,我们既可以使用第一个参数进行递归调用,又可以通过第二个参数访问函数的输入。 从那里,我们只需要编写一个内部函数,该函数实际上将在执行递归调用之前执行高速缓存查找。 尽管此实现确实有点复杂,但很棒的事情是使用非常容易,因为将其他语法保持在最低限度: 从那里,您现在可以使用缓存的功能,并看到它运行得更快! 从那里去哪里? 我上面描述的包含缓存中间结果的过程称为“记忆化”。 它的原理很简单:它将内存换为CPU周期。 尽管可以进行任何形式的折衷,但是它可以带来显着的计算加速,但这并不是万灵丹。 因此,在应用每个特定情况之前,必须考虑到每个特定情况: 在某些情况下,您可能需要限制高速缓存的大小,并实施某些高速缓存替换策略以管理高速缓存。 […]

Swift —在Github上的持续集成

本文是同时介绍TDD和多个CI概念的指南的一部分。 您可以在 此处 查看介绍性文章 。 如介绍性文章所述,对于本指南,我们将使用TravisCI作为CI平台。 它对开源项目是免费的,并且易于使用。 让我们开始工作: 首先在TravisCI网站上创建一个帐户,然后对GitHub帐户进行配对(您也可以使用GitHub凭据直接登录到Travis,从而无需进行配对过程)。 从项目列表中选择所需的项目,以便Travis可以为其生成一个Webhook。 TravisCI现在已挂接到您的项目上,并且在您的代码更改时将得到通知(默认情况下,它设置为在每次推送以及合并时都运行。您可以在github的项目配置页面上对其进行编辑。 现在是时候告诉TravisCI每次对代码进行推送更改时要做什么。 为此,我们必须将一个文件添加到项目的根目录,并将其命名为“ .travis.yml”。 它看起来应该像这样: 7. TravisCI现在已经配置好,可以开始使用了! 提交并推送您的更改(确保包括.yml文件),应通知TravisCI,它将开始构建您的项目并运行测试! 如果一切顺利,您应该得到一个类似于以下的屏幕: 有些不对劲? 请在下面发表评论,我将尽力帮助! 8.您可能还需要检查日志,以了解实际情况。 但是, xcodebuild日志可能有些冗长和混乱。 为了解决这个问题,我们将使用另一个名为xcpretty小工具,它将获取构建日志并使其更加用户友好。 这很容易。 我们只需要向.yml配置文件添加几行: 2. SwiftLint的另一个优点是,您可以配置XCode来运行它,以便在每次构建后进行编码时都能得到实时警告! 为此,我们必须在Xcode的构建过程中添加一个新的“运行脚本阶段”,并包含以下脚本: 尽管非常有用,但SwifLint有时还是会有些干扰。 在某些情况下,您可能会收到您确实不想更改的代码的警告(例如上面的AppDelegate甚至是测试类,它们本来就很长)。 为避免这种情况,您可以配置.yml文件以指定文件排除项。 我希望您更明确一些,并像 // swiftline:disable:next line_length 随着SwiftLint的本地部分得到照顾,现在是时候让TravisCI处理它了。 同样,这是通过travis.yml:完成的travis.yml: 现在该创建一个CodeCov帐户了。 使用您的GitHub帐户注册并从列表中添加您的存储库。 您应该看到类似于此屏幕。 记下令牌ID,因为稍后我们将需要它。 最后,我们现在可以配置TravisCI,以便每次构建项目时也可以检查覆盖范围。 我们必须在yml文件中添加两件事: 通过添加标志-enableCodeCoverage YES ,将xcodebuild配置为也启用coverage数据 使用after_script选项将覆盖率数据上传到codecov 。 您的Yaml应该如下所示: 已知的错误 xcodebuild目前发生一个已知的错误,其中没有考虑UI测试,这会影响您的覆盖率。 例如,当我想以正确的百分比(在FizzBu​​zz示例中为100%)更新CodeCov时,例如在合并合并请求之前,我直接在XCode中运行整个测试套件,然后手动上载coverage使用相同的命令向codecov报告: bash […]

编写健壮的无字符串Swift代码

在不使用字符串的情况下使用情节提要,Xib和ViewController 您如何避免错误? 显然是因为没有编写任何代码。 但是,还有另一个神秘而又不那么幽默的答案。 通过不进行硬编码。 iOS最糟糕的功能之一是对字符串的过度依赖。 难怪如此轻视键值观察(KVO),是的,甚至包括使用故事板和视图控制器实例化。 随着Swift的发展,Apple试图减少字符串的使用,例如在选择器中。 例如,在Swift 2.2选择器使用之前,如下所示: button.addTarget(self, action: Selector(“buttonTapped”), for: .touchUpInside) 。 然后,他们改进为: button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) 。 但是仍然非常依赖,这带来了很大的潜在错误。 考虑以下iOS开发人员可以编写的完美代码: 使用字符串和强制转换实例化ViewController。 容易出错的做法。 注意使用字符串引用情节提要和实例化viewControllers。 在命名情节提要或viewController时犯错误的可能性非常大,这会导致错误代码。 随着代码中使用硬编码字符串的次数增加,在代码中产生逻辑(和致命)错误的机会也随之增加 。 我希望与tableview单元格标识符相关的崩溃能够引起一定的注意。 现在,让我们看看如何避免在代码中使用字符串。 首先,让我们添加一个UIViewController扩展,它不仅在编写代码时使用最少的字符串非常方便,而且在您的应用程序使用各种独立模块(还需要使用自己的故事板)的实例中增加便利性您的主要应用程序。 UIViewController扩展可从任何模块实例化ViewController 在这里, “(\self)” 在storyboardID类属性中,只需返回ViewController的名称。 为此,您要做的就是将ViewController的Storyboard ID命名为与ViewController类相同。 简单。 方法instantiateViewController(viewControllerClass: T.Type, inStoryboard: String, ofModule: Bundle?) -> T实例化任何viewController,只要它是类UIViewController,则此控制器在位于某些模块,无论您当前模块之内还是之外。 接下来,我们为故事板名称添加一个枚举 。 Swift之所以漂亮,是因为枚举可以具有属性,甚至可以具有方法。 请参阅下面的代码片段,以了解如何添加便捷方法。 在这里,我添加了方便的方法来实例化viewControllers,navigationControllers和tabBarControllers。 一个Storyboards […]

JSON Wars:可编码⚔️Unbox

最初发表在 Swift Post上 。 Codable让所有人都感到兴奋,因为我们都喜欢解析JSON,并且很高兴将此工具作为标准库的一部分。 现在是时候测试它是否值得成为我们最喜​​欢的一个了。 让我们看看Codable在恶劣条件下的性能。 我们将使用Codable解析以下JSON,然后将其与流行的Unbox / Wrap实现进行比较。 { “placeName”: “İstanbul, Turkey”, “lat”: 41.0049823, “lon”: 28.7319958, “dateAdded”: “2018-05-25”, “info”: “İstanbul is a very historical city.” } 我们希望我们的数据模型如下所示。 struct Place: Codable { let name: String let coordinate: Coordinate let dateAdded: Date let info: String? } struct Coordinate { let latitude: Decimal let longitude: Decimal […]

Swift-持续集成(CI)

本文是同时介绍TDD和多个CI概念的指南的一部分。 您可以在 此处 查看介绍性文章 。 在一个简单的项目(例如,有一个开发人员)下处理和管理代码通常是一件容易的事。 但是,当更多的人开始加入时,项目将增长,代码将获得更多功能,管理任务将逐步升级,并且很快就无法实现。 CI的基本原理是,通过不断审核更改,可以防止(或至少减少)此类集成问题。 每次提交后(如果您使用的是git),CI都会构建您的代码并运行测试套件,以确保最新的更改不会破坏任何内容! CI还可以在单​​独的计算机上(无论是否在本地)运行,以确保代码在与用户的计算机不同的计算机上运行,​​并且该代码也可以在“干净”的计算机上构建,而无需事先安装任何吊舱等。 在为我的Swift项目寻找合适的CI时,我遍历了其中三个: Travis CI:基于云,它提供了一个VM,供您在其中运行代码。适用于XCode项目,您可以运行xcodebuild xctool甚至fastlane命令。 简单的界面,但至少到目前为止,它仅与GitHub项目配对。 它是免费的开源项目,并且为私有存储库提供了不同的层次。 Circle CI:非常类似于TravisCI,也是基于云的。 它的配置有些不同,但没什么特别的。 它的免费套餐仅适用于Linux机器,并已付费MacOS平台(提供免费的两周计划) Jenkins CI:与前两个相反,Jenkins是免费的,但您必须将其托管在自己的服务器中。 它具有更多的可定制性,但这是以不那么友好的配置为代价的。 它的学习曲线更陡峭,但是如果您想对事情进行更多的控制,这可能是我的选择。 此外,我还想包括其他工具,这些工具将有助于检查测试覆盖率,代码质量和棉绒: CodeCov:有关测试覆盖率的报告 SwiftLint:分析代码中可能的错误,样式错误和/或可疑的内容; 猎犬:类似于SwiftLint,但基于云 Codebeat:通才代码审查,检查代码重复,长函数或语句等 让我们从这里开始看看该工具如何与GitHub存储库一起使用。

MVVM —您做错了

应用程序体系结构是移动开发中的热门话题,并且有一个原因–每个应用程序都需要某种逻辑形式的结构化代码以保持可靠,可扩展和可维护。 iOS应用程序没有什么不同。 最受欢迎的体系结构之一是Model-View-ViewModel,其中视图控制器和视图属于“视图”部分,而视图模型是负责应用程序业务逻辑的单元。 我本人一直在使用此体系结构,还曾见过其他人的多种实现,但是它们似乎都不令人满意,它们显然错过了一些东西。 这些根组件都不适合执行导航或创建控制器。 在控制器负责这些任务的情况下以MVVM方式执行操作感觉很错误,但是我们必须这样做吗? 在MVVM领域中,用于处理路由的一种可能的解决方案是,视图模型公开一个接口,该接口告诉视图控制器何时何地应该路由到何处。 但是,此解决方案远非理想–它使视图控制器意识到其在应用程序中的位置,从而降低了我们以后重用它的能力。 解决此问题的更好方法是引入一个附加组件,这是经典MVVM所缺少的。 有两个常用的对象–路由器和协调器。 两者都是有效的解决方案,它们使单元测试的某些部分非常简单,但是,有一个关键的区别–路由器从视图控制器的单个实例管理路由,而协调器则负责整个流程。 哪一个更好? 与往常一样-没有适合所有应用程序的灵丹妙药解决方案。 如果您的应用程序有很多独立的屏幕,可以在不同的上下文中显示-您可能应该使用路由器,如果它的屏幕可以分为几个控制器-长流程,则协调器可能是更好的解决方案。 我现在正在处理的应用程序属于第一类,因此我一直在使用路由器。 让我解释一下为什么它们比没有它们的路由有这么大的改进。 请记住,以下大多数属性都是与协调员共享的。 路由器的界面不需要了解UIKit,它所使用的控制器很可能只是暴露了push , present和dismiss等基本方法的协议,因此,路由器易于测试,并且可以在不考虑平台的情况下使用或设备。 路由器的导航界面是唯一的界面。 如果使用View Controller执行路由,则可能要处理甚至可能不感兴趣的大量方法–同时,路由器的接口仍然很小,非常简单并且可以完全测试。 尽管您不一定需要测试路由器,但是这种简单性可以使视图模型测试更加简洁,因为对路由器的调用通常是复杂的视图模型逻辑的结果。 为了充分利用路由器,我们需要将它们注入到我们的视图模型中。 我们通过为每个路由器使用协议来实现这一点,并且可以解锁更多令人惊奇的特性: 几乎在每个屏幕上都会执行一些与UI相关的常见操作,例如活动指示器的显示和错误/成功消息的显示-这些可以放置在所有路由器的某些根协议中,例如RouterType,因此我们可以避免很多操作不必要的代码重复。 通用路由器功能可以使用默认实现封装在协议中并组成。 例如,我们可能希望我们的路由器能够向SafariController提供一些URL –这不是所有路由器都需要做的,但是我们可能在一些地方使用它。 我们要做的就是创建一个具有默认实现的协议,并且可以与其他协议(例如ImagePickerRoutable或DocumentBrowserRoutable)进一步组合。 路由器的使用还有一个很大的属性-它使提取与导航相关的通用逻辑变得非常容易。 假设您有很多警报,操作表或弹出窗口,需要用户执行某些操作,然后执行一些任务并关闭。 如果随后应执行某些UI动作(例如活动指示器或其他控制器的表示),则视图模型通常会将其通知给视图控制器。 现在,如果需要在多个应用程序中处理相同的动作,我们可以轻松地将逻辑提取到单个可重用的单元中。 但是如何处理那些与导航相关的动作呢? 如果由控制器处理它们,那么所有的人都需要这样做-这可能是大量的代码重复,而且浪费时间。 对于路由器,这个问题根本不存在-我们可以将其与一些常见的处理程序一起重用。 我还要在这里提一些与视图模型相关的实践: 视图模型不应该是数据源,而应该公开单元配置所需的数据-这对于测试复杂的tableViews和collectionViews特别有用。 您还应该将数据源创建为单独的对象-将来可以轻松重用它们,并且立即进行操作不会有任何危害。 用于填充特定视图(例如UserTableViewCell)的数据应包装为单个结构,例如UserCellConfiguration。 这种结构只是实际数据与其转换之间的薄薄一层,用于填充所有标签,imageViews等。 它使实际模型和视图之间的区别更加容易。 使用依赖注入–可以在单元测试中使用模拟对象,使其易于编写。 视图模型不应导入UIKit-这不是至关重要的事情,但是如果您牢记这一点,它将有助于您保持UI与逻辑层之间的分离。 除了介绍路由器之外,我还在应用程序中使用了另一个组件– ControllersBuilder。 ControllersBuilder只是一个简单的结构,能够在整个应用程序中创建所有控制器。 每个构建方法都遵循相同的方案: 初始化路由器并自行注入,因此此类路由器可以请求创建另一个控制器 初始化视图模型,注入所需的依赖关系,初始数据和路由器 初始化视图控制器并注入视图模型 将视图控制器分配给路由器的弱属性 这里要注意的重要事情–最好让构建器方法返回普通的UIViewControllers,而不是返回特定子类的实例。 […]

为iOS创建自定义键盘

每个开发人员都希望在创建产品时尽最大努力。 通常,它需要超越自然设计的新颖感。 幸运的是,应用程序扩展允许开发人员在常规应用程序的边界之外添加自定义功能。 此扩展名的类型很少,其中一种是自定义键盘。 从iOS 8开始,开发人员可以使用此功能扩展其移动应用程序。 系统键盘很棒,很舒适,而且功能齐全,但是在某些情况下,第三方键盘可以通过滑动或预测用户意图等功能来加快文本输入速度(这是一种什么样的法术?)。 引入它时,我的第一个想法是创建一个简单的密码管理器。 在小型非物理键盘上输入复杂的密码从未如此简单。 从理论上讲,我只需要构建自己的自定义键盘并从此过上幸福的生活。 但是,后来我了解到某些并发症,例如… 自定义键盘限制 这种局限性可以用一句话来概括:不允许自定义键盘访问标准应用程序通常可以使用的许多功能。 首先,关于我的密码管理器,Apple担心用户隐私。 这就是为什么我们在与安全字段进行交互时不能使用自定义键盘的原因,因此无法创建带有魔术按钮的键盘来为我们完成所有这些密码键入操作。 此外,您不能在普通键盘框架上绘制任何元素。 真可惜,但是它与Apple的人机界面设计规则很好地结合在一起,就是这样。 除此之外:我们无法通过“自定义键盘”访问麦克风和摄像头,这使得听写输入变为不可能。 正如您所期望的那样,该列表还在不断增加。 您可以在《人机界面指南》中阅读有关限制和良好实践的更多信息 ……和必备 必须提供一个按钮以切换到其他键盘或返回普通键盘。 在系统键盘中,是那个神秘的地球仪图标按钮。 为了不干扰用户的期望,习惯和根深蒂固的行为,我建议保持这种状态。 我们需要做的就是将带有所有事件的addTarget添加到我们的键盘UIInputViewController到方法advanceToNextInputMode()中(用户可以点击此按钮以快速切换到下一个按钮,或者点击更长的时间以查看可用键盘的列表)。 要使用Internet连接,用户必须允许完全访问自定义键盘。 它允许键盘与包含的应用程序共享数据。 因此,该应用程序可能成为键盘的管理器应用程序。 因此,它可用于同步用户词典或调整并保留用户首选项。 但是,键盘必须在没有完全访问权限的情况下始终可用,因此也需要没有互联网连接。 实施技巧 只是一些代码片段 我不想逐步介绍您,因为我确定您知道如何创建xcode项目,添加视图等。要开始,您需要添加一个新目标(文件->新建->目标->自定义键盘扩展名)到现有项目。 您将获得InputViewController子类,它是键盘的起点-您可以在此处添加控件。 让我们跳到很酷的东西。 例子在Obj-c中,但是基本上它们没有任何特定于语言的怪癖,如果您使用Swift编写,翻译它们会非常容易。 我还建议阅读Krzysztof Pelczar文章中的更多实施技巧。 处理回车键类型和键盘类型 如果要创建可用作主键盘的应用程序,则需要准备不同的文本输入方案。 为了方便用户,您可以在用户输入电子邮件地址时添加“ @”按钮而不是其他按钮,或者在编辑仅允许数字的字段时仅显示数字键盘。 您可以通过在InputViewController中调用来获取当前的键盘上下文(UIKeyboardType): 我不建议使用可视界面构建器来放置按钮,因为完成该过程将花费更长的时间,并且从长远来看将变得很难维护。 通常,在我们的项目中,我们使用具有布局约束(可视格式语言-FTW!)的代码创建视图。 但是这次我决定计算每个键盘按钮的帧将是更好的解决方案。 它只会被计算一次,不需要在相邻视图之间保持约束,并且可以非常快速地调整大小。 一段代码只是为了展示它是如何完成的: 处理长按按键重复 当用户点击删除按钮时,他希望它将删除文本,直到他抬起手指。 这就是它在本机键盘上的工作方式,这也是根深蒂固的用户行为之一。 但是有一个缺陷。 据我所知,没有手势识别器会在每个给定的时间间隔被调用。 但是我们可以使用UILongPressGestureRecognizer和NSTimer做一个简单的技巧。 结果,当用户将手指放在删除按钮上时,我们每150毫秒接收一次事件。 […]

iPhone X在这里; 品牌现在该更新其iOS应用了。

与iPhone X不兼容的应用可能通过以下方式影响用户体验: 圆角和缺少主页按钮可能会切断应用程序的某些部分,尤其是通常位于许多应用程序顶部和/或底部的导航栏 边缘到边缘的显示将迫使不兼容的应用进入信箱模式,从而在屏幕的顶部和底部创建空白 状态栏的高度将随新iPhone X的变化而变化,这意味着应用程序的顶部导航或资产将被切断,并且无法正确显示 应用程序的屏幕边缘手势可能会覆盖或干扰新的系统级手势,从而使用户可以访问主屏幕,应用程序切换器,通知中心和控制中心 以前与旧型号iPhone的@ 2x分辨率和sRGB彩色显示器兼容的图像在iPhone X上新的@ 3x分辨率和P3色彩空间显示器上将以较低的质量显示。 学到更多 为了充分利用新的高分辨率边缘到边缘显示器,应将应用程序设计为支持当前和将来的iPhone设备的各种纵横比和方向。 您的团队还应在以下方面考虑应用程序的兼容性:屏幕分辨率,布局,屏幕大小和安全区域。 有关如何针对新iPhone X优化应用程序的更多详细信息,请单击下面的链接,以获取《 iPhone X设计和开发注意事项指南》的副本。 该指南涵盖了新的iPhone X将如何影响用户的应用程序体验,以及设计和开发注意事项,可帮助您针对新的边到边屏幕体验优化应用程序。 TribalScale具有协助公司适应不断变化的硬件和软件规格的历史,并且擅长为iOS创建流畅的应用程序,这些应用程序会随着时间的推移而不断发展和完善。 我们的产品经理,设计师和工程师将与您的团队合作,以了解您的应用将受到的影响,从而为更新应用创建最佳策略。 加入我们快速发展的部落, 并在 Twitter , LinkedIn 和 Facebook 上与我们联系 ! 在我们的 网站 上了解有关我们的更多信息 。