Tag: 迅捷

简单文字动作扩展Swift 3

之所以如此,是因为我想为自己的一个应用构建共享扩展。 我碰巧也遇到了动作扩展,所以我决定首先在这些扩展上写一个不错的博客,然后再写一个关于共享扩展的博客。 动作扩展与共享扩展非常相似,因为它基本上是自己的小应用程序,可让您修改文本或图像等不同的数据。 例如,消除图片中的红眼,使文本更大且更易于阅读。 就创建这些而言,确实并不难。 我将其称为“添加时间段”,当单击活动视图控制器按钮时,它将出现。 第一步是在项目中实际创建操作扩展。 为此,请转到文件->新建->目标,然后选择操作扩展: 完成此操作后,您将在您的操作扩展程序的应用程序中看到一个新文件夹,其中包含其自己的故事板文件和视图控制器。 由于我希望该应用程序只能接受文本,因此我们必须进入info.plist文件,并将我们的NSExtensionActivationRule插入字典,然后将NSExtensionActivationSupportsText添加为值为YES的布尔类型。 您还可以在plist中更改Bundle显示名称。 这样做的原因是,捆绑包名称实际上是面向用户的名称,这意味着它将出现在活动视图控制器中。 首次创建动作扩展时,您会看到它提供了默认实现,在情节提要中带有imageView,并且在视图控制器中提供了能够处理图像的代码。 在我们的例子中,我们可以使用相同的代码,但是将其调整为处理文本而不是图像..最后,视图控制器将如下所示: 我不会在这里遍历所有代码,但是扩展的工作方式是它们与NSExtensionItems一起返回,我们要做的就是根据我们在系统中设置的内容检查它是否为kUTTypeText类型为String。 plist文件。 在此示例中,您可以看到我通过在结尾处简单地添加句点来更改字符串。 完好的功能只是将字符串转换回NSExtensionItem,然后返回给应用程序。 但是,这仅在您使用扩展程序的应用程序具有接受这些扩展程序的代码的情况下才有效。 我不确定应用接受这些应用的普遍性,但是到目前为止,这似乎并不是很标准的事情。 话虽如此,我建立了一个便笺应用程序,就像默认的iPhone便笺应用程序一样,并用代码编写了接受此操作扩展的代码。 为了使应用程序能够处理操作扩展,您需要在活动视图控制器上调用completionWithItemsHandler。 我在下面的Notes应用程序中包含了整个onShare函数的代码,该代码创建了活动视图控制器,然后创建了接受操作扩展的代码。

方法的系谱

如果您曾经记下几行代码,那么很可能已经使用了一种方法。 方法使我们的生活更轻松。 可以使用.sorted()来组织一个数组,而不是实现一个永无休止的if语句来按字母顺序排列列表。 而不是使用自己的数字,.count()方法将为您提供元素数量! Swift中提供了许多方法,我们常常认为它们是理所当然的。 但是它们都是从哪里来的? 事实是,所有这些方法都是通过类和结构创建我们自己的方法的方式形成的! 每次我们打开新的Project或Playground文件时,xCode编译器都会导入一组类和规则,这些类和规则确定代码的行为方式。 但是,这仍然无法回答这些方法和类来自何处的问题,因此要找出答案,让我们看一下单个方法并将其沿袭追溯到源头。 .count()函数呢? Apple的文档将.count()描述为“返回多值列表中的条目数。”有见地! 但是,通过在操场上通过Option +单击.count()方法,我们可以获得更多信息。 线索! 显然.count()包含一个{get}语句。 剧情变厚了…… 在参考指南中窥探一下之后,结果发现.count()最初来自名为ABMultiValue的类: 此外,“多值列表中的每个值必须具有相同的类型,并且必须具有关联的预定义或用户定义的标签,以及唯一的标识符……此类的实例是不可变的,有关操纵多值内容的方法,请参阅ABMultableMultiValue。清单。” 苹果开发人员似乎创建了一对专门用于容纳Array类型的类:一个用于更改Array(使用.insert(newElement :, at :)和.remove(at :)之类的方法)和一个用于分析Array类型的类。不可变数组(包含.count()之类的方法)。 实际上,ABMutableMultiValue实际上是继承自ABMultiValue,从而使其成为子类。 然而,这种揭示仅引起了另一个问题-这个ABMultiValue类从何而来? 通过跟踪其对源的继承,所有这些类最终都继承自NSObject:Apple所有事物的基础。 总而言之,Apple开发人员使用NSObject创建各种类来处理不同的属性,包括ABMultiValue来容纳可能具有多个值的属性。 当然,每次需要计数数组时,我们总是可以编写自己的代码: 但是似乎我们必须为每种类型的[String],[Int],[Double]和[etc]编写该代码。 取而代之的是,内置方法使我们能够利用函数而无需自行初始化它们。 在过去的编码天中,必须将所有不同的类导入其项目中才能访问方法。 这将包括Foundation,UIKit,还包括在用户的特定项目中创建的每个类。 导入可能占用数十行,并且可能导致易于出错的代码以及令人头疼的问题。 对我们来说幸运的是,xCode实际上在Swift标准库中内置了许多这些Objective-C / NSObject方法,因此在许多情况下,不需要导入框架! 尽管xCode为我们提供了许多一次性方法,但它们的捆绑式包装仍然有些不足。 如果您有一个经常调用的函数,或者根本不想重写它,那么实际上可以构建自己的个性化类并在需要时将其导入! 有关更多信息,请参见此处。 目前,我们感谢Swift标准库为我们提供了许多便捷的方法。

