Tag: Yayitserica

如何制作iMessage贴纸包(Xcode 8)

如果您的iPhone使用iOS 10,则您可能已经使用了一些很棒的iMessaging新功能,例如链接预览,用手指绘图,发送对照片的反应以及发送贴纸。 制作iMessage贴纸包的过程很简单:第1步)制作一堆您想要成为贴纸的图像,第2步)将这些图像放入Xcode的iMessage扩展中,然后第3步)将它们准备好提交给App商店。 步骤1:制作一堆您想要成为贴纸的图像 我强烈建议您制作自己的图像,而不要从互联网上窃取它们。 我不像我希望的那样艺术,所以我的贴纸图像是由我的才华横溢的朋友Lori Hoffman(使用Sketch)创建的。 这里是要记住的关键事项: 贴纸可接受的格式: .png,.apng,.gif,.jpeg。 我将.png用于贴纸包。 贴纸可接受的尺寸:小(300px x 300px),中(408px x 408px)和大尺寸(618px x 618px)。 我选择使用小贴纸。 命名很重要:贴纸名称不能包含任何特殊字符或下划线。 (即使用hardshelledtaco.png代替hard_shelled_taco.png 。) 步骤2:将图片放入Xcode的iMessage扩展中 我制作了一个示例贴纸包:BlogStickerPack,以说明这些步骤。 在Xcode(确保您具有Xcode 8.o +)中,打开一个新项目,然后选择“ Sticker Pack Application”。 为项目命名后,单击导航区域中蓝色的Stickers.xcstickers文件夹,然后将贴纸图像拖到编辑器区域。 现在,运行您的应用程序。 模拟器应向iMessage打开。 单击文本字段,然后选择iMessage应用程序按钮(蓝色) 您甚至可以通过单击您的贴纸图像,然后将它们放入带有Kate Bell的假iMessage中来玩耍。 步骤3:准备好将其提交到App Store。 我假设,如果您的计算机上装有Xcode,则您对iOS编程比较认真,并且可能已经为Apple Developer帐户支付了99美元的年费。 剩下要做的就是制作一个iMessage应用图标,您就可以存档并提交到App Store。 对于应用程序图标,我使用MakeAppIcon,因为您可以拖放一张图像,MakeAppIcon会通过电子邮件向您发送所有iOS设备所需的所有尺寸。 注意:请确保您的应用程序图标具有背景(否则它将显示为黑色背景,iTunes Connect将拒绝该图像)。 这是我在App Store中的涂料标签包的链接。 在下面对您的贴纸包发表评论! 资源: iMessage应用程序-Apple文档

2017年3月女性:将灵感转化为Swift3代码

在本月初,我有点编码狂。 也许那是在洛杉矶度假的两个星期,还有我每天都在吃的所有美味的玉米饼–但我无法忍受自己正在开发的应用程序。 直到月中旬,我(后来)对华盛顿的妇女游行有了更多的了解,我找到了灵感。 如果您不熟悉此活动,那么在华盛顿举行的女性游行就是一群妇女(或任何想代表自己的人!)在2017年1月21日,即特朗普就职后的第二天前往华盛顿游行。 得知此事件后,我立即查看了“女性游行”的网站,并计划前往哥伦比亚特区参加会议。 该网站干净整洁,内容丰富,但我注意到App Store中没有Women’s App应用。 虽然该网站提供了许多有关行军统一原则以及如何捐赠的信息,但它并没有太多的“一日”信息,例如行军路线,停车和浴室设施。 因此,有了新近掌握的编码技能,我开始为“女性游行”开发一个应用程序。 我制作的应用仅包含5个视图,并带有一个标签栏控制器以在它们之间进行导航。 我想制作一个简单,不太繁琐的应用程序,并且对于一次找到本地DC信息很有用。 对于主视图,我使用DarkSky API来获取每小时的直流温度和摘要更新。 完全公开:这些图片是从Women’s March网站上拍摄的,因此,房屋底部的小巧小字体是我赞扬他们的方式。 尽管游行不需要门票,但组织者要求人们报名参加此次活动,以便他们可以准确地计算人数。 在这里,我使用了webView来显示Google Form Women’s March注册页面。 我还提供了一个FAQ页面,其中包含我从官方网站和此Vogue文章中收集的一些信息。 在Tameika Lawrence的帮助下,它被构建为带有多个Q和A标签的scrollView 。 (谢谢你,Tameika!) 在我看来,该应用程序最重要的功能是mapView,其中包括以下位置:1)集合点2)跨性别友好的浴室和3)停车场。 对于浴室数据,我使用了Refuge Restroom API ,对于停车信息,我使用了Google Places API,并带有搜索词“ parking”和“ parkinggarage”。可爱的图标来自Icons8-我爱他们的图标! 最后,由于不熟悉DC Metro系统,我想提供一张地铁地图。 我找到了@wmata Metro地图,将其插入到imageView中,然后在该imageView中添加了一个捏合手势识别器 (以实现放大和缩小)。 这个程序花了我大约3天时间,制作起来真的很有趣。 我喜欢制作一个我知道人们(我)会觉得有用的应用程序。 不仅如此,我之所以工作很快,是因为我知道进军不到7天,需要尽快完成。 最终,女性游行在游行进行的五天前发布了他们的官方应用程序,因此我决定不将我的应用程序推送到App Store。 总体而言,我对自己开发的应用程序感到满意,并且很高兴能找到灵感的源泉。 最重要的是,我很高兴能够参加女子游行,并为这项运动做出了贡献。 我前进的原因有很多,但从未想象过我会经历到积极而充满希望的能量。 我离开了行军,感到鼓舞和动力来编写代码和构建程序,这些程序不仅很酷,而且可以改善人们的生活并将它们融合在一起。 在下面给我留言,告诉我是什么激发了您的代码。 您可以在这里找到我的仓库。

