Tag: 并发

掌握核心数据(第0部分)

#核心掌握数据 项目链接:https://github.com/aliakhtar49/Mastering-in-CoreData Twitter帐户:https://twitter.com/aliakhter49 Linkedin:https://www.linkedin.com/in/aliakhtar49 供讨论 https://ios-venturedive.slack.com/messages/CHE7CA7Q8/team/U67G7FYPM/? 内容正在审核中(进行中) 第1部分(简介) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-1-introduction-7c5d667bfabd 第2部分(核心数据栈) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-2-core-data-stack-ac447d3eb68c 第3部分(编码:核心数据中的CRUD) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-3-coding-crud-in-core-data-b7a278436c3 第4部分(第4部分,面向核心数据对象的CRUD) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-4-crud-in-core-data-object-oriented-style-a592439d7687 第5部分(核心数据中实体之间的关系) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-5-relationship-between-entities-in-core-data-b8fea1b50efb 第6部分(核心数据CRUD操作中的实体之间的关系) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-6-relationship-between-entities-in-core-data-crud-operation-87138fdf6fea 第7部分(核心数据关系删除规则) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-7-core-data-relationships-delete-rules-4798c6c0e762 第8部分(核心数据中的验证) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-8-validation-in-core-data-b38b8038e878 第9部分(NSFetchRequest) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-9-nsfetchrequest-d9ad991355d9 第10部分(NSFetchRequest) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-10-nsfetchrequest-a011684dd8f7 第11部分(多线程并发规则) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-11-multithreading-concurrency-rules-70f1f221dbcd 第12部分(多线程并发问题) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-12-multithreading-concurrency-problem-212a85f37930 第13部分(多线程并发策略通知) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-13-multithreading-concurrency-strategy-notifications-63ef0f110293 第14部分(多线程并发策略父级-子上下文) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-14-multithreading-concurrency-strategy-parent-child-context-305d986f1ac3 第15部分(父级多线程并发策略—儿童用例1) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-15-multithreading-concurrency-strategy-parent-child-use-case-1-12a180a6fc34 第16部分多线程并发策略父级-子用例2 https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-16-multithreading-concurrency-strategy-parent-child-use-case-2-bf7dd7e5245a 第17部分多线程并发策略上下文UndoManager https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-17-multithreading-concurrency-strategy-context-undomanager-d4a52138978a 第18部分使用核心数据的简单持久层架构 (进行中) 第18部分使用核心数据的高级持久层架构 (进行中) 第19部分:高级查询 (进行中) 第20部分核心数据中的错误 (进行中) 第21部分多个永久性商店 (进行中) 第22部分:多持久性存储协调器 (进行中) 第23部分:在App和Widget之间共享核心数据 (进行中) […]

使用启动参数在Xcode中进行核心数据调试

Core Data是Apple的对象图管理和持久性框架,适用于iOS,macOS,watchOS和tvOS。 它已经存在很长时间了,因此是在应用程序中持久存储结构化数据的绝佳解决方案。 尽管Xcode中一些鲜为人知的功能可以为您提供很多帮助,但是Core Data Debugging可能会有些困难。 “让您快速入门的一种好方法是观看有关核心数据的WWDC会议。” 为了更好地了解您的应用程序正在保存的内容,直接打开SQL数据库非常有用。 检索数据库位置的最简单方法是启用SQL调试输出: -com.apple.CoreData.SQLDebug 1 您可以在Xcode的方案编辑器中设置此参数以启用SQL Core Data Debugging: 级别可以设置为4,以实现更详细的输出级别。 它将使您深入了解已执行的提取请求,访问的属性或保存的数据,并且通常是核心数据调试的绝佳工具。 启动应用程序时,它还会向您显示sqlite数据库文件的位置: CoreData:注释:在以下位置连接到sqlite数据库文件:/ Users / antoinevanderlee / Library / Developer / CoreSimulator / Devices / AB66C5B9-D1C1-45C4-9324-DB0E91FAB4F9 / data / Containers / Shared / AppGroup / C6934424-5E58-4164-8593- 3CC0D60D2BB5 / Coyote.sqlite“ 可以使用相同的SQL调试启动参数来发现繁琐的查询或在应用中触发很多请求的位置。 WWDC 2018的核心数据最佳实践会议更详细地介绍了此技术。 核心数据旨在在多线程环境中工作。 但是,并非Core Data框架下的每个对象都是线程安全的。 要在多线程环境中使用Core Data,请确保: 受管对象上下文绑定到初始化时与之关联的线程(队列) 从上下文中检索到的受管对象被绑定到上下文所绑定到的同一队列 […]

