这是一系列文章的第三部分,涵盖了如何使用许多不同的Pod和工具从头开始创建iOS应用,从而使您的生活更轻松。 如果您错过了前面的部分,请检查它们的第一部分和第二部分。 在这篇文章中,我将讨论持续集成Danger和Fastlane。 该项目的源代码可在此存储库中找到。 我为此帖子创建了一个名为v0.3的标签,您 只需克隆存储库并切换到标签v0.3。 持续集成 持续集成(CI)是一门广泛的主题,其中涉及许多教程和书籍,但它是一个相对简单的概念。 在投入生产之前,应尽可能频繁地集成代码以及早发现错误。 如ThoughtsWorks网站中所定义。 “持续集成(CI)是一种开发实践,它要求开发人员每天多次将代码集成到共享存储库中。然后,每个签入都通过自动构建进行验证,从而使团队能够及早发现问题。通过定期集成,您可以快速检测错误,并更轻松地找到它们。” “持续集成不会消除错误,但是确实可以使查找和删除错误变得更加容易。” Martin Fowler 在贝娄,您可以找到有关此主题的更多信息。 持续集成| ThoughtWorks 一家全球软件公司,专注于软件设计和交付。 我们提供专业的服务和产品,以及…… www.thoughtworks.com 基本上,我们必须有一些东西可以监视我们的存储库并运行自动构建。 测试 每次发生任何更改时都将部署过程。 那是CI服务器。 它们有各种形状和尺寸,您可以在这里找到它们的列表。 这篇博客文章将使用Travis,它是一个与github配合得很好的CI,并且是Github上托管的开源项目的主要选择。 特拉维斯 要使用travis,我们首先需要创建一个名为.travis.yml的文件 这就是全部,之后,您可以在每次将新的推送或PR添加到存储库时检查构建。 Travis可以像您期望的那样非常可定制,您可以找到许多不同的配置,它们具有有关此主题的大量文档。 我建议从一个简单的开始,并以此为基础。 同样值得一提的是,您可以看到在travis的脚本阶段中,我们仅调用两件事。 脚本: -快速通道测试 -捆绑执行程序的危险 第一个: -快速通道测试 是我们的自动化管道,是我们在上一篇博客文章中创建的自动化管道。 对于我们的示例,我们仅运行测试并生成覆盖率,但是我们可以做的还很多。 Fastlane可以处理和自动化您的整个管道,测试,构建,部署,生成和上传屏幕截图,发送通知等。 互联网上有许多涵盖所有这些主题的教程,您应该明确检查它们。 重要的是,一旦我们在开发人员机器上掌握了它,在CI中运行它就非常容易。 我们所需要的只是调用Fastlane的车道(例如:例如我们的“测试”),我们一切顺利。 注意事项:首先,请确保您的自动化管道在本地工作,它们带有CI,可以节省您的时间。 第二个: -捆绑执行程序的危险 全部关于代码审查……让我们深入了解它。 危险系统.. Danger是由Orta,Felix Krause和其他出色开发人员创建的令人惊叹的新工具。 危险在CI流程中运行,使团队有机会自动执行常见的代码审查琐事。 这提供了构建中的另一个逻辑步骤,通过此Danger可以帮助减少日常代码检查中的死记硬背任务。 您可以使用“危险”来整理团队规范。 让人们去思考更棘手的问题。 她通过根据您使用Ruby脚本语言创建的规则将消息保留在PR中来实现此目的。 […]
我知道我知道你一定像Swift 4 WTF! 不用担心,Swift 4尚未发布,但是您仍然可以使用Swift开发快照来体验Swift 4的功能。 如果您有兴趣安装Swift 4快照,请查看此链接。 有许多不同的方案,您要将类转换为数据表示形式。 一个非常普遍的需求是当您想将JSON数据作为HTTP正文发布时。 最常见的方法之一如下所示: JSONSerialization类负责返回Data对象,然后可以将其作为HTTPBody传递给请求。 Swift 4中的JSONEncoder和JSONDecoder Swift 4引入了JSONEncoder和JSONDecoder类,它们可以轻松地将对象转换为编码的JSON表示形式。 查看以下示例: 注意,使用了新的Codable协议,该协议使Language结构可编码和可解码。 更高版本的JSONEncoder类用于通过使用encode函数执行编码。 就像编码一样,解码也非常简单,如以下代码所示: 很简单吧! 通过使用协议和扩展,我们甚至可以使它更简单。 让我们创建一个自定义的Serializable协议,它将为我们执行编码。 可序列化 使用JSONEncoder和JSONDecoder很好,但是我们当然可以使它更无缝地执行编码和解码。 代替创建JSONEncoder的实例,类或结构应该能够自己编码。 看一下下面的Serializable协议,所有对编码感兴趣的模型都可以遵循该协议。 代替在每个类或结构中分别实现序列化功能,我们将使用协议扩展的功能来创建默认实现。 上面的代码将给您以下错误: 游乐场执行失败:错误:MyPlayground.playground:8:36:错误:参数类型“ Self”与预期的类型“ Encodable”不符 返回尝试? encoder.encode() 问题在于“自我”不是可编码的。 我们可以通过使Serializable协议符合Codable协议来轻松解决此问题,如下所示: 现在,您可以使用新的Serializable协议轻松编码模型,如下所示: 确保您的语言模型符合“可序列化”协议而不是“可编码”协议。 我相信,在构建依赖于网络服务并发布编码数据的应用程序时,Swift 4中的这些新进步将真正使开发人员受益。 我可以担任高级iOS开发人员。 如果您有兴趣,请在此处查看我的简历。 如果您喜欢这篇文章,那么您可能会对我的课程“ iOS精益控制器的完整指南 ”感兴趣。 本课程涵盖许多有用的架构模式,以构建更好的iOS应用程序。 享受74%的折扣,请单击以下链接: https://www.udemy.com/a-complete-guide-to-lean-controllers-in-ios/?couponCode=MAKEMELEAN
细节可能会有所不同,但是不管您的观察对象,观察者或订阅如何,基本含义都保持订阅的含义。 要发现的关键是,忽略参考周期管理器 (又称disposable ,可以使您摆脱自己破坏参考周期的可能性。 它是进入内存配置的门户药物,一旦无法使用,就再也没有回头路了。 如果使用_ =语法,则基本上可以说,释放observable observer和observer的唯一方法是完成可观察序列。 有时候这可能正是您想要的! 例如,如果您要调用Observable.just ,则不必确保打破周期,这并不重要。 单个元素被瞬时发出,随后是.completed事件。 但是,在许多情况下,您可能无法完全确定所讨论的可观察性的完成可能性: 您从另一个对象获得了Observable ,文档没有说明它是否完成, 您从另一个对象获得了Observable ,并且文档确实说明该对象已完成,但是在此过程中该对象的内部实现发生了一些变化,没有人记得要更新文档, Observable明显未完成(示例包括Variable , Observable.interval ,subject), 可观察的实现中存在错误,例如忘记在Observable.create闭包中发送.completed事件。 由于您几乎无法控制应用程序中的所有可观察对象,即使那样也有可能出错,因此经验法则是确保自己打破参考周期。 要么保留对disposable的引用,并在时间到时调用.dispose()方法,要么使用方便的助手(例如DisposeBag来帮您完成。 您还可以使用.takeUntil运算符提供一个单独的可观察到的循环中断。 选择哪种方式取决于您的具体情况,但请始终记住: 既然我们已经解决了所有问题,我觉得我欠您一点解释。 我上面绘制的心理模型很好,这是一种心理模型,因此并不严格正确。 当前的RxSwift实现(在撰写本文时版本3.x / 4.x)发生了一些复杂的事情。 要了解实际行为,让我们更深入地研究RxSwift内部。 在哪里实现subscribe方法? 毫无疑问,搜索的第一位将是ObservableType.swift文件。 它包含订阅方法的声明,作为ObservableType协议的一部分: func subscribe( _ observer: O ) -> Disposable where OE == E 什么实现了此协议? 基本上,所有各种类型的可观察物。 让我们集中讨论称为Observable的主要实现,因为它是RxSwift中定义的所有可观察对象(除了其中之一)的基类。 其subscribe方法版本简短而简单: public func subscribe( _ […]
我是用于创建和验证模型的Builder设计模式的狂热用户。 为什么? 它使模型创建变得非常简单。 让用户:用户? = UserBuilder() .set(field:.firstName(“ Matt”)) .set(field:.lastName(“ Hoffman”)) .set(字段:.username(“ mhoffman”)) 。建立() 创建模型时,我通常不知道所传递的值是否有效。 因此,我不能简单地创建模型。 在创建模型以验证字段之前,我必须编写很多逻辑。 如果习惯于在模型外部(即在控制器中)编写此验证,则将发现您重复了代码,并且出于速度考虑,可能会错过错误情况。 模型不是只在一个地方创建的。 它们是从网络请求中读取JSON时创建的,在各种视图中,当您根据用户输入创建模型以在应用程序的其他部分中使用时,这会留出很大的出错空间。 构建器模式解决了重复代码的问题,但是仍然需要您仔细考虑在build()阶段进行的所有验证。 为每个字段编写每个set()函数非常繁琐。 如果我告诉您有人花了几天时间使Builder模式更易于实现,并且更容易包含模型所需的所有验证逻辑,该怎么办? 这是您的幸运日! 老路 假设您有一个UserSignUp对象,该对象具有字段firstName , lastName , username , password , confirmPassword ,其中lastName不是必需的。 这就是我以前编写“构建器模式”的方式: 上面的方法是干净且可行的。 如果您不熟悉Builder模式,请继续使用它! 接下来我将要描述的面向协议的方式实际上需要更多代码,但最终会使验证逻辑更加清晰,当添加新字段时,编译器将警告您尚未通过验证功能处理的验证案例。枚举。 新方法 而已! 如您所见,在面向协议的构建器模式中肯定有更多的代码,而不是简单地创建一个自定义的构建器,而没有为每个模型重用代码。 但是,每当您将字段添加到面向协议的模式时,如果您不指定字段的验证和isRequired,编译器都会抱怨。 此外,通过这种方法,可以很清楚地在何处添加模型的验证逻辑。 最后,代码重用是很好的,并且如果需要添加其他方法进行验证,那么它可以为所有构建者使用! 该你了 现在,如果您喜欢我在Swift中使用Builder模式的方法,那么恳请您在项目中使用它并获得回报。 然后,当您遇到改进时,请告诉我! 否则,如果您认为我的工作过于复杂,并且您有另一种方法,或者您只是比我更了解Swift并且可以改进此代码,那么我希望收到反馈。 TL; DR 使用构建器模式使模型在Swift中变得强大。 我做了一个面向协议的实现,您可以在这里找到。
推送是任何移动应用程序中不可思议且必不可少的功能。 亚马逊的AWS通过其惊人的简单通知服务(SNS)为移动提供了推送服务。 我个人发现使用Swift和SNS在iOS上实现推送有点困难,主要是因为没有关于该主题的简化的分步文档。 本教程就是这样:一个简单的分步教程,介绍如何使用Swift和SNS在iOS上实现推送通知。 我们将您要在下面学习的内容纳入了此处列出的大多数产品中。 本教程旨在握住您的每一个步骤 。 我们将创建一个Swift / SNS push应用程序。 首先创建一个单页应用程序:打开XCode并创建一个单页应用程序。 您可以随意调用该应用程序,但要确保名称是唯一的。 创建p12证书:为新应用创建应用ID,推送启用的证书和p12文件。 这是一个很好的教程,请执行以下操作:单击此处。 a)创建一个新的平台应用程序:登录到AWS并转到SNS仪表板。 单击“创建平台应用程序”链接。 b)输入平台应用程序详细信息:输入您的应用程序名称(您的唯一名称)。 推送通知平台应为“ Apple开发”。 4. 完成创建平台应用程序:在下拉菜单中选择“ iOS推送证书”作为推送证书类型。 单击“选择文件”按钮,然后选择您在步骤2中创建的p12证书文件。单击“从文件加载凭据”按钮,如果您为证书创建了一个,则输入密码。 如果没有密码,请将其保留为空白。 完成所有操作后,单击“创建平台应用程序”按钮。 复制应用程序ARN以在XCode应用程序中进一步使用 → 5. 将SNS ARN插入您的应用程序委托:打开AppDelegate.swift文件,并将SNS平台应用程序ARN插入为应用程序委托的第一个变量。 自然,您的应用程序ARN将与下面的字符串不同。 /// SNS平台应用程序ARN 让SNSPlatformApplicationArn =“ arn:aws:sns:us-east-1:203525439813:app / APNS_SANDBOX / SpreebieSNSExample” 6. 下载适用于iOS的AWS开发工具包:转到此处的适用于iOS的AWS开发工具包页面,然后下载SDK或单击此处下载。 7. a)解压缩SDK文件并将其拖放到您的项目中:解压缩下载的SDK,并将AWSCore.framework,AWSCognito.framework和AWSSNS.framework文件添加到您的项目中。 b)嵌入框架:通过转到YourProject-> Targets-> General-> Embedded Binaries,嵌入刚添加到项目中的框架。 添加AWSCore.framework,AWSCognito.framework和AWSSNS.framework。 8.将AWSSNS导入到您的应用程序委托中:将AWSSNS框架导入到您的AppDelegate.swift中 。 导入AWSSNS 9. […]
几乎没有任何iOS项目没有任何依赖关系。 几乎每个项目都必须管理内部或第三方的某种依赖性。 每种主要的编程语言都有自己的依赖性管理系统。 Swift具有多种选项来管理依赖项。 苹果很久以来一直在开发自己的Swift Package Manager。 认真地讲,很久以来,iOS开发人员都渴望获得Apple支持的官方依赖项管理器,但事情似乎以乌龟的速度发展着。 Swift Package Manager仍然不支持iOS项目。 CocoaPods是iOS项目中最常用和最传统的依赖管理,因为开发人员没有其他选择。 CocoaPods是一种神奇的,不可思议的,超能力的魔咒,它使您的Xcode项目无法正常工作。 它建立依赖关系,创建工作区,执行一些脚本和其他东西。 CocoaPods运行良好,但是很少有开发人员了解运行pod install命令时发生的实际情况。 如果一切正常,每个人都会感到高兴,但是当pod安装失败时,每个人都会感到恐慌。 没有人知道如何解决该问题,需要花费数小时,数天或数周的时间才能解决由CocoaPods造成的混乱。 爱它还是恨它,无论哪种方式,您都必须使用它。 迦太基的诞生 Somone了解了iOS开发人员对CoacoPods的痛苦,并制作了一个名为Carthage的婴儿作为CocoaPods的替代品。 Carthage仅适用于动态框架,并且使开发人员能够完全控制他们对Xcode项目所做的工作。 它只是构建框架,开发人员必须手动将那些框架链接到目标的各个构建阶段。 迦太基运作良好,但缺点不多 迦太基仅适用于动态框架 迦太基的开发者社区很小,为该项目做出了贡献 使用迦太基时涉及的手动步骤很少 主要缺点是,它是如此缓慢,特别是在CI服务器上。 迦太基检出和构建每个构建的每个框架。 对于CI而言,这绝对不是一个很好的方法,因为构建速度将非常缓慢且冗长。 如果没有任何更改,则没有干净的解决方案来缓存Carthage /目录。 在这篇文章中,我们将看到如何在CI服务器上缓存Carthage目录并加快构建速度。 CI上的迦太基 迦太基最常见的用法是运行迦太基更新或脚本作为CI脚本的一部分,该脚本会修改所有依赖项以使用最新版本的Cartfile.lock文件更改,该更改不正确,并导致签出和构建所有依赖项。 这将使CI的构建速度非常慢。 因此在CI上使用迦太基的理想方法是 检查Cartfile.lock是否存在。 如果该文件不存在,那么我们必须使用Carthage bootstrap引导所有依赖项。 如果Cartfile.lock存在但未更改,则无需执行引导程序或更新操作,并且可以使用先前版本中Carthage目录中的内容。 如果存在Cartfile.lock并更改了某些依赖关系,则我们仅需引导那些过时的依赖关系,而不是全部。 现在,我们知道了如何使用Cartfile.lock状态执行引导或跳过引导的机制。 下一步将是编写一个脚本来做到这一点。 根据CI服务器提供的环境变量,我们可以通过多种方式实现这一目标。 Jenkins使用的脚本如下所示 [-f Cartfile.resolved]; 然后 CARTFILE_CHANGED =`git diff –stat $(GIT_PREVIOUS_SUCCESSFUL_COMMIT)$(GIT_COMMIT)| grep’\ […]
我们的应用程序允许志愿者记录盲人和印刷品受损人士的文章。 使用AVAudioRecorder非常简单AVAudioRecorder ,它还允许暂停,但是它没有提供任何方法来监听录音,直到过程暂停为止。 必须停止记录才能将数据写入磁盘,并使播放器(例如AVAudioPlayer , AVPlayer , AVQueuePlayer等)可以播放数据。 下图希望有助于突出显示本文中使用的类之间的联系。 NSObject隐式隐含为没有继承箭头的超类。 注意:黑色继承箭头的方向选择可能很不幸。 要解决此问题,请阅读下图, “ AVQueuePlayer 继承了 AVPlayer ” 要么 “ AVComposition 继承了 AVAsset ” 一个重要的推论是AVPlayerItem将在其init接受AVAsset , AVComposition和AVMutableComposition 。 (有关官方证明,请参阅AVMutableComposition的文档。) CAVEAT:该应用程序已经超出了这些控件的范围,但是仍然适用于一般用例(并且将提供全面的文档)。 发现这一事实后,很明显 在部分录音中必须保留参考(以最终由所选音频播放器控制的类型为准-参见下文),以及 阅读完文章后,使用AVAssetExportSession将它们连接起来。 所有这些都应在后台完成,使控件对用户透明: 记录 :实例化AVAudioRecorder对象,并开始记录。 STOP / PAUSE :停止录音,取消self.audioRecorder属性,并将音频追加到self.articleChunks数组。 播放 :用该点的部分录音实例化播放器(即self.articleChunks )并开始播放。 队列和提交 :除了目标略有不同外,它们都将连接录音片段,并使生成的音频文件充满元数据。 在使用RECORD,STOP / PAUSE和PLAY时,记录尚未完成,但在按QUEUE或SUBMIT后,将导出最终结果,并且UI会重置为其初始状态(即, self.articleChunks设置为空数组,没有发布)已选择,标题已清除等)。 AVQueuePlayer选择AVQueuePlayer作为播放器,是因为在我们的方案中,它是最简单,最快的管理方式。 反对其他玩家的原因: 可以直接使用URL或Data初始化AVAudioPlayer ,然后将播放器对象存储在数组中,但是需要花费大量精力才能实现连续播放。 AVPlayer有点高级,它仍然允许通过URL进行初始化,并且可以使用replaceCurrentItem替换当前播放的项目,因此一个对象就足够了。 缺点是后一种方法需要提供AVPlayerItem ,并且需要帮助方法来以正确的顺序连续播放音频块。 […]
我们将在本文档中完成的工作是从Alexa.com获得排名前25位的站点,并对它们运行“ dig”命令,以便查询DNS名称服务器以获取有关站点的信息。 我们将特别寻找的是这些站点的注册IP地址,以便使用CartoDB对它们进行热映射。 为了挖掘排名前50位的Alexa网站,我们首先创建一个Xcode项目。 在Mac上,转到“应用程序”文件夹,然后打开Xcode。 在出现的开始菜单中,在左侧选择第二个选项“创建新的Xcode项目”。 现在,您可以选择为新项目选择模板。 因为我们将制作一个简单的命令行工具,所以在OS X和Application下,选择“命令行工具”选项,然后按“下一步”继续。 在“产品名称”下,随意命名。 确保在“语言”选项中选择“快速”,然后按“下一步”继续。 选择项目的保存位置,然后按“创建”。 现在,在您的main.swift文件中,键入以下代码: 进口基金会 func shell(args:String …)-> Int32 { 让任务= NSTask() task.launchPath =“ / usr / bin / env” task.arguments = args task.launch() task.waitUntilExit() 返回任务状态 } //来自alexa.com/topsites/country/us的前50个站点 var sites = [“ google.com”,“ facebook.com”,“ youtube.com”,“ amazon.com”,“ yahoo.com”,“ wikipedia.org”,“ ebay.com”, “ twitter.com”,“ reddit.com”,“ netflix.com”,“ linkedin.com”,“ craigslist.org”,“ live.com”,“ […]
资料来源:Stackoverflow和互联网🤓。 Apple的定义 :供应配置文件是数字实体的集合,这些数字实体将开发人员和设备与授权的iPhone开发团队唯一地联系在一起,并使设备可以用于测试。 与Android不同,您无法在iOS设备上安装任何应用。 必须先由Apple签署。 但是,在开发应用程序时,您可能需要先对其进行测试,然后再将其发送给Apple批准。 供应配置文件充当设备和开发者帐户之间的链接。 在开发期间,您可以选择哪些设备可以运行您的应用程序以及您的应用程序可以访问哪些应用程序服务。 从您的开发人员帐户下载了配置文件,并将其嵌入到应用程序捆绑包中,并且整个捆绑包均已代码签名。 必须在要在其上运行应用程序代码的每台设备上安装开发配置文件。 如果配置文件中的信息与某些条件不匹配,则您的应用将无法启动。 每个开发配置概要将包含: 开发证书- 开发证书。 这些适用于希望在编写代码时在物理设备上测试应用程序的开发人员。 唯一设备标识符(应用程序可以在其上运行的设备列表) 一个应用程序ID( 可以包含*通配符,用于具有相似包标识符的许多应用程序 )。 —应用程序ID是由两部分组成的字符串,用于标识单个开发团队中的一个或多个应用程序。 在配置文件中指定的设备只能由配置文件中包含iPhone开发证书的个人用于测试。 单个设备可以包含多个配置文件。 那么,当我们将设备连接到xcode并安装应用程序时会发生什么? 在设备上安装应用程序时,会发生以下情况: Mac中的配置文件会转到您的钥匙串中的开发人员证书。 xcode使用证书对代码进行签名。 设备的UUID 与供应配置文件中的ID匹配 。 供应配置文件中的AppID与应用程序中的捆绑包标识符 匹配 。 所需的权利与应用程序ID相关联。 用于对应用程序签名的私钥与证书中的公钥匹配。 这是xcode签名部分的屏幕截图: 因此,从上面的图像中,您可以看到已检查AppID,已验证证书,已匹配团队,已匹配功能和权利。 如果上述所有步骤均成功,则将已签名的二进制文件发送到设备,并针对应用程序中的相同配置文件进行验证 ,并最终启动 。 如果这些条件中的任何一个失败,则该应用程序将无法安装-您将看到一个灰色的应用程序图标。 开发配置文件和分发配置文件之间的区别在于,分发配置文件不指定任何设备ID。 如果您要发布一个仅限于已注册设备数量的应用程序,则需要为此使用临时文件。 分发配置文件用于将应用提交到App Store进行分发。 苹果审核了该应用程序后,他们使用可以在任何设备上运行的自己的签名登录该应用程序。 通过对应用程序进行签名,iOS可以识别谁对您的应用程序进行了签名,并可以验证自从您对应用程序进行签名以来未对其进行修改。 签名身份由Apple为您创建的公私钥对组成。 非对称密码学 非对称加密使用公共密钥和私有密钥 。 用户必须保留自己的私钥,但可以共享公钥。 使用这些公钥和私钥,用户可以证明自己确实是他本人。 非对称密码学如何工作? 假设有一个UserA和UserB 。 […]
在创建单元测试时,我们所有人都会时不时地挣扎,主要是当MainView依赖于核心/服务类(网络服务,API服务等)时。 有一些设计模式可以帮助我们避免这种情况,但是老实说,并非每次都可行,主要是在处理遗留代码时。 因此,这里有一个易于实施的好“技巧”,可以帮助您进行测试,而无需进行任何重大的重构。 MVVM和面向协议的编程在这里可以帮助我们进行依赖注入。 将这两者结合在一起,将使我们能够创建一个符合您所有ViewModel依赖项的存根类。 我们将其称为ServiceStub 。 此类将符合我们所有的依赖协议,并将负责在运行测试时为ViewModel提供所需的信息。 听起来很不错,但我们应该开始使用一些代码来了解发生了什么。 XCode 9.2以上 斯威夫特4 熟悉Model-View-ViewModel(MVVM)模式 对Nimble或XCTest有所了解 对如何编写单元测试的基本了解 椰子足 代码 要开始使用代码,请转到此处并克隆或下载示例代码,运行pod install并打开工作区。 现在好了,我们准备开始。 该示例代码提供了两个服务类( LocationService和ApiClient )和一个MainView 。 到目前为止,对服务类的每次调用都在视图控制器上进行。 让我们通过重构视图模型的所有LocationService和ApiClient调用来更改此设置。 我们的第一步将是创建视图模型并重构我们的MainView然后测试视图模型上的所有公共功能。 首先,让我们运行该应用程序。 它使用GitHub API和用户位置来获取iOS开发人员的可用职位,但是用户可以通过键入邮政编码来更改搜索的位置。 每次用户输入新的邮政编码并进行搜索时,地址标签都会更改,并进行呼叫以获取iOS职位。 初始点 让我们创建视图模型。 为此,在“单元测试依赖项教程”内的项目导航器上单击鼠标右键,选择“新建组”并将其命名为“ ViewModels”。 现在在新创建的文件夹中使用command + N ,选择一个Swift File并将其命名为MainViewModel 。 确保在组区域下方选择两个目标。 (应用和测试目标) 现在,您的文件夹结构应如下所示。 现在,让我们移动func updateCurrentAddress()和 从MainView到MainViewModel func fetchJobsAround(postalCode: String)方法,并删除与视图控制器相关的所有代码。 添加以下代码: 我们将使用变量addressCompletion将地址传回视图控制器,并将作业结果与函数中的完成块一起addressCompletion 。 有更好的方法将数据传递回视图控制器(反应式方法,通知,委托等),但是出于本教程的考虑,我们的方法可以正常工作。 到现在为止,您的项目应该可以正常构建,以确认command […]