如何在Swift中将GIF添加到UIImageViews

我正在制作一个包含gif的漂亮的小应用程序。 我使用了SwiftGif(一个很酷的UIImage扩展)来协助我完成这项任务。 按着这些次序: 如果您没有安装CocoaPods,请安装CocoaPods。 如果您的Xcode项目中还没有Podfile,请创建一个。 您可以通过在终端中键入“ pod init”来创建一个。 您会注意到,我的应用程序名称为“ Should_I_App”。 3.使用文本编辑器打开Podfile(我使用Sublime,它比TextEditor更好)。 如果使用Sublime,则可以键入“ subl Podfile”以在Sublime中打开Podfile。 4.在Podfile的“目标”下添加“ pod’SwiftGifOrigin’,’〜> 1.6.1’” 。 保存并关闭。 5.返回终端,输入“ pod install”,然后按回车键。 您应该得到这样的内容: 6.确保现在关闭Xcode项目。 7.通过终端,打开您的项目文件夹并打开.xcworkspace文件。 该文件是新文件; 它是在您添加任何广告连播时创建的。 8.在打开的.xcworkspace项目中,按⌘B (构建项目)。 这样就实现了项目中的Pod。 9.在ViewController.swift文件中,通过在该文件顶部键入“ import SwiftGifOrigin”来导入SwiftGif扩展名。 10.现在,在我的应用程序中,我正在使用一个生成随机名人gif的API。 在开始编写代码之前,我去了Main.Storyboard并为UIImageView(gifImageView)创建了一个插座来显示我的gif。 11.现在,我的gifImageView有一个@IBOutlet(第17行)。 凉! 在编码部分上……虽然API返回gif作为URL,所以首先我必须将URL转换为字符串(第44行)。 第二,在完成关闭时,我将gifURLString分配给gif(第27行)。 第三,我将gifImageView设置为新的gif(第29行)。 生成并运行。 魔法! 资源: SwiftGif UIImage扩展

使用NSKeyedArchiver持久化数据(Swift 3)

