Tag: 软件开发

tvOS应用开发挑战:焦点效果和无限轮播

苹果公司的tvOS基于iOS 9,并使用许多相同的框架和技术,但是为苹果电视构建应用程序会遇到一些独特的挑战。 由于用户是在整个房间而不是在手掌之间与设备进行交互,因此要使之与Apple的本机tvOS应用程序一样引人入胜且令人身临其境,就需要开发人员和设计师进行创造性的思考。 在该平台上体验应用程序在很大程度上受到焦点引擎的影响,焦点引擎是UIKit中控制焦点和焦点移动的系统。 在为客户构建Apple TV应用程序时,我们在聚焦引擎方面遇到了两个主要挑战:聚焦效果和无限轮播。 我们还开发了一些创造性的解决方案。 焦点效果 我们的一位客户委托我们开发一款Apple TV应用,该应用以令人难忘的设计呈现独特的内容。 我们知道它需要充满活力和内在。 特别是,我们要确保所有交互元素都使用动画焦点效果。 Apple TV上的焦点效果类似于将鼠标指针悬停在网页上时发生的情况。 当您的拇指在Siri远程触摸板上滑动时,焦点将在电视屏幕周围缩放。 苹果内置应用程序中的焦点效果始终是交互式的。 轻轻地在触摸板上摇动手指,使聚焦的元素在周围摆动,就好像您直接接触它一样。 也有很酷的三维效果,有助于整体体验。 与iOS(您的手指直接在屏幕上轻敲)不同,tvOS使用焦点引擎作为手指在触摸板上位置的代理。 聚焦效果,尤其是交互式摆动动画,将您的眼睛吸引到聚焦的元素上,使应用程序更易于使用和更有趣。 考虑一下本机电影应用程序中的以下示例: 借助交互式动画,可以毫无误解地关注哪个电影海报。 挑战 我们的目标是在客户的应用程序中实现与Apple自己的应用程序相同或更好的焦点效果。 但是,当我们开始从事该项目时,我们遇到了一个大问题。 除了静态矩形图像,没有直接的方法可以向任意UI元素添加交互式焦点效果。 开箱即用,不支持其他类型的元素(圆形头像,文本框,按钮,嵌入式视频等)。 经过大量的研究和实验,我们意识到,再现苹果标准效果所需的所有原材料都已经存在。 我们只需要找到正确的食谱。 挑战是双重的。 首先,我们需要将Apple的所有焦点效果分解为基本元素,编写较小的代码块来重新创建每个代码。 其次,我们需要一种混合和匹配基本效果的方法,将它们组合成最适合每种特定类型的UI元素的分组。 解决方案 通过组合从iOS移植到tvOS的许多较旧的API并将它们包装在自定义框架中,我们构建了所需的工具,可为客户应用程序中的每个视图添加焦点效果。 我们甚至可以调整细微的方面,例如投影半径和最大倾斜角度,以达到完全适合客户设计目标的效果,而不是有限的内置选项的“一刀切”方法。 虽然我们无法向您展示客户的实际应用程序,但我们可以向您展示测试项目中的一些示例。 以下是“扁平化”视图层次结构的示例。 每个单元格都有一个圆角背景图像,一个大表情符号字符文本标签和一个标题标签。 所有这三个元素都正在一致地移动,就好像它们只是一个视图一样。 我们竭尽全力使焦点效果与Apple自己的效果完全匹配,因此用户立即就可以熟悉该应用程序。 只有受过训练的开发人员的眼睛才能看到创建这些效果所付出的隐藏额外努力。 这是我们如何创建具有多个视图的自定义视差效果的另一个示例。 每个单元格都有一个大文本标签,显示单个表情符号字符,并在其后面提供许多图像视图以创建隧道效果。 这些视图可能是任何东西:更多文本标签,嵌入式视频播放器,动画GIF。 我们的自定义框架允许我们组合所需的任何元素,独立控制每一层的视差效果。 有了这个自定义框架,我们就可以调整每个元素的详细信息,直到看起来完全符合客户希望的方式为止。 能够说“是的,我们可以做到”,而不是“对不起,那太难了”,这真的很不错。 无限轮播 另一个客户要求我们进行设计,该设计在其应用程序主屏幕顶部包括“无限轮播”。 一个示例就是Apple TV上“电影”应用顶部的轮播: 用户可以向右或向左滚动而不到达结尾。 内容会不断重复,直到您希望滚动为止。 苹果的旋转木马是很好的灵感来源,但我们希望客户得到更好的东西。 我们的设计目标包括: […]

