前语

咱们最新的 MacBook M30X 处理器能够感知到瞬间编译大型 Swift 项目,除此之外,编译代码库只是咱们迭代周期的一部分。包括:

  • 从头启动它(或将其布置到设备)
  • 导航到您在运用程序中的先前位置
  • 从头生成您需求的数据。

假如您只需求做一次的话,听起来还不错。可是假如您和我相同,在特别的一天中,对代码库进行 200 – 500 次迭代,该怎么办呢?它增加了。

有一种更好的办法,被其他渠道所接受,而且能够在 Swift/iOS 生态系统中实现。我现已用了十多年了。

从今天开端,您想每周节约多达 10 小时的作业时刻吗?

热重载

热重载是关于摆脱编译整个运用程序并尽或许避免布置/从头启动周期,一起答应您编辑正在运转的运用程序代码而且能当即看到更改。

这种流程改进能够每天为您节约数小时的开发时刻。我盯梢我的作业一个多月,对我来说,每天节约了 1-2 小时。

坦白地说,假如每周节约10个小时的开发时刻都不能压服您去测验,那么我以为任何办法都不能压服你。

其他渠道在做什么?

假如您只运用 Apple 渠道,您会惊奇地发现有好多渠道几十年前现已选用了热重载。无论您是编写 Node 仍是任何其他 JS 框架,都有一个运用热重载的设置。 Go 也提供了热重载(本博客运用了该特性)

另一个比如是谷歌的 Flutter 架构,从一开端就规划用于热重载。假如您与从事 Flutter 作业的工程师交谈,你会发现他们最喜欢 Flutter 开发者体会的一点便是能够实时编写他们的运用程序。当我为《纽约时报》写了一个拼字游戏时,我很喜欢它。

微软最近推出了 Visual Studio 2022,并为 .NET 和 规范 C++ 运用程序提供热重载,在曩昔的十年中,微软在开发东西和经历方面一直在大杀四方,所以这并不令人惊奇。

苹果生态系统怎么样?

早在 2014 年推出时,很多人都对 Swift Playgrounds 感到敬畏,由于它们答应咱们快速迭代并检查代码的成果,但它们并不能很好地作业,由于它存在崩溃、挂起等问题。不能支撑整个iPad环境。

在它们发布后不久,我启动了一个名为 Objective-C Playgrounds 的开源项目,它比官方 Playgrounds 运转得更快、更牢靠。我的主意是规划一个架构/作业流程,利用我现已运用了几年的 DyCI 代码注入东西,该东西现已由 Paul 制作。

自从 Swift Playgrounds 存在以来,现已曩昔了八年,而且它们变得更好了,但它们牢靠吗?人们是否在运用它们来推动开发?

以我的经历:并非如此。Playgrounds 在大型项目中往往不太牢靠或适用。

SwiftUI 出现了,它是一项了不得的技能(虽然仍然存在过错),它引入了与 Playgrounds 十分类似的 Swift Previews 的主意,它们有什么好处吗?

类似的故事,当它作业的时候是很好的,可是在更大的项目中,它的作业是不牢靠的,而且往往中止的次数比它们作业的次数多。假如你有任何过错,他们不会为你提供调试代码的能力,因而,选用的情况有限。

咱们需求等候 Apple 吗?

假如你重视我一段时刻,你就现已知道答案了,肯定不要。究竟,我的职业生涯是构建普通 Apple 解决方案无法解决的问题:从像 Sourcery 这样的言语扩展、像 Sourcery Pro 这样的 Xcode 改进,再到 LifetimeTracker 以及许多其他开源东西。

咱们能够利用我开端在 2014 Playgrounds 中运用的相同办法。我现已运用它十多年了,而且在数十个 Swift 项目中运用它并取得了巨大的成功!

许多年前,我从运用 DyCI 切换到 InjectionForXcode,经过利用 LLVM 互操作而不是任何 swizzling ,它的作用更好。它是一个彻底免费的开源东西,您能够在菜单栏中运转,它是由多产的工程师 John Holdsworth 创立的。你应该看看他的书 Swift Secrets。

我意识到 Playgrounds 的办法或许过于笨重,所以今天,我开源了。一个十分专注的名为 Inject 的微型库,与 InjectionForXcode 调配运用时,将使您的 Apple 开发愈加高效和愉快!

