Tag: iOS应用开发

在iOS App中使用核心数据背景上下文获取远程数据

核心数据是Apple提供的用于开发iOS应用程序的对象图和持久性框架。 它处理对象生命周期,对象图管理和持久性。 它支持用于处理应用程序内部模型层的许多功能,例如: 对象之间的关系管理。 使用撤消管理器更改跟踪 延迟加载对象和属性 验证方式 使用NSPredicate进行分组,过滤和查询 模式迁移 使用SQLite作为后备存储的选项之一。 Core Data自动提供了许多高级功能,它具有陡峭的学习曲线,可供开发人员首次学习和使用。 在iOS 10之前,要在我们的应用程序中设置Core Data,我们需要执行许多配置和样板代码来构建Core Data Stack。 幸运的是,在iOS 10中,Apple引入了NSPersistentContainer,我们可以使用它初始化所有堆栈并以很少的代码获得NSManagedObject上下文。 在本文中,我们将构建一个简单的演示应用程序,该应用程序可从远程《星际大战》 API获取电影列表,并使用后台队列天真地在没有同步策略的情况下同步Core Data存储中的数据。 我们将建立: 受管对象模型架构和影片实体。 电影实体的托管对象。 CoreDataStack:负责使用该模式构建NSPersistentContainer。 ApiRepository:一个类,负责使用URL会话数据任务从StarWars API中获取电影数据列表。 DataProvider:一个类,提供接口以从后台存储库中使用NSManagedObjectContext从数据存储库中获取电影列表并将其同步到Core Data存储。 FilmsViewController:与数据提供者进行通信并使用NSFetchedResultsController从核心数据视图上下文中获取并观察更改的视图控制器,然后在UITableView中显示电影列表。 您可以在项目GitHub存储库中签出该应用程序的完整源代码。 alfianlosari / CoreData-Fetch-API-Background 使用核心数据背景上下文获取Star Wars API的iOS应用– alfianlosari / CoreData-Fetch-API-Background github.com 您还可以通过单击以下网站的链接来结帐并尝试使用StarWars API。 SWAPI –星际大战API 星球大战(Star Wars)API或“ swapi”(Swah-pee)是世界上第一个量化且可通过编程访问的数据源…… swapi.co 受管对象模型架构和影片实体 我们将执行的第一步是创建包含影片实体的托管对象模型架构。 从Xcode创建新文件,然后从核心数据模板中选择数据模型。 将文件命名为StarWars,它将以.xcdatamodeld作为文件扩展名保存。 单击我们刚刚创建的数据模型文件,Xcode将打开数据模型编辑器,在其中我们可以将实体添加到托管对象模型模式中。 […]

Swift中的惰性属性

Swift中的lazy关键字使您可以延迟存储属性的初始化,直到需要它为止。 这种方法的好处是可以提高性能,因为如果不需要立即启动,可以避免启动过程中潜在的昂贵过程。 您可以将初始化视为分配具有初始值的变量。 一个对象可以具有属性,因此当我们初始化它时,它的属性也会被初始化。 定义惰性属性 您可以通过在var关键字前添加lazy来定义lazy属性。 但是,您不能使用常数,因为惰性属性的值仅在初始化后才计算,而常数则需要一个值。 由于使用lazy关键字的目的是将代码执行延迟到初始化之前,因此,简单的自执行闭包是一个完美的用例。 让我们以下面的伪代码 为例 想象一下,我们有一个MathsHelper类,该类可用于计算Pi的值以及其他随机方程的集合。 如果只打算使用它们的一个子集,则无需计算此类中的所有属性。 通过在var前面加上lazy ,可以延迟此操作,直到需要它为止。 这种方法的另一个优点是,我们现在将此属性的声明和设置都放在一个位置。 我可以将计算属性声明为惰性吗? 不。 每次访问计算属性时都会重新计算,但是根据定义,在初始化时,惰性属性仅计算一次 。 这种方法有什么缺点吗? 附加了lazy关键字的var不是线程安全的。 这并不意味着多个线程在尝试访问其值时将创建多个实例,而是如果2个或更多线程尝试同时访问它,则第一个线程之后的任何线程都可能接收到该对象的部分初始化的实例。 在Swift本身中,有一个开放的错误可以解决此问题。 tl:dr? lazy关键字用于延迟变量的初始化 这可以帮助提高性能和启动时间 但是,此行为不是线程安全的