应用失败-回顾

任何应用程序工程师都会告诉您,如果您无法远程解决问题并必须向商店发布更新以修复该问题,则最糟糕的事情是应用程序崩溃。 这是我们本周发生的事情,我认为解决这个问题,原因和我们可以从中学到什么很重要。 零地 我们依靠来自Facebook和Twitter的社交API来进行社交共享计数器,评论和共享工具。 昨天,一枚未经改动的隐藏式代码炸弹爆炸了。 Facebook已弃用并删除了我们用于显示文章的社会统计和检索图形ID所需的Facebook API之一。 这导致我们的应用程序无法检索计数,而不仅仅是一个问题,除了我们无法优雅地处理丢失的数据并导致应用程序崩溃外,这是不可恢复的。 2015年12月,我们发布了应用程序V1.0,作为一家成长中的公司,我们在工程团队中没有足够的资源或能力来构建iOS应用程序,因此我们将其外包。 不幸的是,当我们将应用程序带到内部时,代码处于不良状态,没有单元测试,很少的文档,并且在过去的几个月中我们一直在努力改善应用程序中的代码味道,我们只是没有最终会爆炸并以致命方式影响我们用户的代码。 掉出来 自V1.0以来,触发炸弹的代码一直处于休眠状态,因此我们应用程序的每个版本都变得无法使用,用户将打开我们的应用程序,尝试阅读文章(该文章将立即加载)然后崩溃。 在当前版本存储的24小时内,有89%的用户受到了影响,我们收到的评论和电子邮件都很差。 复苏 眼下的解决方案是应对Facebook的空洞回应,这意味着我们可以相对较快地将问题修复到商店中,但将受到苹果评论之神的摆布。 填写快速审查表后,这是一个“静观其变”的问题。 尽管我们对发布的修复程序充满信心,但重要的是要检查代码并确定如何重新引入不可用的股数和注释。 恢复功能后,我们提交了单独的版本,与其重新构建木板并冒沉船的风险,不如将其快速塞入孔内。 在将插件提交给Apple的8小时后,我们设法恢复了对我们内容的访问权限,从而避免了致命的崩溃。 提交重建的共享和评论功能24小时后,就可以发布了。 总而言之,我们设法在36小时(36小时)内找到,修复和恢复功能。 外卖 从此类事件中学习很重要,狗屎会发生,从中学习将有助于防止同一狗屎发生两次。 我们正在审查所有底层的第三方API,并在可能的情况下确保我们已收到有关这些API更改的通知,并在其中可以远程删除,合并或抽象API功能; 这将确保我们可以远程处理更改并避免发生类似事件。 它已经在我们的视野中,但是我们将添加一个热修复程序解决方案,该解决方案将使我们能够修补未来的问题,然后发布相关的修复程序。 我们可以学到的最大的一课是进行定期的完整代码审查,我们反复进行审查,但是随着时间的推移,整个代码库都需要进行检查。 您的应用程序是否发生过类似的问题? 您是如何解决它的?您学到了什么? 我希望收到您的来信。

Swift中的关联类型