Apple提供了两种在应用程序启动之间保留数据的方法:Core Data和NSKeyedArchiver。 NSKeyedArchiver编码(保存)和解码(检索)您要持久保存的所有与NSCoding兼容的类。 尽管NSKeyedArchiver不如Core Data健壮(它速度较慢且手动),但它可以完成所需的持久化数据工作,并且不如Core Data复杂。 NSCoding是一种协议,它需要两种方法- 必需的init(编码器解码器:NSCoder)和encode(使用编码器:NSCoder) 。 如果我创建一个符合NSObject和NSCoder的类,则可以将该类序列化(从其当前数据结构转换为可以存储为字节的格式),并反序列化(从字节提取为数据结构)为可以保存到用户磁盘。 为了演示,我将创建一个购物清单应用程序。 步骤1:在情节提要中创建一些UI。 对于此应用程序,我使用了标签栏控制器。 第一个选项卡Add New Item包含一个标签,一个textField和一个按钮。 第二个选项卡Shopping Shopping只是一个tableView,显示了第一个选项卡中我添加的项目。 步骤2:创建我的模型对象和一个单例对象作为我的共享DataStore。 我的对象将是ShoppingItems,现在,每个ShoppingItem都有一个属性:name。 我创建了一个名为ShoppingList的类,并采用了NSObject和NSCoding协议,这将使该类与NSKeyedArchiver兼容。 我创建了1)我的ShoppingList的name属性,2)我的ShoppingList的初始化程序,以及3)创建了一个结构,该结构包含一个静态名称属性来保存我的NSCoding键(为安全起见)。 NSCoder需要两种方法,解码所需的init和编码器进行编码。 encode(使用coder:NSCoder)方法将保存(编码)我创建的Key.name的name属性。 所需的init(coder encoder:NSCoder)方法将检索我保存的名称对象并将其转换为字符串。 我还为我的name属性创建了一个getter / setter,以确保使用加载的newValue更新它。 我还使用单例作为“数据存储”,以便在我的shoppingList数组中拥有一个位置。 步骤3:为我的文本框和按钮创建一个插座和操作。 这些是必需的,以便在单击按钮后我可以在textField中检索输入的文本,并将该文本另存为新的shoppingItem。 第4步:创建一个代表filePath的变量,该变量将指定我们应在何处保存此数据。 在具有textField和按钮的viewController中,创建一个filePath属性。 此filePath属性应创建一个FileManager (如手机上的文件柜文件和文件夹)。 它还应该在我们documentDirectory中 FileManager的url数组中检索一个url。 在这里,我检索了第一个filePath。 filePath属性应该返回该URL,并附加您指定的路径,我使用了“数据”。 var filePath:字符串{ // 1-管理员可让您检查应用程序中文件和文件夹的内容; 创建一个目录到我们要保存的目录 让经理= FileManager.default // 2-这从我们的documentDirectory返回一个url数组,我们采用第一个路径 让url = manager.urls(for:.documentDirectory,in:.userDomainMask).first print(“这是documentDirectory \(url)中的url路径”) // […]

玩键值观察(KVO)(Swift3)

什么是键值观察? 顾名思义,它是一种允许一个对象观察另一个对象的属性的机制。 什么是“可观察的”? 要观察到,它必须继承自NSObject ,并且必须具有动态属性。 动态表示可以在运行时动态分配属性。 我的可观察对象是否需要为类? 可以是结构还是枚举? 可观察的属性必须是类(Objective-C类型),因此无法动态观察Swifty类型(例如结构和枚举)。 Foundation框架中定义的每个类对象均符合NSKeyValueObserving协议。 观察者实际上在做什么? 当一个对象(即一个viewController)被添加为观察者时,它所观察的属性发生变化时,它会收到一个通知。 什么是实现键值观察器的示例? 因此,假设我有一个WKWebView对象,并且想要观察其属性之一, estimatedProgress 。 首先,我需要添加一个观察者,该观察者将收到有关EstimateProgress更改的通知。 在这里,我将ViewController设为观察者。 在上面的第21行,我在seaWebView上调用.addObserver方法,该方法是WKWebView的实例。 .addObserver方法具有四个参数:observer,forKeyPath,options和context。 观察者 =正在侦听的对象(又名我的ViewController,自我) forKeyPath =我正在观察的属性(又名EstimatedProgress )。 注意:这是字符串文字。 此KVO是Objective-C机制,因此键和键路径是字符串。 小心输入这个坏男孩! options =代表观察者收到的信息类型。 类型包括.new (属性的新值) 、. old (属性的旧值) 、. initial (甚至在添加.addObserver方法之前发送给观察者的立即值) 、. prior (发送通知)任何更改之前和之后)。 context =一条通知消息,其中包含在相应的更改通知中传递回观察者的任意数据。 我在上面设置为零。 其次 ,我需要实现observeValue()方法。 在第31行,我实现了watchValue方法,该方法接受四个参数,keyPath,object,change和context。 keyPath =您正在观察的属性(又名EstimatedProgress ) object =引用正在观察的对象 变化=观察到的变化存储在[NSKeyValueChangeKey:Any]?的词典中[NSKeyValueChangeKey:Any]? 因此,所有观察到的特性变化都保存在该词典中。 context […]

谈论我的泛型-第1部分(快速3)

