Tag: 故事板

在ObjC / Swift混合遗留项目中拆分情节提要

您如何将故事板拆分为多个较小的故事板? 那你为什么呢? 在本文中,我将告诉您为什么要这样做,一路遇到什么问题以及如何解决这些问题。 问题:大型情节提要使iOS开发人员陷入困境 随着FINN应用的发展,最近的故事板也不断发展。 使用情节提要意味着您将获得一些有用的功能,并且可以直观地了解应用程序的工作原理。 我说“可以”,因为不一定是这种情况。 另外,使用情节提要具有一些怪异之处,当多个开发人员在同一个项目上工作时,这些怪异之处并不总是被理解。 对情节提要的任何小的更改都可能意味着对情节提要的xml进行了几处更改。 除此之外,XCode只是因为打开文件而具有重新计算几个情节提要项的坐标的烦人趋势! 还有一个烦人的问题是,故事板越大,处理起来就越慢。 通常,我们至少要等待5秒钟才能打开文件,而且操作通常比较缓慢。 因此,iOS团队很久以前就决定将其拆分,但这项工作不一定容易。 还是小。 甚至有趣。 而且,Jira的任务还指出“当心示波器蠕变……”。 是的,它爬了起来。 FINN应用:一些历史 当前的FINN应用程序于2013年8月启动。在这三年中,该应用程序当然有所增长,在过去的一年左右的时间里,使用Swift添加了一些新功能,其中相当一部分是较旧的Objective-C类已在Swift中重写。 但是,大多数代码库仍然是Objective-C。 因此,Swift和Objective-C之间的互操作性至关重要。 快速查看文件数量可知,我们当前在项目中有171个Swift文件和349个.m文件(当然,这还不包括第三方代码)。 这些文件包含> 44,000行代码,其中包括30,000行Objective-C代码和> 14,000行Swift代码(不包括注释和空格)。 从小开始 我们决定从小处着手,首先将应用程序的名为“ Min FINN”(我的FINN)的部分提取到其自己的故事板上。 这是应用程序的一个相当自治的部分,尽管不是很完整。 该应用程序此部分中的大多数导航都在该功能的内部,但是从应用程序其他部分进入该功能的一些入口点。 某些导航是通过segue完成的,但是有多个位置可以直接通过情节提要实例化场景的视图控制器。 当然,这意味着这样的代码会在整个代码库中乱七八糟: 这样做有两个问题:1.引用“ self.storyboard”,这意味着只有在视图控制器与当前视图控制器位于同一个故事板上时,它才会起作用。2.它使用硬编码字符串来引用故事板标识符“ resultListViewController”,容易出错 我们需要更好的方法。 当我们开始时,这就是MainStoryboard_iPhone的样子: 是的,有点混乱,不一定超级可管理。 从概念上讲,它也不是很有用。 那么我们如何进行拆分呢? 有了XCode 7,我们有了一个不错的新功能-重构到情节提要…: 您只需选择要提取的所有场景,然后此重构功能都将为您创建一个新的情节提要,并将旧情节提要和新情节提要中的场景之间的所有连接连接起来。 但是,如果您支持iOS 8,并且正在使用关系查询(即来自UITabBarController的查询),则此方法将不起作用。 当然,这就是我们的情况。 但是,至少它为我们提供了将场景提取到新的故事板上的便捷捷径。 我们只是删除了得到的故事板参考。 此外,对于非关系情况,我们还是要靠自己。 玩弄两个故事板 好的,现在我们有了一个新的故事板,其中只有“ Min FINN”场景: 分散在代码周围的大多数“ […]

解开情节提要