但不要只相信我的话。看看 Alexandra 和 Nate 的反应,在我将这个作业流程引入 The Browser Company 设置之前,他们现已十分精通了,这使得它愈加令人印象深刻。

Swift 中的热重载

Inject

这个小型库是彻底通用的,无论您运用 UIKitAppKit 仍是 SwiftUI,您都能够运用它。

您无需为出产运用程序增加条件或删去 Inject 代码。它变成了无操作内联代码,将在非调试版本中被编译过程剥离。您能够在每个视图中集成一次,并持续运用数年。

请参阅 GitHub repo 中关于装备项目的说明。现在让咱们来看看您有哪些作业流程选项。

作业流

SwiftUI

只需求两行字就能够使任何 SwiftUI 启用实时编程,而当您这样做时,您将拥有比运用 Swift Previews 更快的作业流程,一起能够运用实践的出产数据。

这是我的 Sourcery Pro 运用程序的示例,其中加载了我一切的实践数据和逻辑,使我能够即时快速迭代整个运用程序规划,而无需任何从头启动、从头加载或类似的事情。

看看这个开发作业流程有多快吧,告诉我你宁愿在我每次接触代码时等候Xcode的从头构建和从头布置。

UIKit / AppKit

咱们需求一种办法来整理规范命令式UI框架的代码注入阶段之间的状况。

我创立了 Host 的概念而且在这种情况下作业的很好。有两个:

- Inject.ViewHost
- Inject.ViewControllerHost

咱们怎么集成它?咱们把咱们想迭代的类包装在父级,因而咱们不修正要注入的类型,而是改动父级的调用站点。

例如,假如你有一个 SplitViewController ,它创立了 PaneA 和 PaneB ,而你想在PaneA 中迭代布局/逻辑代码,你就修正 SplitViewController 中的调用站点。

paneA = Inject.ViewHost(
  PaneAView(whatever: arguments, you: want)
)

这便是你需求做的一切改动。注入现在答应你更改 PaneAView 中的任何东西,除了它的初始化API。这些改变将当即反映在你的运用程序中。


一个更详细的比如?

  • 我下载了 Covid19 App

  • 增加 -Xlinker -interposableOther Linker Flags

  • 交换了一行 Covid19TabController.swift:L63

从这句:

let vc = TwitterViewController(title: Tab.twitter.name, usernames: Twitter.content)

替换为:

let vc = Inject.ViewControllerHost(TwitterViewController(title: Tab.twitter.name, usernames: Twitter.content))

现在,我能够在不从头启动运用程序的情况下迭代控制器规划。

这是怎么运作的呢?

Hosts 利用了自动闭包,因而每次您注入代码时,咱们都会运用与开端相同的参数创立您类型的新实例,从而答应您迭代任何代码、内存布局和其他一切内容。你唯一不能改动的是你的初始化 API。

Host 的改变不能彻底内联,所以这些类在 Release 构建中被删去。最简略的办法是做一个独自的提交,交换此单行代码,然后在作业流程的最终删去它。

逻辑注入怎么呢?

MVVM / MVC 这样的规范架构能够获得免费的逻辑注入,从头编译你的类,当办法从头执行时,你现已在运用新代码了。

假如像我相同,你喜欢 PointFree Composable Architecture,你或许想要注入 reducer 代码。 Vanilla TCA 不答应这样做,由于 reducer 代码是一个免费功用,不能直接用注入替换,但咱们在 The Browser Company 的分支 支撑它。

当我开端开端咨询 TBC 时,我想要的第一件事是将 InjectXcodeInjection 集成到咱们的作业流程中。公司管理层十分支撑。

假如您切换到咱们的 TCA 分支(咱们保持最新),你能够在 UI 和 TCA 层上运用 Inject

它有多牢靠?

没有什么是完美的,但我现已运用它十多年了。它比 Apple 技能(Playgrounds / Previews)牢靠得多。

假如您投入时刻学习它,它将为您和您的团队节约数千小时!

Demo 源码

在 GitHub 上获取项目

我正在参加技能社区创作者签约计划招募活动,点击链接报名投稿。