活性可可介绍

ReactiveCocoa是一个框架,允许您实施反应性功能编程。 响应式功能编程是一种编码方法,可确保应用程序某一部分的更改自动反映在整个应用程序中。 因此,让我们假设您具有三个属性A,B和C,并且A = B +C。如果B或C发生变化,那么A也会做出反应并且也会发生变化。 用ReactiveCocoa来解释,功能性反应式编程的基本概念是我们告诉代码做什么而不告诉它如何做。 核心组成 信号会随时间发送值,直到它完成或出错为止。 将每个变量包装在MutableProperty中,可以确保每个变量都有其自己的信号,该信号在值更改时将触发,而不是为模型中的每个变量提供信号和观察者。 ReactiveCocoa具有某些内置功能,可让您转换信号。 在上面的示例中,我正在转换来自初始输入的信号,并使用map函数将信号值的每个字母大写。 映射运算符使用新的映射值生成一个新信号。 也可以订阅信号以产生副作用。 在下面的示例中,按下了SubmitButton并发送了一个信号。 在这种情况下,信号的副作用是通过将用户的用户名值发送到两个位置来设置两个标签:dressViewController的标题和收藏夹视图中的标签。 2. 观察者代表观察信号的物体。 创建信号时将创建观察者对象。 信号具有与它们关联的某些事件类型,您可以在观察信号时调用它们: 值:返回与信号关联的实际值 失败:携带Erro​​rType并在发送时导致信号停止 已完成:导致信号停止,但不发送错误事件 中断:自动发生并停止信号 每次在信号上建立观察时,都会创建一个Disposable对象。 在此对象上使用dispose方法可删除该特定观察值。 如果没有其他可观察的信号,则该信号会随着中断事件而停止。 3. 信号产生器创建的信号可以产生Value类型的值和/或因Error类型的错误而失败。 当事件具有特定的开始和结束时,信号产生很有用。 具体来说,信号产生器推迟事件的执行,直到调用start()为止。 例如,信号产生器在发出网络请求时是适用的,因为它有一个设定的开始和一个设定的结束。 您不想持续拨打网络电话。 4. 绑定允许您说“每当此变量更新时,请确保此属性更新为其值。”此代码非常简单。 在信号中,您输入“ <〜”以表示它正在绑定。 使用此绑定信号更新的标签不是UILabel类型,而是BindableLabel类型。 从下面的代码中可以看到,BindableLabel的行为与UILabel完全相同,因为您可以使用格式化UILabel的相同方式对其进行格式化。 一个区别是,一旦信号值更改,文本将立即更新。 查看ReactiveCocoa的github,以获取有关通过此出色框架可使用的所有强大功能的更多详细信息。 一如既往,快乐的编码!! 🙂

升级到Swift 3