动机 可重用性是软件开发中的重要组成部分。 我认为,软件体系结构中最重要的考虑因素之一就是即将推出的功能的实现时间。 我经常有片刻,然后躺在床上,直到实施了该死的功能后才入睡。 因此,快速的实施时间可以为我节省大量的睡眠时间(这是我绝对需要的)。 继承是重用超类功能的一种方法。 但是事情会迅速发展,随之而来的是复杂性的增加。 幸运的是,我们在Swift中有了面向协议的方法。 但是协议必须是通用的,以便将其定义重新用于不同的类型。 类允许我们指定通用参数。 协议为我们提供了“关联类型” 。 实际示例:用于CoreData处理的CRUD协议 我想为我的CoreData实现创建一个协议。 这将是常见的CRUD (创建,读取,更新,删除)功能。 没有通用协议,我必须在所有地方都使用NSManagedObject,这真的很不舒服,因为我有Xcode生成的子类。 我的实体是: TaskMO和ItemMO 。 我都需要他们的经理班。 对于TaskMO,协议定义必须匹配一次,对于ItemMO,协议定义必须匹配一次。 可以使用“ associatedtype ”关键字来实现。 协议持久{ 关联类型实体 } 如您所见,实体只是一个占位符,而不是具体类型。 具体类型将仅在实现中指定。 使用约束来缩小类型 Persistable协议使我们能够处理CRUD功能。 但是我要确保将其用于CoreData。 我们可以通过向我们的关联类型添加约束来确保这一点。 就我而言,我只想允许在NSManagedObject子类上使用。 此步骤与通用参数非常相似。 协议持久{ relatedtype实体:NSManagedObject } 完整协议如下所示: 编写实现 现在按照您习惯的方式实现类型。 名为“类型推断”的编译器功能会自动检测具体类型的定义。 因此,我们不必明确指定它。 煮咖啡机 凉。 我们创建了一个通用的可重用协议。 但是,让我们深入一点。 我想制造一台咖啡机。 不只是基本的黑咖啡。 我想要一杯很棒的拿铁玛奇朵。 首先,我指定成分: 我的咖啡由主要的咖啡成分和某种牛奶组成。 我将协议命名为“ Drinkable […]

dotSwift 2018

许多Hotels.com iOS工程师在巴黎的dotSwift 2018会议上度过了这一天。 尽管这个名称暗示了会议的重点是Swift编程语言,但其中的一些讨论分散到了iOS平台的其他方面,甚至我们的老朋友Objective-C也出现了几次。 头号发言人是本·科恩; 苹果公司的一名工程师,在Swift Core团队中工作。 他很好地介绍了Swift标准库。 它的目的是什么; 以及自几年前开源以来,其他人如何帮助该语言向前发展。 我们自己的Sally Shepard谈到了可访问性的重要性。 她自己是一个可访问性传播者,并受到视觉可访问性问题的影响,她展示了可访问性问题的问题和解决方案的范围之广,以及我们如何并且应该使所有人都可以使用应用程序和体验。 引起我注意的另一位发言人是格雷厄姆·李。 Wealth Wizards的一名软件架构师。 他表明,面向对象编程和函数编程都不一定是语言领域的相反两端。 他巧妙地使用集合论来表明功能方面和面向对象方面(例如在Objective-C中发现的方面)基本上是等效的。 我已经简化了,但我鼓励您观看他的讲话以听到完整的消息。 与许多其他专业演讲者一样,Swift社区的成员提供了许多闪电演讲。 这些都是快节奏的简短消息,其中包含有用的提示和方法。 总体而言,这是非常愉快的一天-与我见面的其他Swift工程师是参加dotSwift对我来说最有价值的部分。 它还验证了我们在Hotels.com iOS团队中采用的一些方法,让我为成为其中的一员而感到自豪。 视频将很快由组织者发布-请留意https://dotswift.io。

Swift设计模式:观察者模式

今天,我将解释Swift中的观察者模式和实现。 那是什么 真实案例 想象一下,您是一名消防员,在有任何火焰时,他随时准备着紧急电话。 如果有电话从您的便携式对讲机传来,您必须准备好津贴并准备灭火。 定义 因此,观察者模式是一种设计模式,该模式着重于Observable发生更改或其他事件时的对象反应。 从上面的示例中,便捷的对讲机充当可观察对象,以向观察员(消防员)发出通知。 特点 观察者具有满足以下特征的特征: 有一个可观察的 附加和删除可观察物 通知观察者有关更改 代号 因此,该模式包含2个协议, Observable和Observer以及一些符合Observable或Observer协议的具体类或结构。 works 下一步是什么? 我希望您能了解如何在Swift中实现观察者设计模式并了解其工作原理,因为NotificationCenter或KVO机制是建立在观察者模式之上的。 如果有无法理解的事情,请在评论中让我知道。 干杯。