本文通过使用基于代码的方法替换segues来帮助重构情节提要,该方法易于使用且省事。 让我们从大家都同意的事情开始。 故事板很棒 。 在创建出色的应用程序方面,它们确实提供了很多帮助。 但是……在管理应用程序流程和导航方面……嗯……它们可能不是。 关于情节提要的好事 通过使用Storyboard而不是独立的xib,我们可以享受很多好处。 我们可以直观地看到我们的应用程序流程。 我们可以从一个vc浏览到另一个vc,而无需编写任何代码。 我们可以享受UITableView中静态单元格的好处,否则是不可能的。 我们可以在UITableView中设计原型单元。 我们可以在多个情节提要中管理视图,然后通过情节提要引用将其连接起来,这些情节提要允许从情节提要中的一个vc导航到其他情节提要中的任何其他vc。 关于情节提要的坏事 但是,尽管有这些好处,但有时情节提要还是很糟糕: 从一个vc到它可以导航到的每个其他vc定义了硬编码的序列。 为了有条件地从一个vc到另一个vc,您需要为每个segue提供一个您需要在代码中知道的标识符,以便导航到正确的vc。 如果需要将数据从一个vc传递到另一个vc,则需要在vc中重写prepareForSegue (⚠️tight耦合)。 如果您有多个segue,则需要检查segue的标识符才能将正确的数据传递到正确的vc。 需要类型转换才能将数据分配给目标vc。 团队合作 我们团队的工作方式是,我们首先进行设计实现,然后进行api和业务逻辑集成。 因此,与情节提要相关的大部分工作都是在第一阶段完成的。 现在有时候我们需要添加在设计阶段未知的导航。 现在,我们需要在情节提要中添加适当的脚本和情节提要标识符。 这导致在集成阶段中情节提要的变化。 现在,有人可以说,更改情节提要以添加与添加Segue一样少的东西并不重要。 但请相信我。 尤其是当您在大型,不同的团队中工作时,故事板工程师和api /后端工程师的角色定义明确。 此外,我可以做任何避免情节提要冲突的事情,但是在这种情况下这是不可避免的。 在找到此问题的解决方案之后,经过几次尝试并寻找更有才华和经验的人的建议,我找到了一种最适合我的解决方案,肯定会帮助您摆脱情节提要的纠结。 走向解决方案 我有一个使用故事板脚本的原型应用程序。 我们将进行改进以最大程度地减少使用segues,并使用完全基于代码的技术从一个vc浏览到另一个vc。 如果您是一位经验丰富的开发人员,并且不想跟进,则可以在这里直接查看完成的项目。 但我鼓励您继续学习,以加深了解。 FoodOne(我们的原型项目) FoodOne是一个非常幼稚的食品订购应用程序。 它由登录和注册页面组成。 注册或登录后,您将进入可提供的饭菜清单。 您选择一餐以查看其详细信息。 如果需要,您可以通过点击屏幕上的订购按钮进行订购。 就是这样。 该项目包含两个情节提要。 主要 膳食 主板 主故事板包含登录和注册vc,以及故事板引用,用于在成功登录或注册后导航到餐单。 下图中可以看到,在主故事板上总共定义了4个segue。 膳食故事板 膳食情节提要有两个vcs。 一个用于餐单,另一个用于餐单。 在此故事板上仅定义了一个连击。 […]

iOS Segues提示和技巧

Segues是一种有用的导航模式,在iOS上用于在视图控制器之间进行转换。 这篇文章将展示如何在许多常见用例中有效地使用与segue相关的代码。 使用segues的一个主要好处是,从源视图控制器到目标视图控制器的过渡可以完全在情节提要中进行编码,并且不需要任何代码即可管理演示。 一个例外是需要自定义序列,例如自定义表示控制器时—详情请参见下文。 任务创建和准备 给定一个带有带有按钮的源视图控制器的情节提要,只需选择按钮并按住CTRL +拖动到目标视图控制器,即可创建到目标视图控制器的简单序列: 如果需要,可以在源视图控制器类中重写prepareForSegue方法,以配置目标视图控制器,如下所示: 假设我们的数据源是一个项目数组,并且我们想为目标视图控制器配置与所选单元格的indexPath相对应的项目。 由于segue是从表视图中的某个单元格触发的,因此prepareForSegue中的sender对象将是该单元格本身,并且我们可以将它的indexPath检索为tableView.indexPathForCell(cell)并使用它来引用我们的数据源数组。 例: 然后,我们需要像这样实现UIPopoverPresentationControllerDelegate的adaptivePresentationStyleForPresentationController方法: 摘要 利用情节提要板来定义应用程序的导航流程,并遵循以下规则将代码链接到您的任务上: 重写prepareForSegue方法以在显示目标视图控制器之前对其进行配置。 当通过点击按钮或单元格执行搜索时,请在源视图中直接挂钩到按钮/单元格。 有条件地执行segue时,将其挂接到源视图控制器,如果条件评估为true,则调用performSegueWithIdentifier 。 对于表视图和集合视图,使用indexPathForCell获取为prepareForSegue中的数据源建立索引所需的indexPath 。 选择Present as Popover选项,并实现adaptivePresentationStyleForPresentationController方法以返回UIModalPresentationStyle.None,以在iPhone 上将 segue呈现为弹出框 。 参考文献 Apple Docs:故事板Segues PSPDFKit博客:演示控制器和自适应演示 注意 :此故事 最初 于2016年1月25日 发布在我的博客 上。 有关更多此类故事,请 订阅我的邮件列表 。 如果您喜欢,请单击下面的so,以便其他人在中此看到此内容。

