Swift的游乐场驱动开发

作为移动开发人员,我们的使命是为最终用户提供最佳的用户体验,通过专用的应用程序使他们的生活更有趣,更轻松。 任务之一是确保用户看到的用户界面外观良好且正确。 大多数时候,我们可以说应用程序是数据的美化手段。 我们通常从后端获取JSON数据,将其解析为模型,然后使用UIView (主要是UITableViewUICollectionView

对于iOS,我们需要根据设计不断调整用户界面,使其适合小型手持设备。 该过程涉及我们更改代码,编译,等待,检查,然后更改代码等等。…诸如Flawless App之类的工具有助于轻松比较iOS应用程序和Sketch设计的结果。 但是真正的麻烦在于编译部分,这花费了很多时间,而对于Swift来说更糟。 它使我们进行快速迭代的效率降低。 看起来编译器在假装编译时正在秘密开采比特币mining

如果您使用React,您将知道它只是状态UI = f(state). UI表示UI = f(state). 您将获得一些数据,并构建一个UI来表示它。 React具有热重载器和Storybook,这使得执行UI迭代非常快。 您进行了一些更改,然后立即看到结果。 您还将获得每种状态所有可能的UI的完整概述。 您知道在iOS中想要相同的东西!

除了在WWDC 2014中引入Swift之外,苹果还引入了Playground,据说这是“探索Swift编程语言的一种新颖的创新方式”。

一开始我并不十分相信,而且我看到很多抱怨Playground运行缓慢或反应迟钝的抱怨。 但是看到Kickstarter iOS应用程序使用Playground加快了样式和开发过程的速度后,我印象深刻。 因此,我开始在某些应用程序中成功使用它。 它不会像React Native或Injection App一样立即重新渲染,但希望多年来会更好。

或至少它取决于开发社区。 Playground的场景是我们一次只能设置一个屏幕或组件的样式。 这迫使我们仔细考虑依赖关系,因此我可以导入一个特定的屏幕并在Playground中对其进行迭代。

Xcode 9允许在Playground中导入自定义框架,只要该框架与Playground在同一工作空间中即可。 我们可以使用Carthage获取自定义框架并进行构建。 但是,如果我们使用CocoaPods,那么它也是可行的。

如果将Playground添加为嵌套项目,则Playground无法访问同一工作空间或父项目中的代码。 为此,您需要创建一个框架并添加要在Playground中使用的源文件。 我们称之为应用程序框架。

本文的演示是一个使用CocoaPods管理依赖项的iOS项目。 在撰写本文时,它是Xcode 9.3和Swift 4.1。

让我们逐步完成使Playground与使用CocoaPods的项目一起使用的步骤。 还有一些好的做法。

步骤1:添加广告连播

我主要使用CocoaPods管理依赖项。 在某些屏幕中,肯定会涉及到一些吊舱。 因此,要使我们的应用程序框架正常工作,它需要与一些吊舱链接。

创建一个新项目,我们称它为UsingPlayground 。 该应用程序显示某种纸屑颗粒🎊。 有很多选项可以调整这些粒子的显示方式,我选择Playground对其进行迭代。

对于此演示,我们将使用CocoaPods来获取一个名为Cheers的依赖项,因为我们想要一些有趣的东西。 如果您想祝贺用户取得一些成就, Cheers可以帮助展示精美的五彩纸屑效果。

使用UsingPlayground作为应用程序目标来创建Podfile

现在,将要测试的源文件添加到此框架中。 现在,只需检查文件ViewController.swift并将其添加到AppFramework目标。

对于这个简单的项目,只有一个ViewController.swift 。 如果此文件引用了其他文件中的代码,则也需要将相关文件添加到AppFramework目标。 这就是您应该如何谨慎依赖项的方法。

步骤4:将文件添加到AppFramework

iOS中的ViewController主要位于UI层中,因此它应该仅获取解析的数据并使用UI组件进行渲染。 如果您有逻辑,可能涉及到缓存,网络等其他部分,这需要您向AppFramework添加更多文件。 小型,独立的框架更为合理,可以使我们快速迭代。

操场上没有魔术。 您每次更改代码时都需要编译AppFramework,否则更改将不会反映在您的Playground中。 如果您不介意编译时间过长,可以将所有文件添加到AppFramework 。 简单地扩展组文件夹,选择文件并将其添加到目标需要很长时间。 更不用说如果您同时选择文件夹和文件,将无法将它们添加到目标中。 您只能将文件添加到目标。

一种更快的方法是转到AppFramework目标Build Phase下的Compile Sources 。 在这里,所有文件都会自动为您展开,您只需选择它们并点击Add

步骤5:公开

Swift类型和方法默认是内部的。 因此,为了使它们在操场上可见,我们需要将它们声明为公共。 随时阅读有关Swift中访问级别的更多信息:

开放访问公共访问使实体可以在其定义模块的任何源文件中使用,也可以在导入定义模块的另一个模块的源文件中使用。 指定框架的公共接口时,通常使用开放访问或公共访问。

步骤8:享受

现在是最后一步:编写一些代码。 在这里,我们需要在操场上导入AppFrameworkCheers 。 我们需要导入Playground中使用的所有pod,就像我们在应用程序项目中所做的一样。

Playground最适合独立测试我们的框架或我们的应用程序。 选择MyPlayground并输入以下代码。 在这里,我们告诉liveView渲染我们的ViewController:

Xcode的底部面板中有一个按钮。 在这里,您可以在“ Automatically Run和“ Manual Run行为之间进行切换。 您可以自己停止和启动Playground。 整洁🤘

您的应用可能需要处理一些预构建的二进制Pod,以通过标头公开API。 在某些应用程序中,我将BuddyBuildSDK用于崩溃报告。 如果看一下它的podspec,您会发现它使用了一个称为BuddyBuildSDK.h的公共头BuddyBuildSDK.h 。 在我们的应用程序项目中,CocoaPods对此进行了很好的管理。 您需要做的就是通过Bridging-Header.h在应用程序目标中导入标头

如果需要查看如何使用桥接标头,请阅读同一项目中的Swift和Objective-C。

步骤1:导入桥接标题

但是我们的AppFramework目标将很难找到BuddyBuildSDK.h

不支持将桥接标头与框架目标一起使用

解决方案是在AppFramework.h引用该Bridging-Header.h

步骤2:公开标头

完成上述操作后,您将获得

在框架模块中包含非模块化头

为此,您需要将Bridging-Header.h添加到框架,并将其声明为public 。 对SO的搜索显示此报价

公开:该接口已最终确定,可供产品的客户使用。 产品中包含公共标头,作为可读源代码,没有任何限制。

专用:该接口不适合您的客户使用,或处于开发的早期阶段。 产品中包含一个专用标头,但标记为“专用”。 因此,这些符号对所有客户端都是可见的,但是客户端应了解不应使用它们。

项目:该接口仅供当前项目中的实现文件使用。 除对象代码外,项目标头不包含在目标中。 这些符号对客户完全不可见,只有您自己可见。

因此,选择Bridging-Header.h并将其添加到AppFramework并将可见性设置为public:

如果转到AppFramework Build Phases ,您将在此处看到2个头文件。

现在,选择方案AppFramework并单击Build ,它将可以编译而没有任何错误。

我们的屏幕不仅仅包含来自其他窗格的视图。 通常,我们会显示捆绑销售商品中的文字和图像。 让我们将Iron Man图像添加到Asset CatalogLocalizable.stringsResourceViewController包含一个UIImageView和一个UILabel.

让我们看看我们的游乐场是否可以识别这些资产。 在MyPlayground创建一个名为Resource的新页面,然后键入以下内容

资源文件夹

实际上,每个“ Playground Page都有一个“ Resources文件夹,我们可以在其中放置该特定页面可以看到的资源文件。 但是在这里,我们需要访问应用程序包中的资源。

主捆绑

访问图像和本地化字符串时,如果您未指定bundle ,则运行的应用程序默认情况下将在主包中获取资源。 这是更多信息,查找和打开捆绑包。

在找到资源之前,必须首先指定包含该资源的捆绑软件。 Bundle类有很多构造函数,但最常用的是main 。 主包代表包含当前执行代码的包目录。 因此,对于应用程序,主捆绑对象使您可以访问应用程序随附的资源。

如果您的应用直接与插件,框架或其他捆绑内容进行交互,则可以使用此类的其他方法来创建适当的捆绑对象。

 // Get the app's main bundle 
let mainBundle = Bundle.main

// Get the bundle containing the specified private class.
let myBundle = Bundle(for: NSClassFromString("MyPrivateClass")!)

步骤1:将资源添加到AppFramework目标

因此,首先,我们需要将资源文件添加到AppFramework目标中。 选择Asset CatalogLocalizable.strings并将它们添加到我们的AppFramework目标中。

步骤2:指定捆绑

如果我们未指定bundle,则默认使用mainBundle 。 在执行的Playground的上下文中, mainBundle引用其“ Resources文件夹。 但是我们希望Playground能够访问AppFramework中的资源,因此我们需要对Bundle.nit(for:)AppFramework的类一起AppFramework以引用AppFramework中的包。 该类也可以是ResourceViewController因为它也已添加到AppFramework目标中。

ResourceViewController的代码更改为

那自定义字体呢?

我们需要注册字体才能使用。 代替使用plist中Fonts provided by application密钥Fonts provided by application ,我们可以使用CTFontManagerRegisterFontsForURL注册自定义字体。 这很方便,因为字体也可以在Playground中动态注册。

下载名为Avengeance的免费字体,并将此字体添加到我们的app和AppFramework目标中。

ResourceViewController添加代码以指定字体,记住要重新编译AppFramework :

iOS 8引入了TraitCollection,它定义了尺寸类别,比例和用户界面习惯用法,从而简化了设备描述。 kickstarter-ios项目具有方便的实用程序,可以准备UIViewController以便在不同特性下在Playground中使用。 参见playgroundController:

而AppEnvironment,就像一个堆栈,用于更改依赖关系和应用程序属性,例如捆绑软件,语言环境和语言。 查看有关“注册”屏幕的一个示例:

使用Playground时可能会出现一些错误。 其中有些是因为您的代码,有些是由于配置框架的方式。 对我来说,升级到CocoaPods 1.5.0之后,我得到了:

 错误:无法查找符号:__ T06Cheers9CheerViewCMa__T012AppFramework14ViewControllerCMa__T06Cheers8ParticleO13ConfettiShapeON__T06Cheers6ConfigVN 

符号查找问题意味着Playground无法找到您的代码。 可能是因为您的课程没有公开,或者您忘记将文件添加到AppFramework目标。 或引用的吊舱在AppFramework Framework search path不可见,…

1.5.0版提供了静态库支持,并且在模块化头文件中进行了更改。 同时,该演示切换回CocoaPods 1.4.0 ,您可以看一下UsingPlayground演示。

在终端中,键入bundler init以生成Gemfile 。 为cocoapods gem指定1.4.0:

现在运行bundler exec pod installCocoaPods 1.4.0运行pod命令。 该问题应解决。

Swift Playground还支持macOStvOS 。 如果您想了解更多信息,这里有一些有趣的链接

  • Playground驱动的开发Brandon Williams的演示和kickstarter-ios项目激发了Playground如何在生产应用程序中使用的灵感。 另外,在objc.io上有关游乐场驱动开发的讨论确实很好。
  • PointFree:该网站是在Playground的帮助下完成的。 您只需阅读代码及其项目结构,即可学到很多东西。
  • 使用Swift可视化算法:Playground也可以很好地原型化和可视化您的想法。
  • 我的朋友费利佩(Felipe)在演讲中还写了他如何在工作中成功使用Playground的方法:如何避免沙眼
  • 另外,如果您想惊讶,翁贝托·莱蒙迪(Umberto Raimondi)会列出一系列很棒的游乐场。