四月芳菲 發表於 2024-7-22 14:55:00

iOS开发基础135-Core Data

<p>Objective-C (OC) 中使用 Core Data 是iOS应用开发中管理模型层对象的一种有效工具。Core Data 使用 ORM (对象关系映射) 技术来抽象化和管理数据。这不仅可以节省时间,还能减少编程错误。以下是使用 Core Data 的详细介绍,包括示例代码,以及深入底层的一些分析。</p>
<h3 id="基本概念">基本概念</h3>
<ol>
<li>
<p><strong>持久化容器 (<code>NSPersistentContainer</code>):</strong> iOS 10 引入的,封装了 Core Data 栈的设置,包括托管对象模型 (<code>NSManagedObjectModel</code>),持久化存储协调器 (<code>NSPersistentStoreCoordinator</code>),和上下文 (<code>NSManagedObjectContext</code>)。</p>
</li>
<li>
<p><strong>托管对象模型 (<code>NSManagedObjectModel</code>):</strong> 描述应用的数据模型,包括实体(Entity)和这些实体之间的关系。</p>
</li>
<li>
<p><strong>持久化存储协调器 (<code>NSPersistentStoreCoordinator</code>):</strong> 负责协调托管对象上下文和持久化存储。</p>
</li>
<li>
<p><strong>上下文 (<code>NSManagedObjectContext</code>):</strong> 用于在内存中管理对象。执行创建、读取、更新、删除操作时,这些更改暂时只发生在上下文中,直到保存更改到持久层。</p>
</li>
</ol>
<h3 id="使用示例">使用示例</h3>
<p>以下是一个简单的使用 Core Data 创建和查询对象的示例:</p>
<h4 id="步骤-1-配置数据模型">步骤 1: 配置数据模型</h4>
<p>首先,通过 Xcode 的 Data Model Editor 创建数据模型文件(<code>.xcdatamodeld</code>)。假设定义了一个 <code>Person</code> 实体,有 <code>name</code> 和 <code>age</code> 两个属性。</p>
<h4 id="步骤-2-设置持久化容器">步骤 2: 设置持久化容器</h4>
<p>在 AppDelegate 中设置持久化容器:</p>
<pre><code class="language-objective-c">#import &lt;CoreData/CoreData.h&gt;

@interface AppDelegate : UIResponder &lt;UIApplicationDelegate&gt;

@property (readonly, strong) NSPersistentContainer *persistentContainer;

- (void)saveContext;

@end

@implementation AppDelegate

@synthesize persistentContainer = _persistentContainer;

// 懒加载 persistentContainer
- (NSPersistentContainer *)persistentContainer {
    // 如果容器已经被初始化了,直接返回
    if (_persistentContainer != nil) {
      return _persistentContainer;
    }
   
    // 使用名为 MyModel 的模型文件创建容器
    _persistentContainer = [ initWithName:@"MyModel"];
    [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
      if (error != nil) {
            // 错误处理,实际应用中应该替换为更合适的错误处理
            NSLog(@"Unresolved error %@, %@", error, error.userInfo);
            abort();
      }
    }];
    return _persistentContainer;
}
@end
</code></pre>
<h4 id="步骤-3-使用-core-data-新增和查询">步骤 3: 使用 Core Data 新增和查询</h4>
<p>在合适的地方(如 ViewController)进行数据的新增和查询:</p>
<pre><code class="language-objective-c">#import "AppDelegate.h"
#import &lt;CoreData/CoreData.h&gt;

- (void)insertNewPersonWithName:(NSString *)name age:(int)age {
    AppDelegate *appDelegate = (AppDelegate *)[ delegate];
    NSManagedObjectContext *context = appDelegate.persistentContainer.viewContext;
   
    // 创建新的 Person 实体对象
    NSManagedObject *newPerson = ;
    ;
    ;
   
    NSError *error = nil;
    // 保存到持久层
    if (!) {
      NSLog(@"保存失败: %@, %@", error, error.userInfo);
    }
}