Swift中的设计模式:观察者模式

欢迎来到一系列致力于学习设计模式的文章。 尽管许多想法与代码无关,但我们的目标是向您展示如何在Swift中实现它们(在撰写本文时为Swift 3.0)。 每个帖子彼此独立,所有项目代码都可以 在Git上找到 。 观察者模式允许对象订阅所谓的主题。 主题更新后,将通知所有已订阅主题的对象有关更新的信息。 当对象之间存在一对多关系时使用。 观察者模式的常见实现使您能够: 添加一个观察者 这实际上告诉主题“嘿,我想加入循环”,并且在更新其他观察者时保持更新。 将该主题想成小组中总是有八卦并且想告诉别人的人。 通知观察员 观察者订阅后,我们将调用接口中定义的共享函数。 所有观察者都将实现此接口。 移除观察者 可能希望删除对象,而不再希望对其进行更新,因此我们必须给予机会删除它们。 许多语言和SDK都有自己的实现。 iOS将其与Notification Center及其NSNotificationCenter类一起使用。 使用“推送通知”,用户可以订阅以收听来自应用程序的更新,然后应用程序/服务器( 主题 )将通知推送到用户设备,并且用户始终可以选择通过删除应用程序来取消订阅。 我们将使用一个用户希望以二进制,八进制和十六进制格式显示数字的示例。 他们只想输入一次该号码。 该程序的UML图将如下所示: 首先,在Xcode中创建一个新项目。 我们不会在UIKit中碰任何东西,因此创建一个macOS Terminal项目。 首先,我们将从创建观察者协议开始。 该协议将包含id属性。 这将使我们以后可以删除观察者。 该代码将如下所示: 接下来,我们将创建Subject类。 这将是负责通知对象有关更新的类。 当我们附加一个Observer时,我们将其添加到ObserverArray中 。 当我们通知其他对象时,我们遍历ObserverArray并调用Observer协议中包含的update()函数。 看起来像这样: 继承Observer协议的类的工作是为Subject分配一个id,并在从Subject调用update()方法时执行该方法。 它们将如下所示: 现在是时候将它们放在一起了。 在主类中,我们要创建一个Subject对象。 我们创建的所有观察者将被分配相同的Subject 。 然后,我们给主题分配一个数字。 然后,我们将再次进行显示更新。 它看起来像这样: 终端输出将如下所示: 二进制:1111 八进制:17 十六进制:f 二进制数:10 八进制:2 […]

Swift中的设计模式:责任链模式

