结果: 凉! 现在,我们需要调整滚动视图内容的高度,以处理整个表视图内容+标头。 不幸的是,我无法通过scrollView.contentSize属性执行此操作 ,它什么也不做。 为此,我创建了rootContainerView 。 要更改高度,我们实际上需要一个锚点,将其添加并与代码连接。 而使一切正常的最后一件事。 调用tableView.layoutIfNeeded()以重新计算表格内容的高度,并将此内容大小的高度设置为我们先前创建的高度约束。 在下面的屏幕截图中完成了控制器代码和层次结构。 已完成的代码 GistBox代码段 完成!☺️
嗨! 如您所见,这篇文章的标题由两部分组成。 “ 您的观点足够愚蠢 ”是指在项目中的类之间管理代码,这确实是一个有趣的话题,但是还有第二部分-“ 一种无需模拟器即可运行测试的方法 ”。 管理代码是非常简单的主题,您可能知道这部分的内容,但是我如何在没有模拟器的情况下运行测试? 我们不是真的需要模拟器来测试应用程序吗? 原来不是! 您的意见不够愚蠢吗? 这是一个简单的模型,将存储有关一个人的信息。 这里的问题是我们的观点对正在发生的事情了解太多! 我们如何改变它? 让我们看一下MVVM模式,它将使我们可以将这些知识转移到另一个地方。 您可以在此处找到有关架构模式的更多信息 使视图变得愚蠢是获得更易于测试的更干净代码的好方法。 现在,我们可以轻松地测试ViewModel,以查看它们是否按预期工作。 由于我们的业务逻辑与布局分离,这一切皆有可能! 一种更快运行测试的方法! 您可能已经注意到,每次为iOS应用程序运行测试目标时,也会启动一个模拟器。 一段时间后您就习惯了,没关系。 只需要更长的时间。 而且我们还是必须运行模拟器……还是我们? 为什么每次运行测试都会启动模拟器? 好吧……我们需要UIKit ,它是我们应用程序中的依赖项。 UIKit是iOS特定的库。 但是我们的逻辑代码中不再有UIKit了,对吗? 这是否意味着我们应该能够在无需启动模拟器的情况下测试应用程序逻辑? 答案是肯定的! 最近,我开始考虑将大型项目介绍给许多较小的框架。 如果我的逻辑没有紧密结合,那么这应该不是什么大问题,如果您有这种区分,那么代码编写的可能性就很高。 如果我的小框架不依赖UIKit怎么办? 我可以轻松地在不同的平台(如iOS,MacOS等)上重用它们。这也是一种可用于测试这些框架的方法。 如果可以在MacOS上使用框架,那么您也可以在那里进行测试! 这意味着您不再需要模拟器! 我们如何准备针对iOS和MacOS的框架? 在下面,您将找到有关如何创建跨平台框架的文章。 这是Anthony Colangelo的“ Xcode跨平台框架”的链接 使用逻辑创建框架之后,剩下要做的是: 创建OSX单元测试套件的目标 作为要测试的目标,请选择以MacOS为目标的框架 做完了! 通过为应用程序的业务逻辑建立单独的框架,我们获得了: 无需启动模拟器即可测试逻辑的能力 不同平台之间的可重用代码 更清晰的代码,在部分中更易于理解 结论 我相信,这种结构化代码的方式可以使您受益匪浅,并且可以使代码和测试更加简洁,而无需花费很多时间来运行。 我想与您分享的一种在没有模拟器的情况下运行测试的方法对我来说是一种“概念证明”。 我愿意在战场上尝试更多,并观察其适用性。 您如何解决这些问题? […]
我最近有机会涉嫌添加Apple Pay以在应用程序内接受付款。 请务必注意Apple Pay的含义: –购买实物产品(例如T恤) –付费服务(例如乘坐出租车) 另一方面,Apple Pay不适用于应用内购买: –服务订阅(例如记笔记应用程序) –数字资源(例如宝石或数字音乐) 在这个最低限度的教程中,我将向您展示如何使用Stripe在您的应用程序中接受Apple Pay,而没有任何多余的装饰,以便您可以取出代码并在自己的应用程序中使用它。 请注意,这不会从您的信用卡中扣除费用,因此不必担心测试此代码。 首先,让我们创建一个单视图项目。 2.添加项目设置。 3.添加Apple Pay功能。 4.添加商家ID。 点按我圈出的加号按钮。 Xcode将在您的开发人员帐户中自动创建此商家ID。 关于Xcode的新版本的妙处在于,您无需去developer.apple.com或itunesconnect.apple.com来进行一些晦涩的设置。 许多事情会自动为您完成。 Apple Pay的目的是授权开发人员并向其提供令牌,以便向用户收费。 您需要一项服务才能实际执行收费。 我们将使用Stripe,因为它非常容易设置和使用。 5.在www.stripe.com上创建一个Stripe帐户。 6.为Stripe创建证书以能够处理付款。 转到Stripe中的仪表板,选择“付款”,然后选择“ Apple Pay”。 点击添加新应用程序,然后按照提示进行操作。 它们非常详细,并包含指向开发人员门户中生成证书并上传到条带中所需去的链接。 7.从Stripe获取API密钥,因为稍后将使用它们。 8.我们将使用cocoapods将Stripe SDK包含到项目中。 9.现在,我们终于可以开始编码了! 在您的AppDelegate中,导入Stripe并更新您的applicationDidLaunch代码。 您需要添加在Stripe的步骤8中获得的可发布密钥,您会在其中看到“您的可发布密钥”: 12.现在,我们可以添加代码以实际显示Apple Pay对话框。 为此,我们使用PKPaymentAuthorizationViewController。 我们添加了PKPaymentAuthorizationViewControllerDelegate,以便能够在用户与Apple Pay UI交互时处理事件。 14.如果单击“使用密码付款”按钮,则可以完成交易,但实际上不会从用户的信用卡中扣款。 为此,我们需要向应用程序添加一个后端。 在本教程中,我将使用node.js Express服务器。 (您可以使用所需的任何类型的后端服务器来执行此操作。您只需要公开一个供我们调用的API即可。您可以通过此处安装节点。安装节点后,您可以创建一个文件夹,运行“ npm init ”,然后按照提示进行操作。 15.我们将需要安装三个软件包才能启动快速服务器。 为此,您可以运行“ […]
自10.2.7版以来,可可就包含了NSError 。 这是在Cocoa应用程序中表达和返回错误的标准方法。 NSError不仅仅是简单的错误处理代码可以使用的对象。 它具有许多属性和相关的API,尤其是在macOS上,使其非常适合直接呈现给用户。 自从Swift 2引入以来,就可以抛出 Swift ErrorType实例,并使它们自动桥接到NSError。 不幸的是,这种桥接行为相当有限。 桥接到Objective-C API的ErrorType实例非常简单。 他们缺乏本地化的描述,故障原因,恢复建议,帮助锚等。 如果您仅开发移动应用程序,这似乎并不那么糟糕。 大多数iOS应用程序不使用错误恢复或帮助锚等功能。 如果像我们一样开发macOS应用程序,那就更成问题了。 macOS内置了使用NSResponder或NSAlert的initWithError:上的-presentError :呈现丰富错误警报的支持。 如果提供的NSError实例具有完全填充的userInfo字典,则将大大改善用户体验。 例如: 相对于: 尽管iOS并没有像macOS那样立即提供给用户呈现NSError的功能,但是您可以使用UIAlertController或一些其他自定义的瞬态或内联警报,轻松在自己的应用中为NSError呈现创建类似的系统。 我们已经在为客户开发的iOS应用程序中做到了这一点。 未来是光明的 Swift Evolution提案SE-0112描述了Swift的未来版本将如何改善Error ( 错误类型的新名称)与NSError的桥接。 该提案解决了当前桥接行为的所有局限性。 但是目前,我们必须自生自灭 但是,与此同时,我们陷入了Swift 2的困扰– Xcode 8和Swift 3的初始beta版本没有包含SE-0112的实现,但是最近它已经实现(即,Xcode 8 beta 5包含了新的Error协议)。 下面,我提供了一种扩展ErrorType的简单机制,以将更丰富的NSError行为带入您的iOS和macOS Swift 2应用程序。 NSErrorUserInfoValueProviding Itty Bitty Apps 总部位于澳大利亚墨尔本, 为大小客户提供了出色的移动和Mac软件。 这也使 揭示 -适用于iOS开发人员的功能强大的运行时视图调试。
“ Aujourd’hui nous allons illustreràtravers plusieurs L’utilitéde reduce and filter, fond d’ordresupérieurpour manipuler les collection”。 过滤 国务卿,布克尔·波克勒和卢旺达·雷蒙·弗朗西斯科·德·雷蒙·弗朗西斯·科普尔等人收藏,并附有条件性唯一性证书。 Voici签名: 原始封包和封包封的功能以及原封不动的清单。 禁止单身或单身的人在每次旅行中享有永久的权利。 对偶的支持者,对传统的声音的支持: Voici维护人员按功能选择过滤功能 : 商业评论书,以及精美的纪念章和纪念章过滤器,以及不动产说明书。 降低 塞隆语和确定性歌曲的用法和样例:乘数,索性等…独特的价值和价值。 Voici签名: 入门级和高级级的参数功能。 最有价值的初次使用权参数和最终使用权的参数将被优先考虑以保证其最终产量和价值。 法国传统音乐的支持者: Voici维护人员lemême示例avec la fonction reduce : 可以有效地减少不必要的损失,并可以轻松地解决价值问题,并可以有效地降低成本。 结论 遵循性原则可对各种功能进行过滤并 减少代码的永久性添加,并具有持久性和持久性。 N’hésitezpasàlaisser un commentaire si des ou des remarques。
在本文中,我将分享我之前工作过的项目中使用的APIManager。 它是一个单例类,用于管理不同类型的API请求,因此实现将很容易且可重用。 配置 首先,我们需要用于请求和响应类的映射模型才能使用服务。 因此,在APIManager中,使用模型来处理网络请求/响应操作。 您可以在这里找到详细信息。 使用Alamofire和EVReflection自动映射和解析JSON 我经常使用Alamofire进行HTTP联网,这是用Swift编写的流行联网库。 因此,它是… medium.com 另外,我还使用了RouterManager作为APIManager,您可以在这里找到。 使用Swift中的路由器为IOS应用程序更好地路由 在本文中,我将讨论在我正在制作IOS应用程序的项目中使用的其他可重用类。 APIManager使用另一个管理器来处理不同的需求,即AlertManager处理错误警报弹出窗口,而ErrorManager处理错误操作等。因此,在本文中,我省略了有关它们的详细信息。 我将在下一篇文章中分享。 脚步 在/ managers文件夹中设置一个APIManager。 设置您的API方法,方法将请求/响应类作为参数,并使用RouterManager类处理路由以进行操作(.GET,.POST等) 经理 实作 在ViewModel,Presenter等中,可以调用APIManager的方法(例如.getLogin,.postLogin)等。 因此,响应将由APIManager处理,您可以完成自己的任务。 (即将LoggedInState设置为.loggedIn或重定向到其他场景等) 感谢您的阅读。
那么,代表是什么? …在软件开发中,有通用的可重用解决方案体系结构可帮助解决给定上下文中常见的问题,可以说这些“模板”被称为设计模式。 委托是一种设计模式,当特定事件发生时,该模式允许一个对象向另一个对象发送消息。 想象一下,对象A调用对象B来执行操作。 一旦动作完成,对象A应该知道B已完成任务并采取必要的动作,这可以在代表的帮助下实现! 为了获得更好的解释,我将向您展示如何创建一个自定义委托,该委托在简单的应用程序中使用Swift在类之间传递数据,首先下载或克隆此启动程序并运行它! 您可以看到一个包含两个类的应用程序,即ViewController A和ViewControllerB。B有两个视图,这些视图可以在点击时更改ViewController的背景颜色,没有什么太复杂了吧? 好了,现在让我们以一种简单的方式来考虑,当点击B类的视图时,它也可以更改A类的背景颜色。 问题在于该视图是B类的一部分,对A类不了解,因此我们需要找到一种在这两个类之间进行通信的方法,这就是授权的亮点。 我将实现分为6个步骤,因此您可以在需要时将其用作备忘单。 步骤1:在ClassBVC文件中寻找实用标记步骤1,并添加此 //MARK: step 1 Add Protocol here. protocol ClassBVCDelegate: class { func changeBackgroundColor(_ color: UIColor?) } 第一步是创建一个协议,在这种情况下,我们将在B类中创建该协议,在该协议内,您可以根据实现的要求创建任意数量的函数。 在这种情况下,我们只有一个简单的函数,它接受可选的UIColor作为参数。 命名协议的一种好习惯是在类名的末尾添加代理人一词,在本例中为ClassBVCDelegate。 步骤2:在ClassVBC中寻找步骤2的实用标记并将其添加 //MARK: step 2 Create a delegate property here. weak var delegate: ClassBVCDelegate? 在这里,我们只为类创建一个委托属性,该属性必须采用协议类型,并且应该是可选的。 另外,您应该在属性之前添加weak关键字,以避免保留周期和潜在的内存泄漏,如果您不知道那意味着什么现在就不用担心,只需记住添加此关键字即可。 步骤3:在ClassBVC的handleTap方法中查找步骤3的实用标记并将其添加 //MARK: step 3 Add the delegate method call here. […]
1.WAYPOINT MISSION:此任务附带一系列预定义的路标(位置)。 设置高度和航向角后,无人机会飞到每个航路点并执行所需的动作,例如捕获照片或录制视频。 2.热点任务:在此任务中,无人机以定义的半径和高度绕着给定位置(热点)盘旋。 可以为此任务定义速度,摄像头动作,旋转方向。 3.DOWNSHOTMISSION(下潜任务):这是无人机飞行到指定位置,到达所需高度并在该位置执行摄像机操作的任务。 4.全景任务:在此任务中,相机旋转并以开发人员可以定义的不同角度拍摄照片,然后可以手动拼接拍摄的照片以制作全景照片。 5.跟随我的任务:在跟随我的任务中,飞机将遵循不断发送给飞机的GPS坐标,并保持恒定的高度间隔。 如果超过6秒钟未收到新的GPS坐标,则飞机将悬停在原地。 任务控制负责执行任务。 任一个任务 可以通过专门的任务负责人来运行,或使用时间线来连续进行一系列任务和动作。 请参阅链接以获取有关任务控制的详细信息。 任务运营商: 它们提供API,例如运行,暂停,停止以控制任务,并且可以通过侦听器跟踪状态。 他们负责执行单项任务。 很少有运算符是waypointMissionOperator , hotpointMissionOperator , PanoramaMissionOperator , followMeMissionOperator 。 时间线是所有时间线元素( DJIMissionControlTimelineElement )的集合 可以是诸如航路点任务(DJIWaypointMissionOperator),热点任务(DJIHotpointMissionOperator)或一系列动作之类的任务 。 可以给每个元素一个动作,例如DJIGoToAction , DJIAircraftYawAction , DJIGimbalAttitudeAction,以及捕获照片或录制视频的动作等。 为什么要时间表? 当任务执行者执行单个任务时,可以使用时间表来加载多个任务。 DJIMissionTrigger可以与时间轴元素一起使用,以在满足任何特定条件时通知用户。 注意 : 📣任务控制时间表仅适用于DJI飞机,不适用于任何DJI手持设备。 如何执行? 首先,我们需要创建定义无人机行为的时间轴元素。 定义所有元素(动作)后,将使用scheduleElements将这些元素安排到任务控制中 然后startTimeline 。 可以添加侦听器以跟踪时间轴的进度。 注意 : 📣参考链接以下载有关创建时间轴的示例。 该示例显示将Downshot任务添加到时间轴。 有关时间轴的更多信息,请参阅文档 。 以下是一些常见的常见问题和解决方案: 这些是在开发过程中可能会遇到的常见问题。 产品断开连接是面临的一个常见问题,其发生的原因有很多,例如USB电缆损坏,电池电量不足,退出了模拟器。 […]
安装Firebase SDK。 在Firebase控制台中,创建新项目,然后将Firebase添加到您的iOS应用 (输入您的捆绑包标识符)。 下载GoogleService-Info.plist并将其复制到您的Xcode项目根目录中。 将Firebase的依赖项添加到Podfile并安装 pod“ Firebase / Core” 导入Firebase模块并配置FirebaseApp共享实例,通常在应用程序的应用程序中:didFinishLaunchingWithOptions:方法: FirebaseApp.configure() 要启用/禁用调试日志记录编辑方案并添加启动时传递的参数: -FIRAnalyticsDebugEnabled或-noFIRAnalyticsDebugEnabled 将Google跟踪代码管理器添加到您的项目 将Google跟踪代码管理器依赖项添加并安装到您的项目中: pod’GoogleTagManager’,’〜> 6.0′ 在Google跟踪代码管理器帐户中,创建容器(在ADMIN部分中),然后选择Firebase(iOS) SDK 。 提交更改并发布(在“ 工作空间”部分中)。 下载您的容器(“ 操作”->“在VERSION中 下载”部分)并复制到XCode项目根目录中的名为container的文件夹中 记录事件和变量 Google跟踪代码管理器使用Firebase Analytics的事件,参数和用户属性来触发和构建您在Google跟踪代码管理器网络界面中配置的代码。 从这种意义上讲,您的Firebase Analytics实施将充当您的数据层。 我使用EventType枚举来存储和管理将记录的所有事件。 AnalyticsLoger类的方法logEven也使用此参数。 我们可以创建变量来处理 设置Google Analytics(分析)跟踪ID 创建自定义 触发器。 为通用Google Analytics(分析)(而非Firebase Analytics)创建新标签 。 我们必须选择标签类型并放入我们的Google Analytics(分析)跟踪ID。 然后,我们必须选择触发器。 要在Universal Analytics Console中查看活动屏幕名称 ,我们需要设置文件screenName ,值是我们之前创建的事件参数变量。 毕竟,我们必须发布容器。 发布之后,GTM最多需要12个小时来更新应用中的容器。 如果您的应用程序处于开发阶段,则可以预览容器,或下载容器并将其包含在内以在应用程序中进行更新。 如果我们更换容器并想立即对其进行测试。 发布后,我们必须下载并复制到Xcode。 […]
面对现实吧,编写测试在iOS开发中并不那么流行(至少与为后端编写测试相比)。 我曾经是一个单独的开发人员,但最初并未受过本地“测试驱动”开发人员的培训。 因此,我花了很多时间研究如何编写测试以及如何编写可测试的代码。 这就是为什么我要写这篇文章。 我想分享我在Swift中进行测试时发现的东西。 希望我的见解可以节省您在丛林中奔波的时间。 在本文中,我们将讨论测试101的开始: 依赖注入 。 想象一下,您正在编写测试。 如果您的测试目标(SUT,被测系统)以某种方式与现实世界相关,例如网络和CoreData,则编写测试代码会更加复杂。 基本上,我们不希望我们的测试代码依赖于现实世界中的事物。 SUT不应依赖于其他复杂系统,因此我们能够更快,时间不变和环境不变地对其进行测试。 此外,重要的是我们的测试代码不要“污染”生产环境。 “污染”是什么意思? 这意味着我们的测试代码将一些测试内容写入数据库,将一些测试数据提交至生产服务器,等等。这就是存在依赖项注入的原因。 让我们从一个例子开始。 给定一个应该在生产环境中通过Internet执行的类。 Internet部分称为该类的依赖项。 如上所述,当我们运行测试时,该类的Internet部分必须能够用模拟或伪造环境代替。 换句话说,该类的依赖关系必须是“可注入的”。 依赖注入使我们的系统更加灵活。 我们可以在生产代码中“注入”真实的网络环境。 同时,我们还可以“注入”模拟网络环境来运行测试代码,而无需访问互联网。 TL; DR 在本文中,我们将讨论: 如何使用依赖注入技术设计对象 如何在Swift中使用Protocol设计模拟对象 如何测试对象使用的数据以及如何测试对象的行为 依赖注入(DI) 开始吧! 现在,我们将实现一个名为HttpClient的类。 HttpClient应该满足以下要求: HttpClient应该使用与分配的URL相同的URL提交请求。 HttpClient应该提交请求。 因此,这是我们的HttpClient的第一个实现: 似乎HttpClient可以提交“ GET”请求,并通过闭包“ callback”传递返回的值。 HttpClient的用法 问题是:我们如何测试它? 我们如何确保代码满足上面列出的要求? 直观地,我们可以执行代码,为HttpClient分配一个URL,然后在控制台中观察结果。 但是,这样做意味着我们每次实现HttpClient时都必须连接到Internet。 如果测试URL在生产服务器上,那似乎更糟:您的测试运行在一定程度上确实影响了性能,并且您的测试数据已提交到真实世界。 如前所述,我们必须使HttpClient“可测试”。 让我们看一下URLSession。 URLSession是HttpClient的一种“环境”,它是Internet的网关。 还记得我们所说的“可测试”代码吗? 我们必须使Internet组件可更换。 因此,我们编辑HttpClient: 我们更换 与 然后我们添加一个新变量: […]