Swift 4的新功能

Swift 4稳定版本即将发布,可从https://swift.org/download/#snapshots下载swift-4.0-branch。 在本文中,我将带您了解Swift 4中新增的一些功能。 安装 swift-4.0 快照工具链 请转到https://swift.org/download/#snapshots并从下载部分获取Xcode。 2.安装工具链后,导航至Xcode-> Toolchain,然后选择Swift 4.0 Snapshot。 我建议选择工具链后重新启动xcode。 多行字符串文字-SE-0168 使用\ n添加新行并在字符串中转义双引号并不总是一件容易的事。 Swift 4通过提供对多行字符串文字的支持解决了这个问题。要开始字符串文字,请添加三个双引号(“”“)并按回车键,按回车键后,开始使用任何变量,换行符和双引号编写字符串就像您在记事本或任何文本编辑器中编写的一样。 要结束多行字符串文字,请在新行中再次写入(“”“)。 让multiLineStringLiteral =“”“ 这是Swift 4中最好的功能之一 它使您无需任何转义就可以写“双引号” 和不需要“ \ n”的新行 “” 打印(multiLineStringLiteral) 产生以下输出。 “这是Swift 4中最好的功能之一,\ n您可以编写“双引号”而无需转义\ n,而无需“ \ n”就可以换行 String will be treated as collection — SE-0163 就像在Swift 1.x版本中一样,可以将字符串视为集合。 您不再需要编写string.characters.xxx即可执行字符串操作。 let message =“消息!” message.count //不需要message.characters.count 用于消息中的字符{//不需要message.characters 打印(字符) } […]

训练营的编码问题

长大后,我在家接受教育。 这可能使我倾向于采用自我指导的学习方法-我喜欢选择内容和制定有效的消费策略的过程。 不过,在早期,我认真考虑过参加编码训练营(至少作为起点)。 自学方法有弊端,特别是如果您在像我这样的自律中挣扎。 这是参加训练营的一些主要优势。 这些好处是假设训练营经过精心设计,并配备了优秀的教师,他们在应用程序开发方面也具有实际经验。 在与他人合作的团队环境中,您将获得从学习到编码的宝贵技能。 您将被迫主要通过专注于项目驱动的学习方法来学习,这种方法可以防止“学习狂热”。 您将从经验丰富的开发人员处收到有关代码质量和方法的直接,持续的反馈。 您将沉浸在行业工具和最佳实践中。 您将可以使用职业服务,并通过遇到的老师和学生建立良好的联系网络。 一些雇主对通过培训计划获得的正式证书比通过自学更有信心。 由于这些重要因素,我着手寻找一个iOS开发训练营。 不愿意搬到现场接受培训意味着我的选择仅限于提供在线课程的学校。 事后看来,这可能排除了一些最佳选择(基于砖和灰浆)。 我也不愿意承担大量债务,因此进一步排除了许多潜在的好的计划。 尽管我进行了所有研究并且对自己的选择充满信心,但在开始在线训练营仅一周后,很明显我做出了一个错误的决定。 在取消信中,我与公司分享了: “感觉这门课程缺少将其与在线或Apple文档中已有的所有内容区分开的独到见解。 我喜欢了解事物的运作方式。 练习中的解释让他们急于尝试通过一系列步骤。” – 2018年2月 在教育行业中,很难分辨出质量营销与质量计划之间的区别。 有时,最好的资源实际上从外观上说服力最少。 课程报告是查找和评估训练营的绝佳场所。 您可以阅读曾就读于这些学校的人的许多详细评论。 我选择的学校获得了很高的评价,所以不要只根据评论来判断。 大多数人认为只要不可怕就可以算是“好”,而且没有什么可比拟的。 我认为存在出色的iOS训练营。 有些人将从他们的自我强加的结构和严谨的工作中受益匪浅。 但是要考虑两个主要因素: 最好的训练营通常是最昂贵的 。 高价格并不意味着高质量,但是低价格几乎总是意味着低质量。 训练营针对特定级别进行了优化 。 如果您的编程经验水平不是他们所针对的,那么即使是高质量的训练营也可能是一个糟糕的选择。 如果潜在的训练营告诉您他们的计划适合任何水平的经验,请远离。 这两个因素最终使我回到了自学方法。 我不希望参加顶级训练营所需的财务风险,而且很难找到一个不会跳过重要基础知识或花很长时间重新引入基础知识的人。 如果您能够自己有效地学习,那么有很多针对各种知识和经验进行了优化的特殊资源,这些资源可以用很少或几乎没有成本的方式获得。 挑战在于知道要使用哪些资源以及在哪里找到它们。 这会使自学方法缓慢而令人沮丧。 但是,这些正是我希望通过分享所要缓解的挑战。 在以后的文章中,我将返回参加训练营的优势列表,并分享我从其他人那里学到的一些策略,以期在自学过程中培养这些相同的优势。 安德鲁 PS:如果您有兴趣参加iOS训练营,那么有一个在我眼中脱颖而出的人:Dev Mountain。 如果位置和成本不是因素,那可能是我的第一选择。 图片来自Unsplash。