Swift并行编程—第2/4部分

目标队列,调度组,屏障,工作项,信号量和调度源 本文是Swift并行编程的第2部分。 与第1部分一样,我们研究了Dispatch Queue和系统提供的队列。 在本文中,我将重点介绍另一种定义任务和GCD提供的强大API的方法。 如果要查看系列的所有部分: 并发和GCD — Swift并行编程— 1/4 GCD —使用Swift进行并行编程—第2/4部分 议程: 目标队列 调度组 DispatchWorkItem 派遣壁垒 DispatchSemaphore 派遣源 1.目标队列 定制调度队列不执行任何工作,它只是将工作传递给目标队列。 默认情况下,自定义调度队列的目标队列是默认优先级的全局队列。 从Swift 3开始,一旦调度队列被激活,就无法再对其进行更改。 可以通过setTarget(queue:)函数设置自定义队列的目标队列。 在激活的队列上设置目标将进行编译,但随后会在运行时引发错误。 幸运的是,DispatchQueue初始化程序接受其他参数。 如果出于某种原因仍然需要将目标设置在已创建的队列上,则可以使用iOS 10以来可用的initiallyInactive属性来实现。 DispatchQueue(标签:“队列”,属性:.initiallyInactive) 这将允许您修改它,直到激活它。 DispatchQueue类的activate()方法将使任务执行。 由于队列尚未被标记为并发队列,因此它们将以串行顺序运行。 为了使队列并发,我们需要指定: DispatchQueue(标签:“队列”,属性:[。initiallyInactive,.concurrent]) 您可以将任何其他调度队列(甚至是另一个自定义队列)传递给目标队列,只要您从未创建周期即可。 通过简单地将自定义队列的目标队列设置为其他全局队列,可以使用该功能设置自定义队列的优先级。 只有全局并发队列和主队列才能执行块。 所有其他队列必须(最终)以这些特殊队列之一为目标。 您可能已经在使用的Dispatch API或框架中注意到了目标队列。 我在RxSwift库中发现了目标队列的使用。 使用此实现,由于任务正在异步执行,因此很难在完成时获得通知。 这是DispatchGroup图片: DispatchGroup允许工作的聚合同步。 它可以用于提交多个不同的工作项或块,并跟踪它们何时全部完成,即使它们可能在不同的队列中运行。 唯一必要的事情是在调度组上均衡地调用enter()和leave() ,以使其同步我们的任务。 调用enter()以手动通知组任务已开始,并leave以通知工作已完成。 您也可以调用group.wait() ,它会阻塞当前线程,直到该组的任务完成为止。有两种方法来调用完成块: 使用wait()然后在主队列上执行完成块 呼叫组notify() wait(timeout:) 这将阻止当前线程,但是在指定的超时后,无论如何仍将继续。 […]

掌握CoreData(第16部分,多线程并发策略父级-子级用例2)