欢迎来到一系列致力于学习设计模式的文章。 尽管许多想法与代码无关,但我们的目标是向您展示如何在Swift中实现它们(在撰写本文时为Swift 3.0)。 每个帖子彼此独立,所有项目代码都可以 在Git上找到 。 这是其中一种更为自我描述的设计模式。 责任链设计模式允许一连串不同的对象(从相同的类/接口继承),将执行一段逻辑的职责传递给另一个对象。 在此示例中,我们将使用一名需要支付费用的员工,而该费用需要他们结清。 在我们的示例业务中,他们有几种选择可以清除这笔费用。 雇员 员工可以清除0至100英镑之间的所有费用。 老板 如果员工的支出大于此 ,则可以与老板联系,后者有能力结清101-1000英镑之间的费用。 首席执行官 除此之外,员工还需要与公司的首席执行官联系,后者对任何费用都严格限制了10,000英镑的费用。 其他任何事情都可能不会得到公司的批准。 如您所见,这形成了自然的“链”: 在我们的代码中,CEO,老板和员工是同一链的一部分,因此它们将实现相同的接口。 如果他们不能批准费用,他们将有能力将责任推上链。 用于此的UML如下所示: 码 首先,在Xcode中创建一个新项目。 我们不会在UIKit中碰任何东西,因此创建一个macOS Terminal项目。 首先创建一个Expenditure类。 这是一个简单的类,将仅容纳我们的费用。 在现实生活中,这可能包含更多相关信息。 代码如下所示: 然后,我们将创建Chain协议。 该协议将能够沿着管理“链”传递责任。 它看起来像这样: 员工,老板和首席执行官都将实施此协议。 如果费用金额太大而他们无法批准,他们将把费用沿着链条传递。 CEO代码与其余代码略有不同。 您可能还记得,CEO只能接受少于10,000英镑的同意。 为了停止销售,我们检查金额是否超过10,000英镑,并进行打印以告知用户: 然后,在我们的主类中,我们将其链接在一起。 首先,我们需要这样创建员工,老板和CEO对象: 然后,我们在每个适用位置上调用setNextManagementLevel() 。 它看起来像这样: 然后,我们与员工展开连锁反应: 现在,您完整的main.swift文件将如下所示: 运行您的程序,您将在终端中看到以下输出: 员工可以批准这笔支出 你的老板可以批准这笔支出 首席执行官可以批准这笔支出 这项支出过大,不会获得批准 程序以退出代码结束:0 欢呼! 您已经实现了管理层次结构-我的意思是-责任链设计模式。 您可以在Git上找到所有与此相关的代码。 山姆·斯通(@ […]

#2 — Swift编程— 21天挑战赛– Elliott Diaz –中

#2 — Swift编程— 21天挑战 随着我对软件开发精通的渴望的增长,我不断感到自己应该掌握基础知识,开发更多的实践项目来提高我对计算机编程/软件开发的技能和理解,并每天在该领域中不断前进,成为相关的。 如果我在19岁的时候没记错的话,Swift是我选择在2015年底的swift 1.2上学习的第一门编程语言。从那时起,swift发生了巨大的变化,似乎我一直在反复学习所有东西。只是为了介绍基本知识,而不是真正了解事物的总体情况。 因此,我为自己和任何想要尝试自己学习成为专业iOS开发人员所必需的人的人都构成了挑战。 该项目将基于我刚刚发现的Udacity帖子来弄清楚应该把重点放在哪里,这就是我的想法。 简短而甜美而富有挑战性。 并非旨在完善主题,而是更多地介绍和理解主题的含义并进行实践。 正如我所听到的,没有完美的方法来创建程序,我将简单地攻击主题,学习它并继续进行下一个项目。 挑战时间:21天 方法: 3天让自己沉浸在主题中。 第一天=研究/组织将学到的东西 第二/第三天=专注于挑战 每天1个小时分配给此挑战 目标:对成为一名熟练的iOS开发人员需要有深刻的了解。 第1至3天:概述基础知识-Swift 3语法 第4-6天:项目目的-使用github 第7–9天:项目目的-建立对直观用户界面的理解 第10–12天:项目目的-了解设计模式:MVC-委托-通知 第13-15天:项目目的-了解联网 第16–18天:项目目的-核心数据 第19-21天:项目目的-中央车站调度 供参考的是udacity博客文章的链接: 成为iOS开发人员需要具备的7种技能 在iOS中要学习的东西很多,以至于只需跳过基础知识而跳到编程的不同领域就变得非常容易。 我已经做了一年多了,并且一直觉得,如果我花大量的时间学习基础知识并构建简单快速的项目,那么我所做的一切将比以前容易十倍。 用代码行衡量编程进度就像按重量衡量飞机建造进度。 – 比尔盖茨

Swift:第一时间获得正确的MVC

开发人员为什么倾向于在其视图控制器中填充视图? 在Swift中使用MVC的更好方法呢? 我遇到的大多数开发人员都倾向于做真正奇怪的事情。 他们中有些人避免洗衣服和发臭,像地狱一样。 其他人则喝加盐和胡椒粉的咖啡。 但是我看到的最常见的行为是,开发人员不使用视图,而是喜欢在视图控制器中执行所有与视图相关的操作,例如填充,创建动画等。 首先,假设我们有一些描述用户的结构: 其次,我们的任务是用该用户的数据填充一些演示文稿。 许多开发人员的代码,甚至是Apple在其教程中提供的代码,看起来都像下面的怪兽: 罪人,听我说,谁会说:“哦。 嘿。 那就是我通常写的代码。 实际上,这没有什么错。”实际上在几个层面上确实是错的: 视图的内容取决于您何时设置模型。 它不可扩展且不可维护; 这是不可重用的。 而且,我们不应该忘记使@IBOutlets变弱,因为视图控制器的view属性可能会更改,并且我们将对视图持有强大的引用,对此我们不承担任何责任。 如果模型是在视图出现后设置的(例如,它是从Internet下载的),则不会在屏幕上显示,除非进一步进入导航层次结构然后返回。 有很多人在野外用viewDidLoad做到这一点,但更糟糕的是,更新内容的唯一方法是用新模型创建新的视图控制器。 即使这样,如果在将控制器推入导航控制器后设置模型,也不会显示该模型,因为在推入过程中已经调用了viewDidLoad 。 可扩展性和可维护性在这里也确实很痛苦。 您的视图控制器负责填充整个视图层次并为其设置动画。 目前,只有2个子视图,但是想象一下,您有20个甚至更多。 此外,您必须为它们设置动画或根据模型数据更改它们的外观。 viewWillAppear很快就会变成一团糟。 至于重用,请设想一下这种情况,当您希望在不同的视图控制器上呈现相同的视图和模型关系时,具有何时以及如何获取和处理模型的逻辑不同。 例如,在表格视图中将其显示为单元格,或者将其呈现给来自不同API端点的另一种用户。 在我看来,确实很奇怪,网络上没有那么多声音,他们提出了一种更好,更简单的选择。 在大多数情况下,开发人员不会反对编写任何东西: 让我们考虑一下。 UILabel具有一些复杂的绘制逻辑和字符串处理功能。 它的作用是显示字符串。 但是视图的字符串是什么? 这不是很明显吗? 这是模特!!! 那么,为什么我们的代码在使用自己的视图时却归结为我之前模拟的代码? 有些人会开始争论,那是做MVC的正确方法。 MVC是一种设计模式。 苹果公司在其代码中做到了这一点,我们应该承担义务。 你知道,这使我想起什么? 使用20个类和协议编写具有hello world的企业Java项目。 当然,Java开发人员可以简化事情,但是他们严格遵守GoF和其他主流设计模式,忘记了它们是建议,而不是严格遵循的规则。 让我们从我坚持的观点出发,对我们的代码和演示进行推理。 我们的每种观点都与某种模型紧密相关。 它的设计和呈现方式仅适用于一种模型。 证明? 您将无法使用用户展示屏幕展示考试数学问题。 它的设计不同,子视图也不同。 例如,同样适用于UITableView,但是在这种情况下,我们应该将其模型视为模型数组。 在那种情况下,它适合于1模型与1视图关系的相同方案。 同样适用于动画和其他内容。 View Controller不应在实现细节的底层上处理这些事情。 […]

Swift中的TDD简介

我的第一篇英文著作,所以开始吧begin 在本文中,我将尝试向您介绍TDD(测试驱动开发)。 那是什么 TDD是一种软件开发技术,仅要求您先编写测试,然后编写实际代码才能通过您之前编写的测试。 如果您的代码必须处理其他情况,或者要向软件中添加新功能,或者要修复该错误,那就很简单。 只需再次编写不同的测试,然后编写代码以再次通过该测试。 因此,如果您实施TDD,则您的开发周期将像这样 编写并运行测试 编码 重构 重新运行测试 如果您的开发阶段尚未完成,请返回第一。 使TDD更快捷 在您的Swift项目(iOS应用程序或macOS应用程序)中实现TDD非常简单。 您将只编写从XCTestCase类继承的类,定义您的测试用例,然后运行该测试。 我将向您展示如何进行测试,在本示例中,为简单起见,我将使用Xcode Playground进行所有这些测试。 在此示例中,我将创建解决该简单问题的算法。 您是游戏开发人员。 您将构建一个简单的格斗游戏,其中涉及2名战士互相斗殴。 每个战士都可以攻击他的对手,并拥有生命力计和伤害力。 如果战斗机受到攻击,他的生命量将因对手的伤害力而减少。 示例对象 塞纳570 60 RKO 510 65 第1栏是战斗机的名称,第2栏是战斗机的寿命表,最后一个是战斗机的伤害力 步骤1 定义战斗机 为了使您的代码通过该测试,您必须在Player类上修改attack(opponent:) 霍雷! 您的测试已通过