它在这里! XCode 8已经发布,未来就在眼前! 好的,所以也许我反应过度,但是我们对此版本感到非常兴奋! 因此,大约三周前,我们面临着将iOS应用程序升级到Swift 3的早期挑战。 这就是我们所看到的。 通常,XCode会尽最大努力为您提供帮助。 但是,与任何升级/迁移一样,它无法解决所有问题-并且会在开始之前警告您有关此问题的详细信息(因为它与您的独特系统有关)。 首先-当然,在执行此步骤或任何与此相关的升级之前,请确保已完成所有其他更改,以便在出现问题时可以轻松地从中恢复。 尽管您必须在此过程中密切注意,但许多步骤还是非常重复或相似的。 一旦有了正确的心态,您甚至可以在其中找到一些快乐。 更不用说您可以进行的所有重构! 告诉你我们很兴奋。 因此,Apple为您提供了一个很好的参考资料,以使此过渡尽可能顺利。 但是从我们的试验中,这里有更多技巧。 确保您正在使用的所有库都支持Swift 3.0。 即使大多数流行的都进行了过渡,但仍有可能仍在进行中。 在Chromatic FM中,我们正在使用CocoaPods,并且要尽早进行迁移,我们需要修改Podfile使其指向未发布的分支。 您可以转到库的GitHub页面并检查那里的分支swift-3分支很可能在那里。 如果没有,那么-如果可能的话,就应该开始-为开源社区做出贡献是一件很棒的事! 无论如何,这里是指向不同分支的重要资源。 您的Podfile如下所示: pod ‘Alamofire’, :git => ‘https://github.com/Alamofire/Alamofire.git’, :branch => ‘dev’ 分支发布后,您应该切换到更新的版本。 迁移之前,请确保已提交与您无关的更改,并且项目状态为干净。 如果您的项目不受源代码管理,则至少需要在本地启动存储库。 Git是免费的,可以在这里找到。 在迁移期间,请尝试注意项目中的所有功能。 有时,迁移器不会自动尝试为您修复它们,但是存在的风险是,仍可以更改命名。 Swift为第一个参数添加了一致的标签,因此您可以更改方法名称,使其更短,更精确。 例: func foo(bar: Int) => func foo(_ bar: Int) 默认情况下,闭包现在不转义。 这是发生什么情况以及原因的详细说明。 如果您的封口@escaping了身体,请确保已将其称为@escaping 。 酷,对!! 并祝大家好运! […]

中央中央调度(GCD)第一部分

众所周知,如果没有并发编程或多个CPU,愚蠢的计算机一次不能完成一项任务 点击此处获取示例应用 介绍 : 并发在编程语言中是一个巨大的话题,并且有点低级。 在本文中,我将讨论并行编程。 有很多用于并发的API.Apple发布了两个用于并发编程NSOperation和Dispatch Queue的低标签API。我将介绍Grand Canter Dispatch(GCD),并探讨我们为什么需要它以及如何使用Swift来实现它,并希望您能精通在这个API上..所以,让我们一起摇滚吧.. 那么为什么我们需要并发: 我们都知道计算机(单核)不能一次执行多任务。但是在计算中,多任务是必不可少的。因此,为了解决这个问题,发明了并发概念。并发是一次执行多任务的方式。 在高度上:考虑我们有一个应用程序,它一次有两个任务,一个是从网络下载数据,另一个是更新UI。两个任务都需要同时执行。如果下载(网络请求)需要一些时间,例如30此时用户界面将停止更新。并且应用程序将冻结甚至被压碎。从用户角度来看,它的作用各不相同。没有用户会再次使用此应用程序。 我们需要并发编程。 所以 在深入探讨并发之前,我们需要回顾一些定义,这将有助于我们进一步了解: 任务可以串行或同时执行两种方式 串行:任务可以一个接一个地执行。一个任务在其上一个任务完成时开始启动,例如FIFO(先入先出)。 我们可以举一个例子,例如电影院售票柜台。 如果有一个柜台,所有顾客都排队。 它是一个串行队列。当一位顾客购买票时,他将不在排队,下一位顾客将来取票。 它是一个串行队列。 并发: 并发只是一个概念,它可以同时运行多个任务,这可以在单核CPU或多核CPU中发生。在单核CPU中,它是通过时间分片来实现的。一个线程先执行上下文切换,然后再运行另一个线程线程或多核CPU通过并行执行多个线程。 并发是两种类型: 1,并发无并行 2并行并行 线程: 线程是进程的子单元,换句话说,线程是由操作系统调度程序独立调度的任务组。 Queue列: 队列是按先进先出(FIFO)的顺序管理对象的数据结构。在我们的示例电影票客户线上是队列。 为什么我们需要并发? 由于一些非常重要的原因,我们需要并发: 始终响应UI :在任何iOS应用程序首次启动时,默认情况下都会运行一个主队列。主队列可以更新用户界面。因此,我们需要使此队列仅用于UI和后台队列中的其他繁重任务。因此,此处进行并行编程需要解决这个问题。 利用iOS设备:如今,iOS设备是多核处理器,通过并发编程,我们可以并行使用多核处理器。 释放到主队列 大坎特派遣(GCD): 因此,我们已经为并行编程涵盖了足够的主题.Apple有两个用于并行编程的API.NSOperation和GCD。最常用的是GCD(Grand Canter Dispatch)。我们可以通过此API在iOS和MacOS上管理多线程。同步和异步任务队列。 GCD有调度队列,用于按FIFO顺序一个接一个地管理所有队列。GCD提供两种类型的队列,分别是串行队列和并发队列。这两个队列可以同步运行,也可以异步运行。我们将在一段时间后讨论。 串行队列: 串行队列可确保在任何给定时间仅运行一项任务。 GCD控制执行时间。 我们不知道任务何时开始并最终由调度队列管理。 在此图中,所有正在运行的任务都是按一个接一个的顺序执行的任务1比tast 2完成tn thn任务3启动等等… 并发队列: 并发队列一次运行多个任务。 所有任务都是按顺序添加的,但我们不知道什么时候全部完成或一次要执行多少任务都由系统管理。 如图所示,任务1开始并且这次没有任务在运行,但是任务1和任务2在同一时间启动,但是任务1在任务2之前完成了,所以并发队列我们不知道任务什么时候完成或如何完成我们将花费很多时间,我们只是知道任务将按照我们的订购方式运行。 它的依赖于调度到多个任务的队列将在不同的内核上运行或通过上下文切换发生。但是通常,如果内核可用而不是在内核上发生,则通常使用上下文切换。 GCD提供了三种主要的队列类型: […]