使用亲子策略放弃临时更改 在本部分中,我们将看到如何使用“父—子托管对象上下文”策略对UI临时更改核心数据对象。 首先下载启动项目。 注意:有关父级-子托管对象上下文策略,请参见第14和15部分。 当应用程序首次启动时,您将重定向到User屏幕,如图1所示。点击details按钮将执行两项任务。 首先,它将增加登录尝试(实体)计数器,然后将您重定向到“用户详细信息”屏幕,在该屏幕上将显示用户完整信息,用户可以在该屏幕中编辑信息,如图2所示。 图2是“用户详细信息”屏幕,用户可以在其中编辑其信息。 在背面,它移至上一个屏幕(用户屏幕),并放弃临时更改。 点击保存按钮将更新对核心数据的更改 项目结构 描述临时变更问题的项目结构如图3所示。 AppDelegate →负责创建核心数据堆栈。 ViewController→包含显示用户的逻辑,用户可以点击详细信息按钮以重定向到用户详细信息屏幕。 (用户画面) UserDetailViewController→包含用于显示来自Core Data的用户详细信息的逻辑以及用于在用户编辑信息后点击保存按钮时将更改保存到数据库的逻辑 TemporaryChanges.xcdatamodeld→包含两个实体 用户→包含属性firstname , lastName和id LoginAttempt→包含属性计数 问题 首次启动应用程序时,具有firstname和lastname用户(如果不存在)将保存到持久性存储中,并且其f firstname将显示在标签上,如图4所示。 现在,当您点击详细信息按钮时,它将执行两项任务 它将LoginAttempt count属性增加到+1,并通过调用save方法将其保存到持久性存储中 使用情节提要segue重定向到详细信息屏幕 现在点击“用户”屏幕上的“ 详细信息”按钮,它将重定向到用户详细信息屏幕,如图6所示。在此屏幕中,显示了用户详细信息。 用户可以通过单击保存按钮来更新其信息并将其保存到数据库中,也可以通过单击后退按钮放弃其临时更改。 更改用户详细信息,如图7所示,我们将firstname从Ali更改为Ali temp并且还更新了lastname 当用户在任何文本字段上键入内容时,它将更新NSMangedObject类型的User核心数据对象,该对象是控制器的实例属性。 现在,当用户完成firstname文本字段时,此更新也将反映到位于上下文中的user对象 众所周知, User对象是在主线程上下文中填充的,当我们执行临时更改时,它将在上下文中更新该对象,并且当我们点击后退按钮时,更新的值仍然存在于上下文中。 现在,点击后退按钮后,将出现用户屏幕。 我们知道,当我们点击详细信息按钮时,它将首先增加计数器并通过调用save方法来调用save方法,这还将把用户临时更改也推送到永久存储,并使用更新后的值重定向到User Detail屏幕。 由于受管对象上下文是单例对象save方法,因此会将临时更改推送到持久性存储 正如您在更新的屏幕中看到的那样,显示用户临时更改。 问题是,当用户执行后退按钮时,我们需要放弃更改。 我们可以通过三种方式做到这一点 使用父级—子级策略(此部分的封面) 撤消经理(下一部分) 手动跟踪更改(不会涵盖) 使用流程图了解问题 如您在图11中看到的,当应用程序首次启动时,用户信息将存储到持久性存储中。 当您点击详细信息按钮时,它将显示直接与UI交互的主要上下文中的用户详细信息 现在,用户在用于填充“用户详细信息”屏幕的直接coredata实体上编辑信息并更新其信息。 那时,由于User Detail使用核心数据用户对象(主要上下文中)填充其视图。 这种变化也将反映到上下文中。 […]

掌握CoreData(第15部分,多线程并发策略父级-子级用例1)