关于移动应用程序开发成本的另一篇文章

在互联网等平台上展示您的业务需要什么? 网站或移动应用程序,或两者兼而有之。 当前的市场趋势表明,在移动设备上运行的应用程序中提供服务是与客户进行交互的最简单方法。 在全球范围内,智能手机的便携性一直是大众使用智能手机和平板电脑的原因。 印度和全球的IT部门一直在为遇到此要求的小型企业提供此类服务。 多家供应商在IT市场中提供相同类型的服务,这使客户处于困境中,无法选择最佳交易来进行Web应用程序或移动应用程序开发。 随着移动性进入市场,移动应用程序开发是小型企业参与的关键功能。对于此类客户,选择合适的开发人员可以以可承受的成本提供应用程序开发及其功能。 加上可以在应用程序中可用功能方面提供透明开发成本的开发人员。 选择要添加到应用程序中的功能的灵活性也使客户可以选择应用程序的价格和投资。 客户所想到的基本思想是通用的应用程序,开发公司将指导并逐步引导客户使用可添加到应用程序中的各种功能,这可能会影响应用程序开发的最终成本和时间由开发人员用来开发产品。 开发移动应用程序的平均成本在$ 15,000到$ 1,00,000之间,具体取决于您选择的功能。 其中提供的功能尚不清楚,他们说它具有基本功能。 这些基本功能是什么? 想过吗? 它可以像推送通知,用户登录一样基本,或者仅在应用程序页面上显示内容。 所谓的基本功能可能在Web服务器的开头包含很小的存储空间,但是谁知道此可用存储何时耗尽,则可能需要在所有中间请求更多。 因此,在为您的企业的移动平台选择开发人员时做出正确的决定。 构建移动设备并投资相关成本取决于您为应用程序选择的平台。 主要有两个主要平台可用Android和iOS。 两个平台的成本相应地变化。 可能增加/减少预算的因素将是您要求开发人员开发的应用程序的类型。 开发包含大约成本的应用程序的基本类别如下: ·基本应用程序的成本为$ 15K-25K,具体取决于您可以向开发人员提供有关应用程序设计方面的投入。 ·涉及完整CMS,外部集成,聊天和购物车的应用程序可能要花费60,000 INR至1,000,000 INR,这是应用程序开发中最昂贵的类别。 尽管如此,您仍可以减少雇用自己的专门UI开发团队的成本,该团队专门在应用程序的设计部分工作。 最后,涉及年度费用的是应用程序的维护和支持。 由于必须定期更新应用程序,因此随着时间的推移会出现一些小故障。 因此,您需要一个支持团队来帮助您发布应用程序的稳定更新。 应用程序开发分为前端开发和后端开发人员,您可以选择将工作划分给不同的参与者,但是对于一个可以为您提供完整软件包的供应商来说,这是非常好的。 最后,我建议使用此应用程序费用计算器来了解您的移动应用程序开发的指示性价格。 Bluelupin的自定义应用程序开发成本计算器 此工具可帮助您计算开发自定义移动应用的指示性费用 calc.mobilekonnect.com

使用URLComponents和URLQueryItem在Swift中构建安全URL