Swift的甜蜜点滴:Dispatch框架(iOS 10 +)

iOS SDK具有NSOperation和NSOprerationQueue类,它们是用于异步处理的强大类。 苹果公司推出了Grand Central Dispatch,这是另一种执行多任务处理的高级方法。 本文介绍了快速的Dispatch框架。 原始的GCD库像C库一样使用。 例如,通过调用函数并使用诸如dispatch_queue_create,dispatch_semaphore_create等结构。不幸的是,这可能会排斥某些开发人员或迫使他们编写包装器。 就我而言,我必须开发自己的包装器。 希望iOS10附带的新Dispatch框架将所有GCD功能封装在类中。 现在,它更易于使用,代码也更加简洁。 没有任何不使用它的借口:)。 让我们从Dispatch框架的概述开始 总览 Dispatch框架由用于编写并发代码的类组成。 它支持iOS,macOS,tvOS和watchOS。 在GCD中要理解的主要概念是“ 调度队列 ”。 它是通过块或DispatchWorkItems提交的任务的容器。 调度队列中的任务称为工作项 。 分派队列中的工作项按FIFO顺序拉出。 分派队列可以是串行的,也可以是并发的。 串行队列按顺序依次执行其工作项。 并发队列按FIFO顺序对工作项进行排队,并一次同时运行它们。 在并发调度队列中,我们无法预测工作项的完成顺序。 调度框架允许操纵系统提供的队列: 主队列允许将工作项提交到主线程(或UI线程) 具有不同服务质量的全局并发队列。 DispatchQueue类封装了分派队列概念。 DispatchWorkItem类封装了调度工作项概念。 让我们练习一些DispatchQueue函数。 调度队列 在此示例中,我们在全局队列上同时执行两个循环。 .global()函数返回默认的全局队列。 异步功能意味着执行流程不会等待块完成。 如果要等待块完成,请使用sync()方法。 同步和异步方法都采用不同的参数,最常见的一种是传递一个块。 在这里,我们在不同的QoS队列上执行这些块: 服务质量(QoS)限定了优先级,并有助于系统优化其性能。 从高优先级到低优先级有5种QoS类别排序: 用户互动:这是与主要主题相对应的类。 用户启动的:用户触发的操作不必在主线程上运行。 它等效于DISPATCH_QUEUE_PRIORITY_HIGH。 默认 :默认QoS。 它等效于DISPATCH_QUEUE_PRIORITY_DEFAULT。 实用程序 :用于依赖于系统资源(例如文件和网络I / O)的调度项目。 它等效于DISPATCH_QUEUE_PRIORITY_LOW。 背景 :用于优先级较低的任务。 […]