使用父子上下文解决了实际问题 托管对象上下文是用于处理托管对象的内存暂存器。我们使用多个托管对象上下文来执行两种类型的任务。 1)对于前面部分中讨论的长时间运行的任务。 在这一部分中,我们将在实际应用中执行此操作 2)在其他情况下,例如在对用户数据进行编辑时,将托管对象上下文视为一组更改即可很有用,如果应用程序不再需要它们,则可以将其丢弃。 使用子上下文使这成为可能。 在下一部分中,我们将介绍 在本教程中,您将通过使用GooglePlayViewerApp应用程序来使用多个托管对象上下文,并通过添加多个上下文以几种方式对其进行改进。 入门 该教程入门项目是一个Google Play查看器应用程序,用于演示。当应用程序首次启动时,您将重定向到登录屏幕,如图1所示。单击Export时,会将47472 google play应用程序数据加载到Core Data中。 点击“登录”按钮后,它将重定向到列表屏幕,其中将显示所有应用程序名称,如图2所示。 项目结构 在图3中显示了项目结构的屏幕截图 ViewController →负责登录屏幕任务。 它具有点击导出和登录按钮的操作方法。 点击登录按钮时,它将重定向到列表屏幕。 点击导出按钮,它将把csv文件中的数据加载到核心数据中,并将其保存到持久性存储中。 googleplaystore.csv→包含所有Google Play应用信息,总计47472 ,如图4所示。 GooglePlayListViewController →负责显示来自Google Play应用的列表。 它从核心数据中获取数据并在表格视图中显示。 AppDelegate→负责创建Core数据堆栈。 GooglePlayViewerApp.xcdatamodeld→包含Google play实体架构和配置 转到GooglePlayViewerApp.xcdatamodeld →选择Google Play实体,如图5所示,包含Google Play csv数据所需的所有属性 观察/问题 确保首先删除该应用程序。 运行该应用程序,将出现登录屏幕。 点击文本框并开始输入,它可以正常工作。 现在,点击导航栏左上方的导出按钮,立即再次开始键入,您将看到UI挂起。 导出操作需要几秒钟,并且会阻止UI响应诸如键入之类的交互事件。 怎么了 如图7所示,由于此应用程序仅使用一个托管对象上下文 ,该上下文将csv数据填充到主线程上的Core Data中。 当您点击“导出”按钮时,将发生以下情况 将包含47472数据的csv文件的所有内容加载到主线程的data变量中 获取在主线程上创建的托管对象上下文引用 在主上下文上创建了GooglePlay CoreData实体,并填充其属性 将数据推送到持久性存储 正如您在图7控制台日志中看到的那样,大约6秒的应用程序主线程将被此任务阻塞,您可以想象当应用程序冻结将近6秒时,用户的反应是什么 使用并发提高性能 […]

掌握CoreData(第11部分:多线程并发规则)

假设您是在首次启动应用程序时将数百个或数千个主线程上的记录从捆绑数据导入Core Data中的? 结果可能是戏剧性的。 例如,您的应用程序可能由于启动时间太长而被Apple的监视程序杀死,这会显着降低UI性能,甚至可能导致其完全冻结,这不是良好的用户体验。 使用并发,您可以将任务导入其他线程,从而使您的主线程空闲,并且用户可以在不知道后台任何内容的情况下进行交互。 核心数据并发 并发是同时处理多个队列上的数据的能力。 提交到这些队列的工作在线程上执行。 核心数据,多线程和主线程 在核心数据中,作为核心数据堆栈核心的托管对象上下文可以与两种并发模式一起使用,这两种并发模式由NSMainQueueConcurrencyType和NSPrivateQueueConcurrencyType定义。 NSMainQueueConcurrencyType 专用于与您的应用程序界面一起使用,并且只能在始终在主线程上运行的应用程序的主队列中使用。 如前所述,它只能在与应用程序界面(UI)相关的工作中使用。 避免对此进行数据处理 。 ,就像将数据从JSON导入Core Data一样 NSPrivateQueueConcurrencyType 配置在初始化时创建自己的队列,并且只能在该队列上使用。 因为该队列是私有的,并且在NSManagedObjectContext实例内部,所以只能通过performBlock: 和 performBlockAndWait :方法对其进行访问。 在进行编码部分时,我们将对此进行深入研究。 零件中使用了 什么托管对象上下文 让managedObjectContext = appDelegate.persistentContainer.viewContext 以前,我们非常频繁地使用上述代码,并且我们从persistentContainer实例属性viewContext获取上下文。 顾名思义,其并发类型应为NSMainQueueConcurrencyType。 使用NSPersistentContainer时,viewContext属性被配置为NSMainQueueConcurrencyType上下文 PersistentContainer还具有两种方法 performBackgroundTask:和newBackgroundContext,与之关联的上下文被配置为NSPrivateQueueConcurrencyType。 核心数据旨在在多线程环境中工作。 但是,并非Core Data框架下的每个对象都是线程安全的。 要在多线程环境中使用Core Data,请确保: 受管对象上下文绑定到初始化时与之关联的线程(队列) 从上下文中检索到的受管对象被绑定到上下文所绑定到的同一队列 (将通过本节中的代码看到这两点) 规则1 受管对象上下文绑定到初始化时与之关联的线程(队列)。 转到目标→编辑方案→参数→添加参数“ -com.apple.CoreData.ConcurrencyDebug 1 ”,如图2和3所示。我们只是启用了Core Data Concurrency Debugging 如您在图4中看到的,我们正在打破这一规则。 我们正在使用在其他线程的主线程上创建的托管对象上下文。 我们通过执行许多任务来完成此任务 首先使用持久容器 […]