XCode故事板简介

我们也有Launchscreen.storyboard,但是现在我们只需要Main。 默认情况下,Main.storyboard包含显示该屏幕的屏幕,然后您首先启动模拟器。 故事板是一种文件类型,用于以图形方式使用界面。 您也可以通过代码进行接口。 情节提要是界面构建者的一种工作方式。 现在,您会看到IB的窗口。 故事板是一个XML文件。 如果转到Navigator-> Main.storyboard->右键单击-> Open As源代码中的文件,则可以看到XML代码。 您将看到XML代码。 场景/视图控制器/视图等。 通常,我们不会使用XML。 因此,让我们回到IB模式。 导航器-> Main.storyboard->右键单击->打开为界面生成器。 默认情况下,您会看到一个空白屏幕。 它是一个视图控制器。 iOS应用程序中的每个新屏幕都是一个视图控制器。 我现在想向SB添加其他组件。 我们需要去对象的图书馆。 您可以在右上角找到。 图标在圆圈内为正方形。 单击它之后,您将看到对象。 让我们跳过所有黄色对象。 它们用于创建新的屏幕,我们目前不需要它们。 您可以滚动列表,然后看到其他对象。 目前,您可以使用背景上没有正方形的所有内容。 带有正方形的对象用于容器。 您可以使用ImageView,TextView和“从容器查看”。 添加您喜欢的所有对象并运行模拟器。 如果添加任何容器,您将不会在模拟器中看到它。 您可以在窗口菜单中将模拟器视图从实际视图切换到仅屏幕视图。 确保要运行的设备(1)和Interface Builder视图相同。 只需添加我之前提到的任何对象,然后尝试运行您的应用程序即可。 这是您的第一个用户界面。

故事板不再。 制作(编码)自定义UIView

苹果在iOS 5上引入了分镜脚本,从那时起,它帮助许多开发人员创建了精美的应用程序并节省了大量时间,对吗? 它提供了很多很酷的东西,例如: 我们整个项目的概述,或者如果您决定使用多个情节提要文件,则仅提供少量功能。 因为界面文件(storyboard和xibs)简单易用,所以您可以更快地创建视图。 您可以预览正在创建的内容,而无需编译或运行项目。 和更多… 如果您是一个人或在一个小团队中工作,故事板应该可以正常工作,但是当您开始与更多的人从事同一项目或相同功能时,故事板会让人头疼。 为麻烦做准备! 并使其翻倍! 情节提要是XML文件。 如果右键单击它,然后选择“打开为源代码”,将显示以下内容: 我们需要选择要使用的UI组件。 我们将有一个UIImageView和两个UILabel 。 让我们创建一个新类并设置我们的组件 只需创建一个新文件并设置我们的组件即可。 在此示例中,我们创建了一个带有String参数的新init ,以将其作为标题添加到TopView。 要将这个视图添加到viewController中,我们需要创建一个TopView对象并将其添加到我们的子视图中。 现在想象一下我们可以创建多少个自定义UI组件,然后使其在项目中可重复使用。 查看代码并不难学习,并且对您的项目很有帮助。 试试看! 您可以在github上获得最终项目。 有关更多信息,请查看Thiago Lioy的此帖

如何使用IBDesignable可视化情节提要中的可重用xib