快速枚举的实用案例-第2部分

在本文的第1部分中,我们已经看到了如何将枚举用作表视图的数据源。 如果您碰巧错过了第1部分,请检查一下。 如前所述,在这一部分中,我将展示网络堆栈中enum的另一个高级用例,我们将使用以下功能。 泛型 关联值 网络堆栈的组件: 以下是支持基本get,post请求的任何网络堆栈的组件。 基本网址 每个端点相对于基本网址的Api路径 请求类型(Http方法的类型) 网路错误 api响应 最后,一个处理所有网络请求的类(我们将其称为RequestManager)。 让我们看看如何实现上述每个组件。 基本网址: 我们定义了一个相对于所有其他api端点相对的基本url字符串,并将其包装在一个结构中。 struct BaseURL { 静态让url =“ https://example.com:7979/mobile-app/” } Api路径: 要实现Api端点,我们可以根据需要以两种方式使用枚举。 在api端点只是静态字符串路径的简单情况下,我们可以使用基于字符串的枚举,如下所示。 枚举ApiPath:String { 案例书=“书籍/全部书籍” 案例类别=“书籍/类别” } 但是,当我们需要基于用户输入添加动态路径参数时,这将不起作用。 例如,我们可能想根据用户选择的类别列出书籍,并且api端点如下所示。 case booksForCategory =“书籍/类别/ 5” 由于此类别ID将随用户选择而变化,因此我们可以包含一个具有用户所选类别ID的变量,然后使用字符串插值将其添加到api路径。 case booksForCategory =“书籍/类别/ \(类别)” 为了使上面的语句真正起作用,我们需要将类别变量注入枚举实例。 因此,我们将在swift enum🙌中使用关联的值。 但是有一个陷阱,如果尝试将关联值添加到枚举,则编译器会抱怨说不允许其同时具有关联值和字符串原始值。 因此,正如我在第1部分中解释的那样,我们将使该枚举符合CustomStringConvertible协议。 现在我们也可以拥有关联的值! 代码如下。 枚举ApiPath:CustomStringConvertible { 案例书 案例类别 案例书ForCategory(字符串) //符合CustomStringConvertible协议 […]

iOS开发案例:Thiago Holanda和Swift Evolution App

您如何以及何时开始为iOS开发的? 您好,首先,感谢Thiago Lioy邀请我参加第一期iOS Dev Stories。 很荣幸能多介绍一下我作为iOS开发人员的故事,该故事始于一个遥远的银河系,运… 我们在谈论发展,而不是星球大战! 我作为程序员的故事始于2005年。在使用PHP,ASP.NET和Python几年之后,我于2011年4月加入了Concrete Solutions Mobile团队。在他们的支持下,我们是一个只有四个人的小型团队,使所有这些不同的新技术变得有意义。 我爱上了移动开发:电话,手表,电视,物联网,您给我起个名字,就算是我。 您能否分享一些经验? 您贡献的项目,参加的活动等 只要我记得,我就一直与开放源代码领域有着深厚的联系。 通过使用,贡献,从这些项目中学习或混合学习。 开源项目一直在改善我的日常生活,并在许多方面使我的工作效率更高。 我们不仅通过编写代码来支持开放源代码,有时只需要打开一个问题,解决一个错字,在自述文件上写一些新内容,询问功能,表现出兴趣! 开源不仅是代码,而且我的贡献也很有限,就像我为Zewo(Swift服务器端项目,我是核心成员)所做的那样。 我的第一次参与始于与Paulo Faria的合作伙伴关系,我们共同创建了HTTPBasicAuth中间件,此后,我们一直在讨论Zewo的未来。 我还在CocoaHeads中做了一些有关IBDesignable,Swift Server Side和AppleTV的演示。 2015年,我去了科罗拉多州丹佛市的360iDev。这是一次完美的体验,在那里我遇到了很多优秀的人,直到今天我仍然几乎每天都在和他们聊天。 下一个目标是WWDC,但我还在等待! 😉 iOS社区非常活跃。 您如何与社区中发生的一切保持同步? 我隶属于巴西的iOS社区iOSDevBR。 该社区的一些成员还管理着CocoaHeads Brazil,因此我有机会成为共享信息的地方。 这些社区是获取新信息的好地方。 您几乎不需要花力气就能找到它。 我加入了其他一些闲散的频道,并订阅了每周几封来自世界各地的信件。 保持iOS开发中最新动态的另一种方法是关注Twitter和Github上的关键人物。 他们总是分享许多见解和新内容。 Github的“资源管理器”是另一种发现好东西,检查趋势的方法等等。 您通常使用什么工具来完成工作? 首先,Xcode哈哈。 有些朋友没有扩展就看不到自己的生活。 我喜欢使用没有太多配置或扩展和主题的IDE。 终端 :iTerm2。 Git :我有Tower的许可证,当然也使用了免费版本的GitKraken和CLI 设计和导出资产 :Sketch和Adobe XD。 代码/文本: Sublime Text3(不存在带有多个光标的编辑器,如Sublime),CodeRunner(我仍然使用Objetive-C,而CodeRunner是我的游乐场)和VSCode。 HTTP请求 :Paw.cloud,HTTPie和cURL Markdown :MacDown或Hackmd.io […]

iCarousel演练-Swift 3.0

什么是轮播? 该框架的思想是以令人印象深刻且流畅的方式移动和呈现数据。 —向GitHub的nicklockwood大喊大叫 。 让我们开始吧。 克隆github链接上提供的iCarousel文件,并将其保存到桌面。 尼克洛克伍德/ iCarousel iCarousel –适用于iOS和Mac OS的简单,高度可定制的,数据驱动的3D旋转木马 github.com 2.创建一个新的XCode项目> Single View Application。 3.从下载的iCarousel文件中,将iCarousel.h和iCarousel.m复制并粘贴到您的项目中。 确保单击“创建桥接头”,这将自动配置桥接以使两种语言都可以访问类。 4.在-Bridging-Header.h文件中,我们需要输入 #import “iCarousel.h” 这将使我们能够使用iCarousel框架中的所有文件。 5.为了使用iCarousel框架,我们需要在Build Phases > Link Binary with Libraries添加QuartzCore.framework 。 现在,所有文件都已设置。 现在,我们可以进行代码编写和设置故事板。 以编程方式设置iCarousel的方法与TableViews和CollectionViews几乎相同。 6.转到情节提要。 在View Controller场景中,选择View并在Identity Inspector中更改自定义类,然后将其设置为iCarousel 。 7.打开助手编辑器。 我们需要从Carousel视图到View Controller建立IBOutlet连接。 8.像我们如何设置TableViews和CollectionViews一样,我们需要在ViewController文件和情节提要板上设置delegate和dataSource 。 9.因为我们说过我们的ViewController有一个iCarouselDataSource协议。 我们需要遵守这些协议,在其中我们需要在ViewController中执行这些功能。 10.在示例代码中,我希望轮播显示狗的图像。 让我们继续看一下代码是如何工作的。 创建一个空数组,将保存狗的图像。 var images = [UIImage]() 11.调用函数carousel(viewForIndexAt:reusing:), numberOfItems(in:) and […]

开始进行Swift编程第16部分-inout,Lazy,Getters和Setters

之前,我们介绍了使用泛型和枚举进行闭包。 开始进行Swift编程第15部分-具有泛型和闭包的枚举 在上一篇文章中,我们讨论了错误处理。 medium.com 在本课程中,我们将逐步摆脱所有这些问题,并讨论一些可使您的代码更有效率的事情。 进出 inout是将参数传递给函数时使用的关键字。 当我们想要将变量传递给函数并修改该变量的值而不创建新变量时,使用inout 。 让我们看一下如何使用inout和不使用inout修改值。 懒 创建类时,几乎总是创建该类使用的属性。 这些属性可能只是我们打开或关闭以确定类的当前状态的标志,或者它们可能是更大的对象,例如新类用来执行某些操作的另一个类。 让我们看一个例子,我保证它是相关的。 吸气剂和二传手 获取器和设置器是计算属性的一部分。 他们是与属性观察者didSet和willSet 。 您可能还记得,当计算属性即将更改或已更改时, didSet和willSet在那里执行额外的任务。 获取器和设置器为我们提供了可用于设置值或检索值的逻辑。 这是一个例子