“ 通用编程是一种计算机编程风格,其中,算法根据稍后要指定的类型编写,然后在需要以特定类型作为参数提供时将其实例化 。” — Wikipedia 使用泛型编写代码是一种编写函数和数据类型而无需指定需要使用哪种确切类型的方法。 顾名思义,泛型类型不是特定的。 通过使用泛型,我们可以编写非特定的代码,因此,我们可以以更清洁,错误更少的复杂方式抽象代码。 在第一部分的这篇文章中,我将讨论数组,字典和可选变量是泛型的示例。 第二部分将讨论编写通用数据类和结构,编写通用函数和约束通用类型。 第三部分将讨论“关联类型”和“通用where子句”。 泛型数组 数组是泛型类型的示例。 数组是容纳任何类型的事物的容器。 在Swift中,我们受益于类型推论,我们可以在不显式声明其类型的情况下创建数组。 由于我们不必指定任何数组的类型(因为可以推断出该数组的类型),因此该数组作为数据结构是通用的。 让月份= [“一月”,“二月”,“三月”] 上面,我有几个月的时间。 由于我给的数组类型参数是字符串,因此本月的实例被赋予了STRING的具体类型 。 换句话说,声明数组时应定义的类型。 数组的通用语法 尽管上述月份的数组未正式将类型声明为STRING,但是有一种通用的语法声明数组,如下所示: var springMonths:Array = [] 请注意,单词Array后跟尖括号中的类型。 我们可以在这些尖括号之间分配“通用类型”的名称。 对于泛型,规范是使用作为我们引用的任何泛型类型的占位符。 在数组上使用通用方法 数组是通用的,带有通用方法,例如.append() springMonths.append(“ March”) springMonths.append(“ April”) springMonths.append(“五月”) 您会在上面注意到,我在springMonths数组中附加了月份“ March”,“ April”和“ June”。 如果我接下来编写以下代码行,您会怎么办: springMonths.append(50) 如果您猜编译器会给我错误: 那你是对的! 由于我们声明了Array的类型为STRING,因此任何不是字符串的东西都会使编译器不满意。 泛型词典 字典也是泛型的,因为我不必直接指定每个键的类型或每个值的类型。 例如,在下面,我没有具体说明字典类型: let monthDaysDictionary = [“一月”:31,“二月”:28,“三月”,31,“四月”:30,“五月”:31,“六月”:30,“七月”:31,“八月”: 31,“ […]

谈论我的泛型-第二部分(快速3)

“泛型编程 是一种 计算机编程 风格, 其中 算法 是根据 类型 编写的 待定,然后 在需要作为 参数 提供的特定类型时实例化。” — Wikipedia 使用泛型编写代码是一种编写函数和数据类型而无需指定需要使用哪种确切类型的方法。 顾名思义,泛型类型不是特定的。 通过使用泛型,我们可以编写非特定的代码,因此,我们可以以更清洁,错误更少的复杂方式抽象代码。 在上一篇文章中,我描述了数组,字典和可选变量是泛型的示例。 在第二部分的文章中,我将讨论编写通用数据类和结构,编写通用函数和约束通用类型。 第三部分将讨论关联类型和通用Where子句。 编写通用数据类和结构 虽然数组,字典和可选变量都是泛型的示例,但我们也可以使用泛型来创建自己的数据类型。 例如,我可以堆一个 具有泛型的数据类型-不特定于任何数据类型(浮点数,双精度数和整数)。 堆栈使用LIFO(后进先出)过程,将新项目推到堆栈顶部,然后从堆栈中取出最新项目。 我喜欢将其视为一叠纸牌,将它们一叠放在另一叠上,并且只能从顶部取出。 假设我要创建自己的堆栈。 我可以使用尖括号将其指定为通用,这意味着,我可以在创建堆栈时决定要堆栈的内容。 在这种情况下,我想编写一堆字符串,这些字符串代表我当前正在阅读的所有编码书。 1:我创建一个结构来表示我的EricasStack数据类型。 请注意,在尖括号之间使用“通用 ”一词。 我可以在那里写任何词(也许是“炸玉米饼”?)作为我在此EricasStack中使用的值的占位符。 2:我创建了一个泛型数组,该泛型将容纳我的编码书籍堆栈。 3: 我想一次将两本书添加到我的书架中,所以我编写了一个推入两个项目的函数。 4:我想一次将两本书移到我的书架中,所以我编写了一个函数,该函数返回要被POPPED的两个项目。 5:我创建一个类型的EricasStack实例。 请注意,我现在只能追加字符串。 我将两本书推到CodingBooksStack上,然后再推两本书(总共四本书)。 然后,我打印出最终的CodingBooksStack包含的内容。 当我调用.popTwoItems()时,还可以看到打印出来的打印内容。 我也可以赚到一笔EricasStack的钱: 如您在上面看到的,当我创建EricasStack类的实例时,可以用任何类型填充。 编写通用函数 假设我想获取一个Int,然后将其复制到数组中。 假设我想获取一个String,然后将其复制到数组中。 假设我想使用Float,然后将其复制到数组中。 我应该为这三种不同的类型编写三种不同的功能吗? 我可以使用GENERICS编写一个仅适用于所有类型的函数。 函数和方法在泛型类型的上下文中可以是泛型的。 1:我编写了一个名为的通用类型的函数,该函数接受一个项目,并指定一个整数,该整数指定要复制ItemToDuplicate的次数。 2:我创建一个空数组来保存我的arrayOfDuplicates。 3:循环numberOfTimes,每个团队都将一个ItemToDuplicate添加到我的arrayOfDuplicates数组中。 […]

大中央派遣-如何终端! (快速3)

嗯,多线程,并发等等。 这些都是在Flatiron学校的话题,我们被告知“这确实很重要”,现在我开始寻找工作,阅读工作说明并进行技术面试,现在我意识到Flatiron并不是在撒谎。 因此,在这里,我们只关注一件事: 中央中央调度(GCD) 。 Grand Central Dispatch(以前称为libdispatch的框架)是Apple的框架,用于将并发(管理同时发生的多件事)合并到您的应用程序中。 基本上,GCD会为我们管理队列(为我们完成所有任务调度!),因此我们不必考虑如何合并线程或在哪里“锁定”代码行。 GCD允许我们(开发人员)考虑将代码编写为单个线程或进程,因此,我们只需要考虑在哪里分解我们的部分代码以在另一个线程上运行。 Apple文档指出,“ GCD提供并管理FIFO(先进先出)队列,您的应用程序可以以块对象的形式向其提交任务。 提交给调度队列的工作在系统完全管理的线程池上执行。 无法保证执行任务的线程。” 简而言之,GCD是我们的小帮手,因为它: 因为它在后台运行长时间运行的任务,所以有助于提高我们的应用性能。 通过避免在新线程上设置锁和分离代码的需要,使开发人员更轻松(如果操作不正确,可能会导致并发错误) 可以提高代码性能,例如单例。 因此,让我们退后一步,回顾一些在开始讨论GCD之前需要理解的词汇和概念: 任务=需要完成的一项工作(即API调用)。 线程=操作系统提供的进程,它允许多个指令集(又称代码行)在单个应用程序中同时运行。 进程=代码的可执行部分,可能在多个线程中。 太酷了,既然我们已经把这些术语简化了,让我们来谈谈任务的执行方式。 串行调度队列与并发调度队列 如果一项任务一次执行一次,则称它是串行执行的。 如果可以同时执行多个任务,则称它们是同时执行的。 Grand Central Dispatch提供了调度队列(以“队列”为一行),使您可以在所谓的并发调度队列上并发运行代码块。 使用并发调度队列,我们​​有多个线程可用于同时处理多个代码块。 这种队列不同于串行调度队列 , 串行调度队列一次只在一个线程上添加一件工作。 同步与异步执行 函数可以是同步的也可以是异步的。 同步功能仅在上一个任务完成后返回 。 我喜欢将其视为“同步”(有趣的事实:NSYNC是我一直以来最喜欢的男孩乐队)。 异步意味着它可以立即运行,而无需等待上一个任务完成就可以开始。 因此,它不是同步的(我喜欢将异步看作是我的NSYNC的后街男孩)。 大中央调度:我们如何使用它? 如前所述,GCD为我们提供了调度队列,用于管理代码块。 这些分派队列负责处理我们提供给GCD的任务,并按FIFO ( 先进先出 )顺序进行处理(第一个任务排在队列的首位,依此类推)。 您还记得在串行调度队列中 ,一次只执行一个代码块。 在GCD中,这些块的执行时间在GCD的控制之下。 换句话说,我不知道代码的第1、2和3块要花多长时间,但是我知道两件事:1)每个块一次要运行一个,2)他们要运行一次以添加它们的顺序运行。 对于并发调度队列,可以同时执行多个代码块。 GCD的工作是决定何时启动每个块。 由于这些是同时运行的多个代码块,并且将重复执行这些代码块,因此GCD 决定何时这些块之一应在其他内核上运行 (一个内核是计算机的处理器之一。我的Macbook […]

viewDidLoad()vs. loadView()(Swift3)

这个月在Flatiron学校,我们深陷“项目模式”! 对于小组的项目,我一直在视图中使用程序化UI元素,这使我成为本博客文章的主题。 现在,我们都知道并喜欢视图控制器中的viewDidLoad(),但是loadView()呢? 这个loadView()函数是什么? loadView()是由viewController管理的方法。 当其当前视图为nil时,viewController调用它。 loadView()基本上获取一个视图(您创建的)并将其设置为viewController的视图(superview)。 可以为我们的viewController创建视图的方式有哪些? 好了,您可以创建一个xib(nib),可以使用情节提要(Interface Builder),也可以以编程方式创建一个UIView对象。 因此,如果我使用情节提要,是否需要使用loadView()? 如果使用情节提要,则不需要使用loadView()。 实际上,不要重写此方法。 仅当您手动创建视图(即不是故事板)时才重写此方法。 loadView()创建并实例化UIView对象。 因此,如果我从Xib / Nib创建视图并想进一步对其进行自定义,则应使用哪种方法? 使用名为viewDidLoad()的方法,即loadView()完成其工作并且UIView准备好显示之后。 viewDidLoad()允许您初始化view / viewController对象的属性,并在调用viewWillAppear()之前将其完成。 那么,首先加载哪种方法? 当视图完成加载时,将调用viewDidLoad(),而在视图开始加载时,将调用loadView()。 希望这有助于弄清差异! 资源: loadView()— Apple文档 viewDidLoad()— Apple文档

什么是通知(Swift3)?

最近,有一位朋友告诉我,在最近的一次采访中,有人问她有关Notification的经历。 我认为稍微研究一下会很有用。 我了解到的一件事是,通知中心(以前称为NSNotificationCenter)适合观察者设计模式,该对象在其中将任何更新或更改通知其他对象。 Apple的文档指出,“ NSNotificationCenter对象(或简称为通知中心)提供了一种在程序内广播信息的机制。”换句话说,Notification就像广播消息的广播电台一样。 这样, 发送者 (广播者或广播电台)发出消息, 观察者 (听者)可以决定何时收听以及收听什么内容。 基本上,通知提供了一种在应用程序内传递信息的方法,而类之间没有直接引用。 通知中心会跟踪关注特定通知的所有不同类型的观察者,因此在发布通知时,通知中心会将消息发布到已为该通知注册的每个观察者。 要设置通知中心,需要3个步骤: 步骤1:将事件(消息)发布到通知中心,该事件将通知要侦听此特定消息的所有对象。 步骤2:将观察者(侦听器)添加到通知中心。 步骤3:编写一个代码块,该代码块在发生通知时被调用(收到通知后您将要做什么?)。 我制作了一个带有标签栏控制器的简单应用程序。 标签1:显示随机的海洋图像。 选项卡2:如果用户喜欢选项卡1中的图像,则选项卡2将向他们显示另一个随机海洋图像。 在上面,我向NotificationCenter.default发布了一个名为“ LikedItNotification”的通知。一旦用户单击FirstViewController中的 Like Like按钮,该通知就会被发布! 在上面,我为在FirstViewController中创建的通知创建了一个观察者(侦听器)。 我还编写了将在收到通知后执行操作的代码。 在这种情况下,我的操作是取消隐藏youLikedItLabel并将随机图像分配给SecondViewController中的imageView。 埃里卡(Erica),如果您在想,我觉得您可以通过使用单例来做类似的事情,您是对的。 看来NotificationCenter只是让您的班级互相交谈的另一种方式。 我的理解是,如果整个应用程序需要了解特定的通知(即显示键盘,用户确实登录/注销),则可以最佳地利用NotificationCenter。 这是我完成的应用程序的演示视频! 希望您今天了解到有关NotificationCenter的新知识。 您可以在此处下载项目。 资源: Apple文档— NSNotificationCenter 视频— Swift 3中的iOS通知中心 停止使用NSNotificationCenter Ray Wenderlich — iOS设计模式:观察者模式