如何在 Core Data 中对 NSManagedObject 进行深拷贝 请访问我的博客 www.fatbobman.com[1] 以获得更好的阅读体验 。 对 NSMangedObject 进行深拷贝的含义是为一个 NSManagedObject(托管对象)创建一个可控的副本,副本中包含该托管对象所有关系层级中涉及的所有数据。 本文中将探讨在 Core Data 中对 NSManagedObject 进行深拷贝的技术难点、解决思路,并介绍我写的工具——MOCloner[3]。 对 NSManagedObject 进行深拷贝的难点 复杂的关系结构 下图是 健康笔记[4] 的数据模型图节选。 entity 这些 Description 是开发 NSManagedObject 深拷贝通用代码的基石。
为什么要用NSManagedObject子类 这时候其实可以进行数据的增删查改了。 但是这时候赋值(或者修改)一条数据,都是通过NSManagedObject类实例进行的(我们创建的实体,都是NSManagedObject类型的),类似如下: NSManagedObject *newUser 所以,我们通常都会创建NSManagedObject的子类,用点语法直接进行存取操作。 如何创建NSManagedObject子类 创建NSManagedObject子类,有如下两种办法 方法1:直接Command + N创建一个新类,继承NSManagedObject类,然后定义的属性和模型文件中的一致 方法2:选中对应的实体,然后Editor > Create NSManagedObject Subclass...,系统自动生成NSManagedObject子类。
生成实体对应的 NSManagedObject 子类声明 在绝大多树情况下,开发者都会为 Entity 创建对应的 NSManageObject 子类声明。 例如: @objc(Item) public class Item: NSManagedObject {} extension Item { @nonobjc public class func 这是因为 Core Data 也提供了一种轻量级的方式来访问和操作托管对象,即使用 NSManagedObject 对象本身来进行属性访问和操作。 创建托管对象实例的关键并不在于是否有托管对象上下文,而在于告诉 NSManagedObject,该实例对应的是哪个 EntityDescription。 通过使用正确的 EntityDescription,我们可以创建 NSManagedObject 实例,在许多场景下可以达到同样的效果。
三、创建实体类 利用可视化创建了实体,但是我们要想获取对应的数据和名称,就必须关联类,因此要创建实体类,创建步骤如下: 1、选中 .xcdatamodeld 文件通过 Editor 创建:NSManagedObject 四、手动创建CoreData的使用 值得注意的是:下面的例子中我们可以直接使用创建的目的实体类如:Dog,也可以使用NSManagedObject 这一公共实体类,可以使用KVC赋值,也可以使用 . 2、增:增加数据 /** 增加数据 */ -(void)addData{ //传入上下文,创建一个Person实体对象: NSManagedObject *person = 然后你很容易再重复手动创建NSManagedObject子类,这时候就会报类似「duplicate symbol _OBJC_METACLASS_Photography in:...」这类错误。 所以,如果你想自己手动创建NSManagedObject子类,就要把系统预设的Class/Definition改为Manual/None。
不推荐使用 setPrimitiveValue(value:, forKey:)、value(forKey:) 等方式读写 NSManagedObject 属性数据,缺乏编译检查。 将 PersistentModel 转换为 NSManagedObject,实现子查询 在 Core Data 中,开发者可以通过创建子查询(SubQuery)谓词,直接在 SQLite 端实现嵌套查询 通过将 PersistentModel 转换成 NSManagedObject,我们可以用包含子查询的谓词提高效率: func getCollectCountByCategoryByKit(categoryName 将 NSManagedObject 转换为 PersistentModel 有人可能会问,我们只能用 SwiftDataKit 返回统计数据吗? 是否可以将 NSFetchRequest 获取的 NSManagedObject 转换为 PersistentModel 在 SwiftData 中使用?
一、CoreData结构 可以用两张图来表示: NSManagedObject 数据库对象,一个NSManagedObject对应一张表,NSManagedObject的一个属性对应数据表的一个字段 数据库的增删查改就是操作NSManagedObject,通过xCode->Editor->Create NSManagedObject Subclass…来创建对应表的对象model NSManagedObjectContext NSManagedObject操作的上下文,NSManagedObject的操作会先缓存在上下文中,还未存到磁盘中 - (NSManagedObjectContext *)managedObjectContext 用以主线程的上下文 defaultContext的父context是rootContext:RootSavingContext,可以看出MagicRecord默认用的是第二种模式,很简单就可以新建一个NSManagedObject
// Computed property to access the NSManagedObject var managedObject: NSManagedObject? 同样,如果用 SwiftDataKit 直接改写 PersistentModel 底层对应的 NSManagedObject 实例的持久化属性,也不会产生通知。 直接使用该方法将导致底层 NSManagedObject 的数据与表层 PersistentModel 数据不一致。 的一个属性对应到 NSManagedObject 的多个属性(当属性为复杂类型时),以及线程调度(确保线程安全)等任务。 isDeleted:表示是否已添加到 ModelContext 的删除列表,与 NSManagedObject 的同名属性功能类似。
如果是查询的话,因为 NSManagedObject 也不能跨线程访问,所以在block里获取到的NSManagedObject对象只能将objectid传到主线程,主线程再通过 objectWithID
文件代码如下:Copy codeCoreData.swift// Beforeimport Foundationimport CoreData@objc(Track)public class Track: NSManagedObject // After@objc(Track)public class Track: NSManagedObject, Identifiable { @nonobjc public class func removeArtists:) @NSManaged public func removeFromArtists(_ values: NSSet)}@objc(Artist)public class Artist: NSManagedObject self.jsonDecoder.decode(Song.self, from: jsonData) let artists: [NSManagedObject [] track.setValue(Set<NSManagedObject>(artists
//完成Entity模型的创建之后,接着来创建一个托管对象类 NSManagedObject。在项目名称文件夹上点击鼠标右键,然后选择菜单 中的【New File……】命令。 在弹出的文件模板选择窗口中,依次选择 【Core Data>NSManagedObject subclass】选项,创建一个 NSManagedObject的子类 image.png //然后点击 【Next】按钮,并在接下来的选择待管理的实体页面中选 中【User】实体,从而创建一个名为User的NSManagedObject子类和名 为User+CoreDataProperties.siwft
不推荐使用 setPrimitiveValue(value:, forKey:)、value(forKey:) 等方式读写 NSManagedObject 属性数据,缺乏编译检查。 将 PersistentModel 转换为 NSManagedObject,实现子查询 在 Core Data 中,开发者可以通过创建子查询(SubQuery)谓词,直接在 SQLite 端实现嵌套查询 通过将 PersistentModel 转换成 NSManagedObject,我们可以用包含子查询的谓词提高效率: func getCollectCountByCategoryByKit(categoryName 将 NSManagedObject 转换为 PersistentModel 有人可能会问,我们只能用 SwiftDataKit 返回统计数据吗? 是否可以将 NSFetchRequest 获取的 NSManagedObject 转换为 PersistentModel 在 SwiftData 中使用?
给它起一个名称,并以第一个模型版本为基础:现在,让我们创建 Artist 实体并添加所有字段:也让我们为新的 Artist 实体创建 NSManagedObject 子类,Artist.swift 代码如下 :Copy codeimport Foundationimport CoreData@objc(Artist)public class Artist: NSManagedObject, Identifiable 现在,让我们为 Track 实体添加缺失的关系,并删除 artistName 和 json 属性:并更新 NSManagedObject 子类以反映更改,Track.swift 文件代码如下:import Foundationimport CoreData@objc(Track)public class Track: NSManagedObject, Identifiable { @nonobjc decoder.decode(Song.self, from: jsonData) // 4 let artists: [NSManagedObject] =
Core Data架构 一个基本的 Core Data 栈由四个主要部分组成:托管对象 (NSManagedObject),托管对象上下文 (NSManagedObjectContext),持久化存储协调器 image.png NSManagedObject是我们的数据模型,也就是我们存储的对象。这些对象都保存在NSManagedObjectContext中,每个存储对象都知道自己对应哪个上下文。 [NSManagedObject] if let results = fetchedResults { people = results NSEntityDescription.entity(forEntityName: "Person", in: managedObectContext) let person = NSManagedObject
这些类都是一些抽象的结构类,并不存储实际每条数据的信息,具体的数据由NSManagedObject类来描述,我们一般会将实体类化继承于NSManagedObject。 Xocde工具提供了快捷的实体类化功能,还拿我们一开始创建的班级与学生实体来演示,点击.xcdatamodeld文件,点击Xcode工具上方导航栏的Editor标签,选择Creat NSManagedObject
(entity)是数据模型的基石 一个实体表示应用程序中有意义的一部分数据 可以把实体看待成 SQLite 中的一个表,或者数据模型 创建实体对应的代码文件 选择菜单 Editor / Create NSManagedObject show in Finder —>在test文件夹下新建一个DataModel文件夹 —>将文件夹拖入到项目的文件列表中 2、选择xcddatamodeld->选择菜单 Editor / Create NSManagedObject (entity)是数据模型的基石 一个实体表示应用程序中有意义的一部分数据 可以把实体看待成 SQLite 中的一个表,或者数据模型 创建实体对应的代码文件 选择菜单 Editor / Create NSManagedObject show in Finder —>在test文件夹下新建一个DataModel文件夹 —>将文件夹拖入到项目的文件列表中 2、选择xcddatamodeld->选择菜单 Editor / Create NSManagedObject
其中,开发者接触最频繁、使用量最大的托管对象上下文(NSManagedObjectContext)和托管对象(NSManagedObject)恰好都不是线程安全的。 Button("NSManagedObject in wrong context"){ // 视图运行在主线程 let backgroundContext = PersistenceController.shared.container.newBackgroundContext await context.perform { // 调整回 context 队列(本例中为主队列) context.reset() } }}Button("NSManagedObject 通过 NSManagedObject 来查找上下文 在某些情况下,只能获得托管对象(NSManagedObject),通过从中获取托管对象上下文,保证在正确的队列中对其操作。 bgContext.save() }} 或者仍采用 NSManagedObject 为参数 func delItem(item:Item) { let id = item.objectID
1.3 CoreData操作对象 1.3.1 NSManagedObject > Managed Object - NSManagedObject Managed Object 表示数据文件中的一条记录 Managed objects must be instances of either NSManagedObject or of a subclass of NSManagedObject. NSManagedObject is able to represent any entity. 你可能会采取批处理的方式,即一小批一小批的更新NSManagedObject并保存到 NSManagedObjectContext 中,但这样会花费很多时间,用户体验较差。 一旦有非法数据录入数据库,下次加载并修改 NSManagedObject 的时候就会导致数据验证失败。
user.userName; cell.detailTextLabel.text = [NSString stringWithFormat:@"%@", @(user.userID)]; // 如果没有自定义NSManagedObject 子类,就应该类似:NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath]; 监视数据的变化 选择Transformable,然后重写get、set方法,进行转换……还是用上面的方法吧,比较简单:) 自定义对象 自定义对象,也有两种思路: 直接定义成xcdatamodeld文件中的一个实体,作为NSManagedObject
,处理数据与应用的交互 NSManagedObjectModel 被管理的数据模型,数据结构 NSPersistentStoreCoordinator 添加数据库,设置数据存储的名字,位置,存储方式 NSManagedObject (^)(NSManagedObjectContext *))block; 5.增删改查排 写入数据 // 1.根据Entity名称和NSManagedObjectContext获取一个新的继承于NSManagedObject insertNewObjectForEntityForName:@"Student" inManagedObjectContext:_context]; //2.根据表Student中的键值,给NSManagedObject
,处理数据与应用的交互 NSManagedObjectModel 被管理的数据模型,数据结构 NSPersistentStoreCoordinator 添加数据库,设置数据存储的名字,位置,存储方式 NSManagedObject (^)(NSManagedObjectContext *))block; 5.增删改查排 写入数据 // 1.根据Entity名称和NSManagedObjectContext获取一个新的继承于NSManagedObject insertNewObjectForEntityForName:@"Student" inManagedObjectContext:_context]; //2.根据表Student中的键值,给NSManagedObject