在Zenchef,我们使用情节提要来设计视图控制器并获得应用程序导航的概述。 但是,情节提要板不适用于您要多次使用的视图。 例如,您可能想在UIViewController,UITableViewCell或UICollectionViewCell中使用复杂的视图。 为了避免每次都设计视图,通常有两种解决方案 1.以编程方式设计视图 这样,您可以使视图IBDesignable并通过实现prepareForInterfaceBuilder来实现,当您包括该视图时,您将在情节提要中看到结果。 当视图使用CoreGraphics实现drawRect时,它既简单又好用。 但是,一旦获得许多子视图,这将变得不切实际。 编码自动布局约束可能会很痛苦,大小类甚至更大。 Interface Builder功能强大,我们希望尽可能多地使用它。 2.在Xib中设计视图 这样,您就可以享受Interface Builder的所有功能,包括自动布局,尺寸分类和特征收集,同时保持视图的可重用性。 但是,每次需要时,都必须加载xib并以编程方式将视图添加到视图层次结构中。 此外,您也无法从“实时视图”(Xcode 6中引入)中受益。 您不会在情节提要中看到您的xib,因为在此阶段,所有IBOutlet都为零。 它将无法呈现,并且视图调试器将给您以下错误: 展开Optional值时意外发现nil 3.替代 因此,这是在情节提要中包括和可视化xib的方法: 步骤1 —创建一个视图容器 我们需要创建一个实用程序类,其行为类似于一个称为XibView的容器。 我们的XibView将负责加载xib,并将我们的视图添加为其子视图。 它具有2个属性: contentView将是您在xib中创建的视图。 nibName是您的xib文件的标题。 我们希望稍后在情节提要中从身份检查器访问此字段。 @IBDesignable XibView类:UIView { var contentView:UIView? @IBInspectable var nibName:String? 在初始化时,该类将: 从其xib名称加载视图 添加具有自动调整大小掩码的子视图,以实现自动布局约束 覆盖func awakeFromNib(){ super.awakeFromNib() xibSetup() } func xibSetup(){ 守卫let view = loadViewFromNib()else {return} view.frame =界限 […]

为什么我停止在iOS项目中使用Storyboard和Xib

故事板可帮助我们简化创建iOS应用程序的UI。 拥有一个仅需几次单击和拖动的模拟应用程序,真的很棒,对吗? 我们甚至可以忘记导航,即每个应用程序使用的功能。 仅通过从一个屏幕到另一个屏幕的链接即可完成所有导航,如果转换很复杂,有时还可以使用自定义代码。 苹果正在继续改进Xcode的Interface Builder,以添加越来越多的功能来帮助开发人员简化其UI存根。 例如,我们现在可以预览不同屏幕尺寸的渲染。 我发现此功能非常有用。 当我们由一个小型团队(或一个人)开发一个小型应用程序时,所有这些好东西仍然是好的。 一旦应用程序扩展,团队就会成长,使用情节提要和.xib可能会成为噩梦。 让我们看看为什么。 如果我们没有足够强大的MacBook(Pro),则当我们不得不打开一个大的故事板时,Xcode可能会冻结您的计算机一段时间。 即使使用简单的情节提要板,我也花了大约10秒钟的时间在Xcode中打开它。 对于必须使用旧的MacMini或旧的MacBook开发的人来说,这可能会降低他们的工作性能。 当我们创建具有多个屏幕的大型应用程序时,情节提要文件可能会非常庞大​​。 概述和遵循应用程序流程并非易事。 如果有新的开发人员加入该项目,他将很难理解屏幕之间的逻辑和转换。 当然,我们仍然可以采用一种解决方法来创建使用情节提要面板场景,以将其分隔为多个情节提要面板,并避免使用大型情节提要。 但是,从中创建View / ViewController的实例时,开发人员应该照顾故事板名称或Xib名称。 使用情节提要/ xib时最不方便的是与.storyboard或.xib文件存在某些合并冲突。 当团队的开发人员在不同的存储库分支中同时编辑同一.xib或.storyboard,然后合并到主分支中时,就会发生这种情况。 情节提要和xib文件均为XML格式。 但是这些XML不是用户友好的。 Xml节点是自动生成的,这使我们很难知道xml中带有节点的UIView的引用。 每个节点还具有很多属性(用于指定高度,宽度,位置,颜色等)。 发生合并冲突时,如果合并不正确,将导致错误的结果,有时我们会破坏xml格式,因此无法打开.xib或.storyboard文件。 基本上,我们不会通过Storyboard / xib创建ViewController和View,而是将它们全部写入* ViewController.m / .swift或* View.m / swift。 在这篇文章中,我只会以Swift来编写代码,因为我更喜欢Swift而不是Objective-C,而且我相信你们也喜欢Swift。 假设我们要创建一个包含登录名和电子邮件文本字段以及用于处理登录的按钮的登录屏幕,如下所示: 我们将必须创建两个类: LoginView.swift和LoginViewController.swift 。 LoginView.swift继承了 UIView的子类,并且包含用于构建要在所有自动布局约束条件下显示的视图的代码。 LoginViewController.swift继承了 UIViewController的子类,并包含我们需要应用于这些元素的控件处理程序。 首先,让我们看看我们在LoginViewController.swift文件中要做的事情。 它不是那么复杂,对吗? 我们要做的就是重写loadView函数,以告知LoginViewController它需要加载并使用LoginView类中的自定义视图。 然后,ViewController应该控制此View内部的功能元素,以控制用户单击登录按钮或关闭按钮时的操作 。 在ViewController类中,我们不实现任何视图布局或视图的自动布局。 所有视图布局必须在View类内部完成。 这样,ViewController将变得更轻,更清洁。 […]

带有情节提要的高级动态自动布局

众所周知,iPhone的尺寸截然不同,因此开发人员可以应对。 为了创建看起来不错/复杂的场景,UI组件需要与其他组件保持动态约束。 让我给你一个我在工作中的设计师给我的情况。 我指的是常量部分正下方的“优先级”。 您可以直接使用优先级。 如果存在彼此相对应的约束,或者在同一UI组件上设置的约束多于约束,则优先级用于确定Xcode坚持的约束。 当然,选择的优先级更高。 在本期中,它可能不只是一个小尺寸的屏幕,因此我们将所有内容都放在滚动视图中作为第一步。 这是我如何设置动态自动布局的提示。 您要处理最坏的要求/限制,然后再转到理想的要求。 让我们看一下必须远离顶部的顶部图像视图。 它必须与顶部至少相距40,但最好为70。 因此,最糟糕的要求是它必须与顶部保持40的距离,因此我们将此约束设置为1000优先级,这是最高优先级,这样其他约束不会对其产生任何影响。 对于距离顶部70的位置,我们将赋予700优先级,这意味着在将所有约束设置为高于700的优先级之后,我们将转向该约束条件,看看是否需要设置。 现在我们完成了顶部图像视图部分。 有多容易? 我们不需要计算空白空间,不需要放置很多if条件,就可以设置约束。 让我们进入拒绝组视图。 由于当我们显示拒绝原因时,我们要相应地更改高度约束,而不是手动更改。 我们如何实现适合内容的自动高度限制? 为此,我们将使用内容抗压缩性优先级。 对于不熟悉内容抗压缩优先级的用户,这基本上是优先级,其中当将某个UI组件在垂直或水平方向上抑制为较小尺寸并且其抗压缩优先级高于对其进行压缩的约束时,UI不会被压缩。 如上所示,我们将拒绝标签的内容抗压缩优先级设置为1000,这意味着该标签在任何情况下都不会被压缩。 您可能要看的一件事是拒绝组视图和横幅视图之间的距离。 它的大小很大没有问题,但是当它很小时,它可能会与另一个重叠,因此我们需要为此设置约束。 彼此之间没有特定的距离,但它的设置方式是两个必须彼此分开。 这就是为什么它的优先级也是1000! 和田田! 都结束了。 是时候检查它是否适用于较小的尺寸,例如iPhone 4s。 如您所见,图像视图和顶部之间的距离是我们想要的40,其他UI组件的行为也与设计时一样,例如拒绝原因标签随内容占用而改变高度限制。 我们已经学习了如何将优先级用于复杂的约束关系。 这是关于哪个优先级更高,哪个对哪个优先级设置了约束。 即使我是程序设计UI的拥护者,但我还是使用Storyboard处理复杂场景的忠实粉丝。 试试看。 如此简单和直接会让您惊讶! 感谢您抽出宝贵时间阅读此博客。 如有任何疑问,请随时告诉我:)

Xcode大学—故事板和Segues快速入门

以任何设备查看 不久前,在情节提要中创建新场景时,我们将获得一个500×500的正方形框来表示我们的视图。 老实说-我喜欢它! 它足够抽象,可以构建通用布局,而无需不知不觉地仅针对一个屏幕大小进行设计。 困难的部分是使用iPad上的每个屏幕尺寸,不同方向和分屏进行测试。 今天,我们可以单击屏幕底部的“查看为”,并为每个设备和方向呈现布局,而无需构建和运行项目。 IBDesignable / IBDesignable 是否曾经创建过自定义视图,并且不得不修改一些代码,运行应用程序并转到视图可见的位置,以查看其外观? 真浪费时间。 使用IBDesignable属性,您的自定义视图将立即在情节提要中呈现! 使用IBInspectable ,您可以在属性检查器中为任何自定义UIView或UIViewController类显示属性。 查看Nate Cook撰写的有关NSHipster的快速指南。 何时不使用情节提要 我们证明情节提要很棒,但并不总是如此。 有些事情他们做不到。 例如: 没有一些技巧,就不可能重用自定义视图,因为没有场景就无法创建视图。 当前,我们必须使用一个nib文件。 对于在不同视图控制器中重用的表/集合视图单元格,同样适用。 Segues非常容易,但是对于链式转换来说效果不佳。 立即关闭并显示视图控制器时,由于转换在转换之前已完成,因此显示将失败(带有已记录的警告)。 结论 Tabs vs. Spaces阵营可能永远不会停止战斗,但这并不意味着我们无法做出自己的命运。 故事板,笔尖与代码阵营可以并存,并在一个大型的快乐项目中享受每个阵营的好处。 如果您有任何疑问,请随时与我联系,或者随时在Twitter上与我联系。 不要忘记查看我们的聚会-Swift Coders和Learn Swift LA。 制表符与空格 有用的资源 Marcin Krzyzanowski编写的情节提要代码生成器—该框架将为情节提要创建具体类型,而不是使用字符串标识符。 想要尝试一会儿。 在AdrienCognée的情节提要中使用IBDesignable和可重复使用的Nib文件-我做了非常相似的事情,以便能够在情节提要中呈现自定义视图。 这是“ hacky”,但非常有用。

iOS中的表单-第1部分

大家好! 这是我的第一篇中篇文章,非常感谢您提供反馈。 今天,我们将研究在Xcode Storyboard中使用Object引用。 由于我一直喜欢现实世界的用例,因此本文的大部分内容将研究如何使用这些Object引用实现Forms。 到本文结尾,目标是拥有可通过故事板进行配置的高度可重用的表单组件。 这也只是第1部分。在这一部分中,我们将构建一个简单的表单示例,在第二篇文章中,我们将研究一个更复杂的示例。 对象引用 好了,情节提要中的对象引用是什么? 您可能已经在Xcode的UI库中看到了Object引用(这是图1中显示的黄色小方块)。 早在iOS开发人员的早期,此对象曾用于Nib文件中的文件所有者引用。 如果那没有任何意义,请不要担心。 我们现在生活在更好的时代。 现在,从我所看到的来看,它今天使用不多。 我知道直到最近我才从未使用过它。 那怎么办呢? 图1.0的描述说明了一切。 这些对象可用于建模从NSObject类继承的任何对象。 您可以附加N个这些东西来在情节提要中查看控制器。 然后,您可以从默认的NSObject覆盖它们的类。 真的很棒! 我可以通过Storyboard将一堆依赖项附加到我的视图控制器。 然后,在视图控制器上设置IBOutlet ,以创建对这些对象的引用,情节提要将处理实例化所有这些对象。 现在您可能会认为这很酷,但是我不能没有出口就直接将这些依赖项添加到我的视图控制器中……当然可以。 但是,使用情节提要板的强大功能意味着也可以通过情节提要板配置这些对象的任何依赖关系。 情节提要将为我们处理所有这些对象的实例化,我们不必担心。 这些对象还可以通过IBOutlet引用视图上的元素。 接下来,我们将在实现表单时看到这将如何帮助我们。 情节提要中的表单对象 本节将逐步为我们的表单示例构建一个示例Xcode项目。 欢迎继续阅读,或者如果您想阅读,本文结尾处的Github上有一个指向该项目的链接。 让我们从简单的示例开始。 图2具有我们表单的情节提要配置。 有两个视图控制器,一个带有一个可导航到第二个视图控制器的按钮,这些按钮全部嵌入在导航控制器中。 这将使我们在第2部分的稍后部分中创建更多链接。 第二个视图控制器包含我们的表单。 这种形式只是三个标签和三个文本字段,它们都嵌入在UIStackView中 。 底部还有一个提交按钮,将打印出表单的值。 好的。 让我们开始编码。 首先,在Xcode项目中创建一个名为Forms的新组。 然后创建两个名为Form.swift和FormControl.swift的新文件,如图3所示。 我们将从FormControl.swift文件开始。 该文件将包含以下协议: @objc 协议 FormControl { var键:字符串? { 得到 } var文字:字串? […]