构造URL是每个Swift开发人员在构建iOS应用程序时都会执行的一项日常任务。 确保我们构建的网址安全且使用百分比编码格式正确编码非常重要。 构造URL的最简单且最容易崩溃的方法是使用传递原始字符串的URL Struct String initalizer。 让 searchTerm =“ obi wan kenobi” let format =“ wookiee” 让 url = URL(字符串:“ https://swapi.co/api/people/?search= \(searchTerm)&format = \(format)“)! //异常(致命错误)! 虽然它适用于没有查询参数的简单URL,但是当我们手动将查询参数添加到未使用百分比编码正确编码的字符串时,就会出现不安全行为。 手动为每个查询参数附加字符串的过程也很容易出错。 输入URLComponents和URLQueryItem 为了解决此问题,Apple的Foundation框架实际上提供了两种类型的Struct,我们可以将其用作构建带有安全查询参数的URL的构件,它们是URLComponents和URLQueryItem 。 URL由许多部分组成,例如方案,主机,路径和查询。 使用URLComponents结构,我们可以通过手动指定方案,主机和路径来安全地构建URL。 为了安全处理查询参数的百分比编码, URLComponents还公开了queryItems作为属性。 QueryItems是URLQueryItem的数组,我们可以使用URLQueryItem初始化程序传递查询参数的名称和值。 通过分配queryItems数组, URLComponents将在内部添加查询参数的百分比编码。 将键值字符串的字典映射到URLQueryItem数组 我们可以使用的另一种有用模式是将查询参数封装在具有String作为键和值的Dictionary内。 我们使用一个接受Dictionary的变异函数向URLComponents添加扩展,然后使用每个项目键和值将Dictionary映射到URLQueryItem数组,然后将其分配给URLComponents queryItems属性。 使用URLComponents和URLQueryItems构建SWAPI API存储库(示例) 这是一个示例,说明如何使用URLComponents和URLQuery项目作为每个端点的构建块来构建Remote DataRepository类。 我们还将为每个Planets, Spaceships, Vehcicles, People, Films, Species, Wookiee format, JSON format […]

使用Swift 4编码和解码JSON

Apple上周在圣何塞举行的WWDC 2017主题演讲和国情咨文中宣布了Xcode 9以及Swift4。使它成为Swift 4标准库的最重要的变化之一就是一系列编码,解码和解码协议。类型实例的序列化,允许用户与JSON以及与本地磁盘进行相互转换。 这些协议(最著名的是Codable , Encodable和Decodable旨在作为Swift的本机答案,以解决开发人员在Swift 3或更早版本中序列化对象时遇到的一些限制。 这些协议仅在一个星期前就已经流行了,但是Apple可以在线获取一些出色的文档。 我花了一些时间对这些API进行试验,以进一步了解它们的工作原理,可能的功能以及在生产代码库中使用它们可能遇到的一些优点和缺点。 到目前为止,Swift社区中最大的开放问题之一是“您使用哪个第三方框架对JSON反序列化? 还是你自己滚?”。 自从我第一次开始编写Swift以来,我已经尝试了几种第三方框架并开发了自己的框架。 我经常对此感到沮丧的是,每个框架都带来了自己独特的方法,但是它们似乎都误选了可选内容,缺乏强大的错误处理能力,并且使用了不直观的自定义运算符。 Swift 4的Codable协议现在为解决该问题提供了一种通用且推荐的方法,因此我根据一些我经常会遇到的关键用例进行了实验。 反序列化 假设您有一个结构Product并且想从网络请求中收到的JSON响应中反序列化实例。 确保Product和任何自定义属性类型均符合协议Codable (如果不序列化回JSON,则仅Decodable )。 在要将Data对象反序列化为Product模型的那一点上,初始化JSONDecoder对象,然后调用decoder.decode(_: from:) 。 如果解码操作失败,则此函数将引发错误,因此您可能需要将其包装在do,try catch语句中。 就是这样。 假设Product模型上的所有属性名称与您要反序列化的JSON结构中的字段名称完全对应,Swift将处理初始化模型实例所需的所有工作。 序列化 将Product序列化回JSON仅需要模型及其所有自定义属性类型符合协议Codable (如果您不从JSON反序列化,则仅Encodable )。 在您想要将Product实例序列化为要在网络请求或其他任何地方发送的Data ,请初始化JSONEncoder对象,然后调用encode(_:) 。 如果编码操作失败,此函数也会引发错误,请随意将其包装起来,然后尝试再次捕获。 嵌套类型 在Swift 4中,对具有同样也是Codable类型的属性的Product模型进行反序列化变得非常容易。非常简单,只需确保每个嵌套类型都符合Codable (或者在需要时仅Encodable / Decodable )。 就像您期望的那样, JSONDecoder将以与解码顶级对象相同的方式来处理嵌套属性的解码。 自定义属性名称 当然,使用JSON从未如此简单。 作为移动工程师,我们经常无法控制我们正在使用的Network API,并且想要为要从JSON有效负载解码的属性定义自定义字段名称。 重要的是要了解,默认情况下,Swift会自动使用您定义为字段名称的属性名称来从JSON进行解码。 在Codable类型上为属性定义自定义字段名称就像在对象CodingKeys上定义一个枚举一样简单,该对象的rawValue类型为String并符合CodingKey协议。 您需要为模型上的每个属性定义一个案例。 然后,将每种情况的RawValue用作要从JSON解码的JSON字段名称。 自定义键路径 在我尝试使用更复杂的键路径和JSON结构进行的简短介绍中,似乎Swift的处理这些方法需要一些习惯,并且涉及很多样板。 […]

使用RxSwift切换组件

拨动开关列表在移动世界中广泛存在。 我在我使用的大多数应用程序的“设置”屏幕中找到它。 对我来说, 打开和关闭事物并将其保存在某个地方的简单动作隐藏了我将要揭示的有趣的复杂性。 在本文中,我将使用RxSwift构建“切换列表”屏幕。 我将使用上一篇有关自动完成的文章中介绍的技术。 我们将创建Toggle组件-一个带有输入和输出要插入的黑盒子。 阅读此书后,您将可以在项目中使用它来建立自己的切换体验。 切换 首先,了解我们将要积累的经验。 请注意,在将其状态发送到服务器时,单次切换处于禁用状态,有时它会摇动并退回到先前的状态-发生保存错误时: 在Swift中也一样: 并提供用于使用Toggle配置单个UISwitch支架: 现在,将在setUp(settingSwitch:with toggle:)完成输出编排。 它以settingSwitch和toggle作为参数。 在上面的视频中,对UISwitch进行了三种修改: settingSwitch.isOn属性使用切换初始值设置,以后可以使用切换后备值强制更改; settingSwitch.isEnabled已更改为Toggle活动; 播放settingsSwitch.shake()动画以切换回退值 。 第一个修改是由initialValue和fallbackValue流合并到单个switchValue流中定义的: switchValue流驱动rx.isOn属性。 虽然.flatMap { $0.map(Driver.just) ?? Driver.empty() } .flatMap { $0.map(Driver.just) ?? Driver.empty() }可能看起来很神秘,它只有在不为nil时才发出值。 如果使用RxSwiftExt库,则等于.unwrap() 。 为了提高代码的可读性,我们使用ToggleValue扩展的以下三个便捷属性: 第二个突变很简单: 否定isBusy输出以驱动器settingSwitch.rx.isEnabled 。 当fallbackValue出现在fallbackValue流上时,第三个突变播放.shake()动画: 我们不在乎fallbackValue发出的值,因此我们将其映射到void () 。 最后,通过UISwitch的此扩展来制作shake()动画: 值得注意的是, Toggle组件并不限制我们构建这种类型的UX。 某些应用会在服务器上保存设置时阻塞整个屏幕。 只需将多个isBusy输出合并到单个isLockViewVisible流中,即可使用Toggle轻松完成。 单元测试 因为唯一的Toggle’s依赖项是ToggleStorage ,它是一个协议,所以创建MockToggleStorage并完全测试Toggle非常容易。 一个很好的例子是该测试确保在用户输入后发出更新值。 我们使用帮助程序recordedValues数组存储value输出发出的所有值。 […]

在iOS上使用Charles作为SSL代理

大多数应用程序都使用HTTPS请求来访问数据,并且由于SSL加密,很难从App Store中已存在的iOS应用程序中对其进行调试。 Charles是帮助您检查HTTPS请求的完美工具。 Charles Proxy是一款旨在通过代理调试Web应用程序的软件。 它不是免费的,但您可以使用其30天的试用版。 作为iOS移动开发人员,您可以将其作为与iOS设备一起使用的HTTP代理, 以中间人的方式来检查手机发出的请求。 以下是在手机上启用该功能的步骤。 在进行任何操作之前,请确保您的设备和计算机位于同一网络上。 然后,您需要在设备上安装“查尔斯根证书”。 为此,请按照帮助> SSL代理>在移动设备或设备上安装Charles Root证书进行操作 。 它将为您提供IP地址和要使用的端口。 在iPhone的Wifi设置下,您需要使用Charles给出的计算机IP地址启用HTTP代理。 保存后,将在笔记本电脑上提示对话框,要求允许此新访问权限。 您的设备连接现在将抛出Charles。 您可以立即看到HTTP请求。 但是,要检查HTTPS请求,还需要执行几个步骤才能启用SSL代理。 使用Safari,您必须导航到chls.pro/ssl才能在手机上安装Charles证书并进行验证。 以后您仍然可以在“设置”>“常规”>“配置文件”下找到它。 在您的手机上安装证书后,我们需要确定证书已启用。 为此,请遵循设置>常规>关于>证书,然后启用您刚刚下载的证书 。 在Google网站上进行测试,我仍然看不到发送的内容。 我还可以看到未为此主机启用SSL代理 。 我们需要完成在Charles端启用SSL代理的功能。 返回您的笔记本电脑,在代理> SSL代理设置下 ,我们将添加一行以覆盖Google域。 我还指定了HTTPS端口443使其保持干净。 您可以为通配符使用* 。 终于,我请求中的所有内容现在都清楚了。 在后台发生的事情,从您的笔记本电脑到Google的请求仍在HTTPS下。 但是,在使用从笔记本电脑到手机的本地受信任证书时,在实际发出请求之前,可以清晰地访问发送的那些数据。 您本地网络上的其他任何人都无法访问那些未加密的数据。 此示例涵盖了来自Safari之类的Web内容的调试请求。 但是,如果要使用它调试特定的移动应用程序,则可能需要在plist文件中添加安全性标记才能启用该功能。 NSAppTransportSecurity NSAllowsArbitraryLoads 总之 ,Charles Proxy使用起来非常直观,但是设置起来却很棘手,我希望本教程也可以使其他人更容易。 如果您对该文章有任何疑问或建议,我们将很乐意在评论部分提供帮助 最初发布在 http://benoitpasquier.com/charles-ssl-proxy-ios/ 。

iOS:设计模式

设计模式是针对软件设计中常见问题的可重用解决方案。 它们是旨在帮助您编写易于理解和重用的代码的模板。 最常见的可可设计模式: 创作性 :单身人士。 结构 :装饰器,适配器,外墙。 行为的 :观察者,和,纪念品 让我们开始吧…… 🏄🏻 正面 Facade设计模式提供了到复杂子系统的单个接口。 无需向用户提供一组类及其API,而是仅公开一个简单的统一API。 当使用大量类时,尤其是当它们使用复杂或难以理解时,此模式是理想的选择。当外观下的类可能会更改时,这也很有用,因为外观类可以保留相同的API事情在幕后发生变化。例如,如果您想替换后端服务的日子到了,您将不必更改使用API​​的代码,而只需更改Facade中的代码即可。 装饰器 装饰器模式可以动态地 向对象添加行为和职责,而无需修改其代码。 它是子类化的替代方法,在子类化中,您可以通过将类与另一个对象包装在一起来修改类的行为。 在Objective-C中,此模式有两种非常常见的实现: 类别和授权 。 在Swift中,此模式还有两种非常常见的实现: 扩展和委托 。 委托:用于将实现特定的行为排除在通用类之外。 iOS中的许多UI元素都使用委托来控制其行为,例如UIScrollView。 UIScrollView类不知道应该滚动什么,因为那是应用程序特定的任务。 因此,要通知应用程序滚动事件,它将使用UIScrollViewDelegate。 应用程序可以实现委托,然后拦截由UIScrollView发送给它的滚动事件。 纪念品 在Memento模式中, 可以将您的内容保存在某处 。 稍后,可以在不违反封装的情况下恢复此外部状态。 也就是说,私有数据保持私有。 Memento模式的实现示例是存档,序列化和 状态恢复 。 适配器 适配器设计模式将类的接口转换为客户期望的另一个接口 。 Adapter使类可以协同工作,否则由于接口不兼容而无法实现。 它将客户端与目标对象的类分离。 苹果使用协议来完成这项工作。 您可能熟悉UITableViewDelegate , UIScrollViewDelegate , NSCoding和NSCopying等NSCopying 。 例如,使用NSCopying协议,任何类都可以提供标准的copy方法。 观察者 观察者设计模式定义了对象之间的一对多依赖关系,因此当一个对象改变状态时,其所有依赖关系都会被通知并自动更新。 观察者模式本质上是一个发布和订阅模型,其中主题及其观察者是松散耦合的。 […]