两个月前,我加入了Neura,担任开发人员计划负责人,以围绕Neura的产品创建一个强大的开发人员社区。 从一开始就很明显,我们需要: 1.让我们的用户(开发人员)拥有流畅的体验,将我们的SDK集成到他们的移动应用中 2.阐明使用我们产品的最佳实践。 Neura的SDK可以通过多种方式使用。 我想确保我们提供的最基本的用例(在最佳时机吸引最终用户)可以作为代码示例下载和修改。 我爱开源 作为开发人员,我无法想象没有它。 我过去曾为开源项目做出过贡献,有时是通过贡献代码,有时是通过积极开放新问题并帮助其他开发人员使用它来做出贡献。 我一直想发布自己的项目,但是我要么还不够好(我今天不知道这个原因),要么我只是从事代码工作,却看不到如何完全或部分开源(再次,今天我知道答案是“只问一个人”)。 当我开始新的职位时,我知道我必须实现这个目标。 幸运的是,在潜入更大的任务后不久,其中一个提出了挑战,迫使我创建了一个补充项目。 该辅助项目是一个简单的Node.js应用程序,可以将最终用户的数据持久保存到(MongoDB)数据库中,并根据Neura的机器学习算法将推送通知发送给这些用户iOS设备。 这个辅助项目(一个示例iOS应用)实现了基本的医学依从性概念。 一旦服务器启动并运行,很明显该应用程序也是一个很好的开源候选人。 它具有简单的UI,实现了简单的网络解决方案,并且整个项目都基于MVC。 这就是我们这里,而不是Github上的一个开源仓库,我从一开始就有两个! 这个项目囊括了Neura的特定开发实践以及客户-服务器开发的一些一般原则,这一事实使我为自己的工作感到更加自豪:)。 Node.js Webhook示例:https://github.com/NeuraLabs/neura-webhook-sample。 iOS应用示例:https://github.com/NeuraLabs/neura-meds-reminder-ios。 如有任何疑问,请在此处评论或通过Twitter和LinkedIn与我联系。 另外,我们正在招聘!
新的伟大而轰动的应用程序Pokemon Go完美地重新定义了我们的社区,因为完全陌生的人联手追踪并捕获了虚构的怪物! Pokemon Go是否能解决旧时代冒险方式与新一代数字设备缺乏活动之间的巨大鸿沟? 我们认为可能确实如此。 不可否认,Niantic制作的《 Pokemon Go》已经在一夜之间取得了成功。 在短短几天内,它为Nintendo的市值增加了90亿美元 ,几乎超过了日常活跃用户中最受欢迎的Twitter,这不是很有趣吗? 似乎每个人都无话可说。 口袋妖怪围棋突然间像飓风一样进入我们的生活,无论是对于粉丝还是反对者。 但是,完成诸如Pokemon Go之类的大型项目需要极高的预算 。 在制作应用程序之前要牢记的重要一点是绝对知道其实际成本。 如果您需要增强现实应用程序的最佳报价,请务必注意,专门从事此技术领域的团队很少,因此您必须非常小心为项目雇用的人员。 神奇宝贝Go吸引了众多观众,其中之一就是其对增强现实(AR)和地理位置(GPS)的熟练使用。 《PokémonGo》从字面上将原始游戏的想法变为现实; 您必须继续寻找虚拟的神奇宝贝。 通过使用增强现实,Pokemon Go通过将所有真心粉丝变成Pokemon培训师,确实设法使这个世界栩栩如生! 从表面上看,游戏应用程序的开发与正常的移动应用程序开发完全不同,并且需要考虑许多细节和细微差别。 首先,最好弄清楚PokémonGo手机游戏的区别是什么; 创意,独特的方法,技术,游戏引擎和位置意识。 在创建诸如PokémonGo之类的移动应用程序时,应注意所有这些。 如何开发自己的Pokemon Go-像App 估计:神奇宝贝Go-like应用开发费用 正如我们之前强调的那样,制作好的增强现实应用程序既不容易也不便宜。 专门从事增强现实技术的专业人员并不多,可能是因为正确开发此类应用程序需要花费大量时间和金钱。 您将意识到此项目非常昂贵且耗时。 尽管如此,创建一个不太复杂但又不那么令人兴奋的应用程序可能是一个不错的选择。 无论如何,您永远都不知道为什么一个或另一个应用程序会迅速流行起来,因此,如果您有一个好主意,请立即将其变为现实。 因此,让我们快速总结上述所有内容,找出可能的技巧,以及创建PokémonGo移动应用程序的低端模拟所需的总金额。 增强现实 以《PokémonGo》为例,该公司通过Ingress自行开发了这项技术,这是一项非常漫长且昂贵的工作。 但是,根据您自己的情况,可以使用像Microsoft RA或Unity这样已经开发的技术。 对于出色的增强现实工作,最简单的Unity驱动游戏肯定会花费至少50,000美元。 设计 在有效地设计应用程序时,还必须重复花费大量的精力和金钱来开发应用程序。 尽管设计可以忽略不计,但如果我们希望获得良好的结果以免破坏数字等,开发人员必须在相同的时间范围内进行开发,并且预算至少为50,000美元。 同样,您可以设计更简单的产品,成本最高可达40,000美元。 不要忘记! 这些费用将全部包括游戏设计(但是,不要指望精美的图形)和质量保证。 应用程式内购买,位置识别和增强现实集成等所有其他功能将总计增加您的费用。 后端 这是《 Pokemon Go》实际上在欧洲面临的主要问题之一,其原因是它被迫推迟了发布时间,而后端问题是: 设计,配置文件,地理位置,交互等。这是开发此类应用程序的基本组成部分,如果要使其完全腾飞而没有任何障碍,必须至少投资50,000美元。 应用商店优化与营销策略 开发像PokémonGo这样的应用程序的旅程并没有就此结束。 成功开发该应用程序之后,现在您需要使其广为人知,吸引用户并同时通过其获利。 […]
询问任何经验丰富的iOS开发人员,他们会告诉您应用签名是散发大多数屁味的部分。 它不会杀死您,您可以度过难关,但是却充满了不便,愤怒和一点神秘感。 因此,Apple一直在努力实现流程自动化,因此对于产品开发人员而言,只需勾选一个复选框即可。 当无法选中该框时,还有其他工具可以帮助减轻痛苦。 因为这只是最糟糕的情况,所以我们懒惰的工程师已经制作了足够的工具,可以容忍完整的应用程序签名。 但是中间的步骤呢? 仅仅因为我们可以从纽约飞往洛杉矶,就不能更轻松地开车前往费城。 模拟器 人们不时喜欢在发送代码之前对其进行测试。 这可能是最佳做法,我不知道,我是工程师,所以提起诉讼。 有些人甚至喜欢自动化他们的测试。 如果您想在iOS上自动化测试,则意味着您将在模拟器中进行测试。 现在,您将如何在要分发到实际设备的构建中执行此操作? 您知道吗,我们早先谈论过的那些花哨的建筑? 这些将不适用于模拟器。 不,现在您需要一个新的过程。 这可能看起来很神秘,但实际上只是在做您之前所做的事情,但是大约停止了四分之一。 实际上,每次您运行针对模拟器设备的应用程序的调试版本时,Xcode都会创建有效的模拟器版本。 运行针对模拟器的构建后,您可以在派生数据文件夹中找到模拟器构建本身。 外观类似于: ~/Library/Developer/Xcode/DerivedData/{App GUID}/Build/Products/Debug-iphonesimulator 。 但这不好。 什么,您将在每次测试时调试您的应用程序,拔出模拟器应用程序进行像非利士汀一样的测试吗? 不,你比那更好。 您应该得到比这更好的东西。 您应该得到自动化的东西。 也许还有一个饼干。 Fastlane自动构建仿真器 我会说TLDR,但为时已晚。 这是使用Fastlane创建模拟器版本的方法。 xcodebuild(workspace:“#{workspace}”, 方案:“#{scheme}”, xcargs:“-configuration#{configuration} -sdk’iphonesimulator11.3′-destination’generic / platform = iOS Simulator’” )zip(路径:“ ./ simulator / Build / Products / Debug-iphonesimulator /#{app-name}”, output_path:“ ./ build /#{build-name} […]
这个故事最初发布在 apps-top.com上 Xcode代码段是可以帮助您进行编程例程的代码段或代码模板。 通常,当您更新Xcode时,代码片段没有任何反应。 但是有时候,在购买了新的Mac,重新安装Xcode或更新OS之后,您可能很难找到代码片段。 在迁移到新版本的Xcode或Mac OS Update之前,最好将代码段转移到安全的地方。 在Mac上查找Xcode代码段的3个简单步骤是: 在Mac上打开Finder 按Go>转到文件夹 类型:〜/ Library / Developer / Xcode / UserData / CodeSnippets
有时,您会发现自己的应用无法正常运行。 因此,这里提供了一些您可以使用的工具以及可以使事情变得更好的最佳实践。 这是本文的第二部分,基于2017年国际移动开发者大会MBLT DEV的Fyusion的iOS工程师,RayWenderlich.com上的iOS开发教程作者Luke Parham的主题演讲。 在这里您可以找到第一部分。 在这里观看完整的演讲: 这是一个时间分析器,其顶部有一个帧速率表。 底部是调试选项中最重要的部分。 我们将介绍两个最重要和最容易解决的问题。 第一个是颜色混合层。 这是一个非常容易解决的问题。 这使我们进入了表演警察的第一部分。 基本上,许多应用程序都存在问题:甚至iMessage(心爱的Apple应用程序)也做了很多不太出色的事情。 在这里,我们看到有很多红色: 红色表示您的标签带有白色背景。 然后,它们位于另一个白色背景之上,并且由于某种原因,它们未设置为不透明。 因此,搅拌器将这些颜色(白色和白色)混合在一起,从而得到白色。 对于具有红色的每个像素,它都会进行额外的计算而没有任何好处,但是背景仍然会变为白色。 为避免这种情况,只要它们在同一颜色上具有相同的颜色,就可以使它们尽可能不透明。 如果子视图具有相同的背景色,则不需要混合。 您所要做的就是将图层的不透明度设置为1,然后确保设置了背景色。 如果您的背景颜色是透明的,则它永远不会是不透明的。 如果打开此选项,则屏幕外渲染的元素将以黄色显示。 关于Core Animation工具的好处是您可以看到其他应用程序。 您可以打开这些选项,然后转到系统中的任何应用程序,然后可以查看它们在做什么错。 在这种情况下,Instagram顶部会显示这些小气泡,向您展示人们的故事。 如您所见,它们都是黄色的。 在iPhone 5上,它们的速度非常慢。 这是因为屏幕外渲染比alpha混合差得多。 它使GPU停顿。 最终必须在GPU和CPU之间来回进行额外的计算,因此您将获得大多数情况下不必要的额外停顿。 下一条规则:不要使用转角半径属性。 如果您有一个视图并设置了view.layer.сornerRadius,则始终会引入屏幕外渲染。 相反,您可以使用贝塞尔曲线路径和早期的同类CGBitmap内容。 在这种情况下,为UIGraphics上下文。 此函数与UIImage一起使用,它具有一定的大小,并根据该大小进行圆角处理,并使用贝塞尔曲线路径进行剪切。 然后,我们裁剪图像并从UIImage上下文返回它。 因此,这将返回一个预先舍入的图像,而不是舍入该图像所在的视图。 最后一个例子。 这是Twitter,这是此动画运行的实时视图。 它应该打开并向您显示信息,但是所有这些文本和内容均已在屏幕外呈现,因此将动画放慢了速度。 这是我在App Store上的应用程序中发现的性能最低的东西。 那么这是怎么发生的呢? 导致这种情况发生的一件事是CALayer的shouldRasterize属性。 这是图层上的一个选项,允许您缓存已渲染的纹理。 有很多奇怪的规则。 就像如果未在一定毫秒内使用它一样,它将离开缓存。 然后,如果它离开缓存,它将在每帧上进行屏幕外渲染。 拥有它可能带来的好处并不真正值得。 而且很难检查它是否真的使您受益。 如果可以,请避免屏幕外渲染和Alpha混合。 […]
Swift是一种高效的语言,但是如果您不小心的话,可能会遇到难以理解的构建和编译时间 Swift构建和编译时间可能要花费大量时间,这有很多不同的原因。 最突出和常见的原因是由于类型推断。 本质上,由于昂贵的类型检查过程,Swift编译器在解析和编译简单的Dictionary&Array文字时特别慢。 不幸的是,有时候不可避免地会出现缓慢的编译时间,但是好消息是,您可以利用某些工具和设置更改来加快Swift的编译和构建时间。 1)在Xcode中显示构建时间 首先,我们需要衡量您的编译时间。 重要的是要进行衡量,以确保本文中建议的更改实际上具有预期的影响。 您可以直接在Xcode的用户界面中启用计时器。 默认情况下,此计时器不可见,但是如果您在命令行中运行以下命令,则每次构建应用程序时都会显示时间。 defaults write com.apple.dt.Xcode ShowBuildOperationDuration -bool YES 启用计时器后,您将在Xcode的构建状态栏中看到编译应用所需的时间。 每次您要测量应用程序的构建时间时,建议您清理项目(包括构建文件夹⌘+⌥+K )并删除应用程序的派生数据。 您可以从命令行使用以下命令进行操作。 rm -rf ~/Library/Developer/Xcode/DerivedData 2)确定编译缓慢的代码 Xcode具有内置功能,可让您识别导致更长编译时间的函数和表达式。 您可以指定编译时间限制,并在代码库中标识超出此限制的区域。 打开项目的构建设置,然后将以下标志添加到“ Other Swift Flags 。 -Xfrontend -warn-long-function-bodies=100 -Xfrontend -warn-long-expression-type-checking=100 100整数表示您在函数和表达式上放置的编译时间限制。 以毫秒为单位。 编译代码时,任何超过100ms的函数或表达式都将被标记为警告。 这为您提供了重构代码并减少编译时间的机会。 3)仅构建活动架构 选择了Debug配置后,您的项目应仅构建活动架构。 此设置默认情况下应处于活动状态,但值得以防万一。 导航到Build Active Architecture Only在项目的构建设置中Build Active Architecture Only 。 确保将Debug设置为Yes并将release设置为No 4)优化dSYM生成 您可以使用dSYM文件来了解崩溃报告。 当您没有连接调试器时,这特别有用。 但是,它们需要花费一些时间来生产,因此只有在没有附加Xcode调试器的情况下才生产它们才有意义。 […]
接下来,该应用程序将从API加载餐厅数据,并将结果显示在列表中。 我们将使用Yelp API返回的数据为单元格设置样式。 我们不会在这里停止; 让我们制作一个细节屏幕,以提供有关餐厅的更多信息。 在这里我们可以显示一些照片,最重要的是地图。 那是该应用程序的精简版。 希望构建它之后,您就可以摆脱一些新技能。 首先,您将学习如何使用CoreLocation获取用户位置,如何使用Alamofire进行联网以及如何在屏幕之间传递数据。 最后,订阅频道以在新视频删除时接收通知。
在经历LISP中的词汇作用域概念时; 我想知道Swift是否提供这种支持。 确实如此。 好极了… 我使用了一个简单的函数- 数字的平方根来尝试词法作用域。 我使用牛顿法计算平方根。 以下是第一个版本。 sqRt是一个递归函数。 当先前步骤中的猜测足够好时,代码将终止。 其他猜测得到改善,并再次调用函数。 但是然后,在squareRoot函数范围之外,诸如goodEnough和perfectGuess之类的函数没有任何意义。 幸运的是,在Swift中, 函数是一等公民 。 我们可以像声明变量一样声明函数。 这使我进入了sqRt函数的第二个版本。 诸如validateGuess和goodEnough之类的函数在sqRt的函数参数上运行 。 由于这些函数已经在sqRt函数的范围内, 因此可以认为将参数传递给这些内部函数是多余的。 确实是正确的,这就是用词法作用域解决的 。 封闭功能的参数/变量在这些功能的范围内。 具有LexicalScoping的语言具有以下特征: 1.可以在其他功能中定义功能(和过程等) 2.这些内部函数可以访问封闭范围中定义的局部变量。 3.这些内部功能还可以访问封闭功能的功能参数。 通过利用词法作用域支持, sqRt函数的版本3如下。 嘿,等等! 为什么我们不能进一步利用Swift的支持来简化代码。 Square , goodEnough和ImprovementGuess看起来像变量。 因此,让我们简化一下。 我希望您了解Swift中的词法作用域支持。 让我知道你对此的想法。 如果您喜欢这篇文章,请分享/推荐。 该博客还发布在我的个人网站https://swapnilsankla.me
为了提供高质量的软件并避免退化,对于每个iOS应用程序都必须实施单元测试。 模拟对象是单元测试中的一种技术,它通过使用与真实API相同的API来创建伪造对象。 本文旨在为您提供有关如何使用假数据以及为iOS应用程序上最常出现的场景编写单元测试的最佳实践。 在编写单元测试时,我们应始终避免更改应用程序目标的真实数据,而应仅将伪造的数据用于测试目的。 以下部分将讨论如何通过使用常用iOS API的伪造数据编写测试。 在软件开发中,减少对象的依赖性始终是一个好习惯。 最佳情况下的依赖关系应注入使用它们的类中。 但是,如果我们检查现实生活中的iOS开发场景,几乎每个项目UserDefaults通过直接调用其API来存储或检索任何数据来使用UserDefaults 。 因此,我们将尝试提供一种测试UserDefaults的实用解决方案,而不是通过协议抽象其API。 我们可以在UserDefaults上创建两个新函数 始终不改变单元测试目标的应用程序数据是一个好习惯,因此,我们应该为测试目标创建另一个保存用户数据的地方。 在这种情况下,我们使用suiteName — testDefaults初始化一个新的UserDefaults对象,它完全独立于标准UserDefaults 。 让我们尝试编写一个使用UserDefaults的简单测试 由于这些数据基本上仅用于测试,因此我们应避免将这些数据挂在我们的应用程序文件中,因此,我们在完成测试后创建了一个负责删除此存储的函数。 当然,清除此数据的最佳位置是我们的单元测试类中的tearDown函数。 Singletons对象在iOS上的许多API上得到了广泛使用,我们可以在NSFileManager , NSApplication , UIApplication以及其他许多地方找到它们。 对于iOS开发人员而言,了解如何测试单例是一件有用的事情。 在我们的示例中,我们将使用apple的iAd框架。 我们将创建一个文件以获取本地JSON响应,而不是请求广告属性详细信息时的真实数据。 iOS中的一个不错的功能是,迅速的扩展使我们不仅可以为预定义的API添加新功能,还可以使它们符合我们自己的自定义协议。 让我们定义一个AdvertismentClient协议 之后,默认情况下,我们通过默认的ADClient和我们的虚假广告客户端都遵守此协议,如下所示 然后,我们将依赖关系更改为 私人var adClient:AdvertismentClient = ADClient.shared() 要么 私人var adClient:AdvertismentClient = MockAdClient() 并如下使用 通过这种方式,我们可以轻松决定何时使用真实数据以及何时进行测试,这取决于我们是进行单元测试还是从实时应用程序目标中调用API。 核心数据在iOS中仍非常用于缓存数据。 测试核心数据实体可能很棘手。 下面我们将解释组织核心数据服务和伪造数据的良好实践。 通常,在大多数情况下,创建一个负责在数据库中获取和写入特定数据的服务类总是一件好事,而不是在整个项目中使用核心数据代码。 这主要有两个好处: 它使您与正在使用的基础数据库脱钩,如果将来您想用任何其他数据库替换核心数据,则只需在一个类中进行更改。 通过这样做,我们可以轻松确定将使用哪个CoreDataStack或在其他框架中可能需要的任何其他设置。 我们将创建一个CoreDataStack协议,然后创建两个符合该协议的MainCoreDataStack ,一个MockCoreDataStack和一个MockCoreDataStack 。 然后,取决于我们是在应用程序目标上还是在单元测试目标上使用它,它们中的任何一个都可以初始化我们的DatabaseService。 我们的主要核心数据堆栈将具有如下的默认设置 […]
在Swift Post上以更好的格式阅读此文章。 每个iOS开发人员都需要了解iOS应用程序的可能状态。 知道该应用何时终止或处于不活动状态,使我们知道在幕后能做什么,哪些可能行不通。 应用程序在某些情况下(例如处理切换,应用程序间通信等)需要额外的工作。 为什么我们需要知道? 首先,我们应该对应用程序的启动做出适当的响应。 某些第三方库需要在应用程序的不同状态下进行设置。 另外,我们应该准备该应用程序以使其在前台工作。 我们可能需要提供不同的用户体验。 例如,我们的应用程序在进入前台时都可能要求输入密码。 另一方面,我们的应用程序可以像Dropbox一样在后台运行时上传图像。 甚至我们可能想在应用终止后从用户离开的地方重新打开。 因此,每个功能在不同的应用程序状态下需要不同的实现。 因此,在提供不同且更好的用户体验的同时了解状态和转换可能至关重要。 我们需要知道些什么? 事不宜迟,以下是状态的简要说明: 未运行 :应用未由系统启动或终止。 后台 :应用程序在后台运行,仍然能够运行代码。 但是此状态的持续时间由OS确定,并且代码执行可以随时中断。 如果开发人员要求额外的时间来执行一些代码,则时间可能会更长。 在某些情况下,可以直接在后台模式下启动应用程序。 例如,如果在收到远程推送通知时开始下载某些内容,则该应用程序可以在后台模式下启动。 非活动状态 :通常是启动应用程序的活动状态和背景状态之间的过渡状态。 例如,如果我们在应用程序处于前台状态时收到电话,它将进入非活动状态。 活动 :当应用程序处于前台并且可以接收事件时,它处于活动状态。 已挂起 :当应用程序处于后台状态时,系统将其挂起,并且该应用程序无法执行任何代码。 没有任何有关暂停事件的通知。 系统会自动挂起该应用程序。 我们如何知道何时进行状态转换? UIApplication是代表我们的应用程序的对象。 它会设置所有内容并启动应用程序运行。 UIApplication对象通过UIApplicationDelegate通知我们。 当UIApplication对象控制系统与应用程序对象之间的通信并管理事件循环时,我们在UIApplicationDelegate对象中编写我们的自定义代码,以处理应用程序的启动以及状态之间的转换以及更多其他事情。 因此,让我们看一下UIApplicationDelegate中调用了哪些方法,以及何时需要在每个方法中添加代码。 application(_ application:willFinishLaunchingWithOptions:) 调用willFinishLaunchingWithOptions ,我们知道我们的应用程序的启动过程已启动,主故事板或nib文件已加载,但该应用程序仍处于非活动状态。 如果我们的应用是由于特定原因启动的,例如远程推送通知或主屏幕快捷方式,则此信息将在options 。 这里要了解的重要一点是,在这些情况下,系统可能会调用其他UIApplicationDelegate方法。 例如,如果调用该应用程序以打开URL,则系统将调用application(_:open:options:)方法。 options为我们提供了必要的信息,以便我们对这些事件做出正确的反应。 另一个很好的例子是Twitter feed。 我们可以看到,无论何时终止Twitter iOS应用并再次打开,它都会从我们离开的位置恢复。 它不会一直滚动到顶部。 如果我们要实现相同的状态恢复功能,则所需的步骤之一是在willFinishLaunchingWithOptions调用UIWindow的makeKeyAndVisible()方法,而不是在application(_ […]