iOS派遣组

通常,在iOS应用程序中,我们会尝试为应用程序提供功能,使其能够同步​​由于网络故障而无法发送的某些请求。 一个快速的实现是在UserDefaults中缓存一些简单的String,或者缓存其中的数组。 在应用程序变为活动状态期间,您可以尝试运行DispatchGroup() 这只是我的一个简单发现,即快速,轻松且易读 想象一下,如果您有一系列要发送给请求的帖子,并且只想在所有请求都完成后才希望获得回调,那么您可以通知用户脱机帖子已经发送,并且可以清理缓存。 令group = DispatchGroup()for in in 0 .. <n { group.enter() //这是一个示例伪代码 //不是完全运行的代码 MyNetworkClass.request(){在 group.leave() } } group.notify(队列:.main){ 打印(“所有请求都已完成”) } 因此,使用此示例代码片段,您可以将其抽象为实用程序功能,以处理应用程序中缓存项的发送,并在所有请求完成后进行清理

大中央调度#1

自推出以来,Grand Central Dispatch已成为Apple平台上并发编程的最终解决方案。 GCD同时执行代码,提供调度和同步功能,并与语言功能和API无缝集成。 GCD提供并管理应用可以向其提交任务的队列。 这种抽象隐藏了线程管理,并专注于构建任务序列。 GCD是Objective-C的一项现代功能,它提供了一组丰富的方法和API,可用于支持常见的多线程任务。 它提供了一种将任务排队以进行调度的方法: 主线程“只有一个线程是主线程,所有其他线程都是背景” 并发队列(并行运行) 或串行队列(以FIFO顺序运行) 我们可以创建自己的线程,但这可能会导致很多问题。 在将任务分配给GCD或工序队列时 ,系统将自行管理线程。 我们可以创建多个任务并将其分配给队列。 每个任务分为多个单元,每个单元由可用线程执行。 系统将任务分解为多个单元并将其分配给线程。 并发问题 (使用GCD或操作队列可以避免前两个问题 ): 竞争条件 :两个线程试图同时访问一个资源(变量或内存中的数据结构) 。 Xcode中的Thread Sanitizer可以为我们进行管理。 假设您在后台线程中访问变量时更改了主线程中的变量! 2.当高优先级工作依赖于低优先级工作时, 优先级反转将一直停止,直到低优先级完成所需的工作,然后恢复。 3.死锁 Xcode中的调试导航 器可区分线程, 时间分析器记录不同线程上的活动,而线程清理程序可帮助捕获线程违规。 信用