- (NSArray *)fetchPersons {
    AppDelegate *appDelegate = (AppDelegate *)[ delegate];
    NSManagedObjectContext *context = appDelegate.persistentContainer.viewContext;
   
    NSFetchRequest *fetchRequest = ;
   
    NSError *error = nil;
    NSArray *results = ;
    if (!results) {
      NSLog(@"查询失败: %@, %@", error, error.userInfo);
    }
    return results;
}
</code></pre>
<h3 id="深入分析">深入分析</h3>
<p>Core Data 的底层使用了 SQLite 作为默认的持久化方式(尽管你可以选择内存或者自定义解决方案),但开发者无需直接与数据库交互,所有的操作都是通过上述的对象和 API 完成。Core Data 框架负责转换这些操作为 SQLite 命令并执行。</p>
<h4 id="core-data-性能优化">Core Data 性能优化</h4>
<ul>
<li>
<p><strong>批量请求:</strong> iOS 8 引入了批量删除和更新,这样可以在不加载数据到内存的情况下直接在持久层执行操作,极大提升效率。</p>
</li>
<li>
<p><strong>预获取:</strong> 对于频繁访问的关联对象,可以使用预获取来减少查询次数。</p>
</li>
<li>
<p><strong>轻量级迁移:</strong> 对于数据模型的更改,通过轻量级迁移避免手动处理数据结构变动。</p>
</li>
</ul>
<h3 id="封装">封装</h3>
<p>对于Core Data的使用,进行二次封装可以提高代码的复用性,让外部调用变得更加简洁。我们可以创建一个单例类<code>CoreDataManager</code>来管理Core Data的常见操作,比如增删改查。</p>
<p>首先,你需要确保你的数据模型(.xcdatamodeld文件)已经设置好,举个例子,这里假设我们有一个<code>Person</code>的Entity,它有两个属性:<code>name</code>(String类型)和<code>age</code>(Int16类型)。</p>
<h3 id="步骤-1-创建core-data管理类">步骤 1: 创建Core Data管理类</h3>
<pre><code class="language-objective-c">#import &lt;Foundation/Foundation.h&gt;
#import &lt;CoreData/CoreData.h&gt;

@interface CoreDataManager : NSObject

@property (readonly, strong) NSPersistentContainer *persistentContainer;
+ (instancetype)sharedManager;
- (void)saveContext;
- (void)insertPersonWithName:(NSString *)name age:(NSNumber *)age completion:(void(^)(BOOL success, NSError *error))completion;
- (void)fetchAllPersons:(void(^)(NSArray *persons, NSError *error))completion;

@end

@implementation CoreDataManager

+ (instancetype)sharedManager {
    static CoreDataManager *sharedManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&amp;onceToken, ^{
      sharedManager = [ init];
    });
    return sharedManager;
}

- (NSPersistentContainer *)persistentContainer {
    @synchronized (self) {
      if (_persistentContainer == nil) {
            _persistentContainer = [ initWithName:@"YourModelName"];
            [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                if (error != nil) {
                  NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                  abort();
                }
            }];
      }
    }
    return _persistentContainer;
}

- (void)saveContext {
    NSManagedObjectContext *context = self.persistentContainer.viewContext;
    NSError *error = nil;
    if ( &amp;&amp; !) {
      NSLog(@"Unresolved error %@, %@", error, error.userInfo);
      abort();
    }
}

- (void)insertPersonWithName:(NSString *)name age:(NSNumber *)age completion:(void(^)(BOOL success, NSError *error))completion {
    NSManagedObjectContext *context = self.persistentContainer.viewContext;
    NSManagedObject *newPerson = ;
    ;
    ;
   
    NSError *error = nil;
    if (!) {
      NSLog(@"Error saving context: %@, %@", error, error.userInfo);
      completion(NO, error);
    } else {
      completion(YES, nil);
    }
}

- (void)fetchAllPersons:(void(^)(NSArray *persons, NSError *error))completion {
    NSManagedObjectContext *context = self.persistentContainer.viewContext;
    NSFetchRequest *fetchRequest = ;
   
    NSError *error = nil;
    NSArray *results = ;
    if (error) {
      NSLog(@"Failed to fetch persons: %@, %@", error, error.userInfo);
      completion(nil, error);
    } else {
      completion(results, nil);
    }
}

@end
</code></pre>
<h3 id="使用封装的coredatamanager">使用封装的CoreDataManager</h3>
<p>这里展示如何使用<code>CoreDataManager</code>进行数据操作:</p>
<pre><code class="language-objective-c">// 插入新的Person对象
[ insertPersonWithName:@"John Doe" age:@25 completion:^(BOOL success, NSError *error) {
    if (success) {
      NSLog(@"Person added successfully");
    } else {
      NSLog(@"Failed to add person: %@", error.localizedDescription);
    }
}];

// 获取所有的Person对象
[ fetchAllPersons:^(NSArray * _Nonnull persons, NSError * _Nonnull error) {
    if (error) {
      NSLog(@"Failed to fetch persons: %@", error.localizedDescription);
    } else {
      for (NSManagedObject *person in persons) {
            NSString *name = ;
            NSNumber *age = ;
            NSLog(@"Fetched person: %@, age: %@", name, age);
      }
    }
}];
</code></pre>
<p>通过上面的封装,我们只需调用简单的方法就可以完成对<code>Person</code>对象的增删改查操作,而不用关心Core Data的具体实现细节。这大大提高了代码的可读性和可维护性。</p>
<h3 id="总结">总结</h3>
<p>Core Data 是一个功能强大的框架,通过封装复杂的底层细节,使得数据管理变得更加简单。高效地使用 Core Data 必须理解其背后的原理,并遵循最佳实践来设计应用。</p>


</div>
<div id="MySignature" role="contentinfo">
    将来的你会感谢今天如此努力的你!
版权声明:本文为博主原创文章,未经博主允许不得转载。<br><br>
来源:https://www.cnblogs.com/chglog/p/18316000
頁: [1]
查看完整版本: iOS开发基础135-Core Data