斯坦福大学iOS开发公开课总结(十二 & 十三) :Core Data,表格视图,Flickr 摄影师资料列表Demo

第十二课和第十三课都介绍了CoreData的知识,并在十三课的中段通过一个Demo来具体实现了CoreData的操作。

笔者之前从未接触过Core Data的相关知识,因此学期这两节课比较吃力,这一篇总结还是有很多需要改进的地方,以后随着对Core Data认识的深入和对这两节课的反复咀嚼,会不断更新该总结。

开始吧!

Core Data


Core Data是一种持久化技术,它能将模型对象的状态持久化到磁盘,但它最重要的特点是:Core Data不仅是一个加载、保存数据的框架,它还能和内存中的数据很好的共事。

排除错误认识:Core Data并不是数据库! 它只是连接类(Class)和数据库(SQL)的桥梁。通过Core Data的相关功能,我们可以对数据库进行增删改查的操作。

CoreData是如何工作的呢?

1. 创建对象的可视化映射

在看到可视化映射之前,需要了解实体的概念:

实体的概念:每个实体是一个表,每个表对应一个对象。
简单粗暴的理解:实体在数据库领域叫做表,在面向对象领域叫做对象。

实体之间的关系=表之间创建关系,对象之间的关系。

注意:两个对象之间的关系在两个对象端具有不同的名称。而且关系的对应数量也是不同的:to one,to many

举个🌰 :摄影者和照片的关系:
摄影者对应多个照片,但是照片只对应一个摄影者。

那么言归正传,如何创建对象的可视化映射呢?

  1. 创建模型文件,用来装入各种需要映射的实体。
  2. 在模型内部添加实体(Entity),创建实体之间的关系(必要时)。

下面笔者录制了创建实体,增加实体属性,连接实体的操作:

创建实体,增加属性

2. 为实体创建NSManagedObjectd子类

我们需要将刚得到的可视化的实体“转变为”具体的类。在Core Data中,这些类都是NSManagedObjectd子类。

下面演示一下其创建过程:

创建NSManagedObjectd子类

以实体Photo为例,系统为我们生成了Photo.hPhoto.m

我们先看一下Photo.h:


#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

NS_ASSUME_NONNULL_BEGIN
@interface Photo : NSManagedObject
// Insert code here to declare functionality of your managed object subclass
@end
NS_ASSUME_NONNULL_END
#import "Photo+CoreDataProperties.h"

我们可以看到,Photo类继承了NSManagedObject

但是,有意思的是,系统还为我们自动生成了Photo+CoreDataProperties.hPhoto+CoreDataProperties.m,详情见动图左侧,创建实体类之后。

思考
生成这两个文件的目的是什么呢?
首先,我们首先要知道这两个文件是什么:
他们构成了Photo类的分类(Category)。

那么什么是分类呢?
通过分类,我们可以向原有的类添加方法,而不需要通过继承的方式。分类的局限是:在分类里不能再添加属性。

那么显然,通过````Photo+CoreDataProperties,我们就可以不用继承Photo类来给其添加方法。因为原有的Photo```类只具有属性,除了获取属性之外,并不能为我们做其他的事情。这时,如果可以在其他的地方给其无限地添加方法还是很具有诱惑力的。令人欣慰的是,系统可以自动为我们生成。

3. 通过创建NSManagedObjectContext访问,操作数据库

数据库创建对象,设置对象属性,查询对象都需要NSManagedObjectContext

创建NSManagedObjectContext的两个不同的方法:

1.通过其自身的初始化:

[NSManagedObjectContext alloc] init];

2.通过UIManagedDocument创建:

UIManagedDocument 用于管理存储的机制,将Core Data数据库放入某存储空间。

UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:url];
//url:这个core data 数据库存储的地方

数据库的操作:

1. 向数据库添加对象(实体):

[NSEntityDescription insertNewObjectForEntityForName:@"Photo" inManagedObjectContext:context];

2. 从数据库删除对象(实体):

[aDocument.managedObjectContext deleteObject:photo];

删除对象后,系统会向所有对象发送这个消息

- (void)prepareForDeletion{
 //在这里保持数据同步,比如删掉这个对象的时候会影响到其他对象的数据
 //应该在这个对象被删除前及时更新那个数据
}

3. 在数据库查询对象(实体):

我们使用NSFetchRequest类查询数据库的对象,通过设置其不同属性来查找符合不同标准的数据:

举个🌰 :查找出100个photo的实体:

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Photo"];
request.fetchLimit = 100;

关于Core data的线程安全

//让context在安全队列中执行的方法
[context performBlock:^{
    [A doSomething];
}];

NSFetchedResultsController


NSFetchedResultsController的作用是将NSFetchRequest 和 UITalbleView联系到一起。
和TableView的数据源方法类似:

- (NSInteger)numberOfRowsInSection:(NSInteger)section{
  return [[self.fetchedResultsController sections] count];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
   return [[self.fetchedResultsController sections] count] objectAtIndex:section] numberOfObjects];
}

详细的使用方法会在Demo讲解部分中告诉大家。

Demo


Demo需求

  • 每隔20分钟,从flickr拿回最新的摄影者数据。
  • 用一个TableView显示当前拿回的摄影者的名字和所照的照片数。

Demo效果图

摄影师的信息列表

重要代码段

1. 在启动接口获取flickr的数组


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     self.photoDatabaseContext = [self createMainQueueManagedObjectContext];    
     [self startFlickrFetch];   
     return YES;
}

- (void)startFlickrFetch
{
    [self.flickrDownloadSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        if (![downloadTasks count]) {
            NSURLSessionDownloadTask *task = [self.flickrDownloadSession downloadTaskWithURL:[FlickrFetcher URLforRecentGeoreferencedPhotos]];
            task.taskDescription = FLICKR_FETCH;
            [task resume];
        } else {
            for (NSURLSessionDownloadTask *task in downloadTasks) [task resume];
        }
    }];
}

2. 每隔20分钟获取新的内容


- (void)setPhotoDatabaseContext:(NSManagedObjectContext *)photoDatabaseContext
{
    _photoDatabaseContext = photoDatabaseContext;
    
    //photoDatabaseContext设定成功后,每隔20分钟重新获取信息
    if (self.photoDatabaseContext)
    {
        self.flickrForegroundFetchTimer = [NSTimer scheduledTimerWithTimeInterval:FOREGROUND_FLICKR_FETCH_INTERVAL
                                                                           target:self
                                                                         selector:@selector(startFlickrFetch:)
                                                                         userInfo:nil
                                                                          repeats:YES];
    }
    
    //photoDatabaseContext设定成功后 向控制器发送消息
    NSDictionary *userInfo = self.photoDatabaseContext ? @{ PhotoDatabaseAvailabilityContext : self.photoDatabaseContext } : nil;
    [[NSNotificationCenter defaultCenter] postNotificationName:PhotoDatabaseAvailabilityNotification
                                                        object:self
                                                      userInfo:userInfo];
}

3. 在表格视图查询所有摄影师的名字


- (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
    //哪个数据库
    _managedObjectContext = managedObjectContext;
    
    NSFetchRequest *requet = [NSFetchRequest fetchRequestWithEntityName:@"Photographer"];
    requet.predicate = nil;//所有的,无过滤
    requet.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(localizedStandardCompare:)]];

    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:requet managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    
}

4. 重写tablelViwe:cellForRowAtIndex:方法,显示摄影师数据


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Photographer cell"];
    
    //拿到摄影师的名字和摄影数量
    Photographer *photographer = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = photographer.name;
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%lu photos", [photographer.photos count]];    
    return cell;
    
}

本Demo显然是一个未完成品,它只显示了摄影师的相关信息,并且只有一个页面。在接下来的课程中应该会对该Demo进行更多过的扩展。

最后的话


如果哪位小伙伴想拿到本文Demo的代码请不要客气,可以进入我的GitHub下载哦~ 这一系列到现在为止的所有Demo都在里面,分为英文注释版本和中文注释版本两种。

十分欢迎给笔者的代码和文笔抛出宝贵的意见和建议~

本文已在版权印备案,如需转载请访问版权印。48422928

获取授权

-------------------------------- 2018年7月17日更新 --------------------------------

注意注意!!!

笔者在近期开通了个人公众号,主要分享编程,读书笔记,思考类的文章。

  • 编程类文章:包括笔者以前发布的精选技术文章,以及后续发布的技术文章(以原创为主),并且逐渐脱离 iOS 的内容,将侧重点会转移到提高编程能力的方向上。
  • 读书笔记类文章:分享编程类思考类心理类职场类书籍的读书笔记。
  • 思考类文章:分享笔者平时在技术上生活上的思考。

因为公众号每天发布的消息数有限制,所以到目前为止还没有将所有过去的精选文章都发布在公众号上,后续会逐步发布的。

而且因为各大博客平台的各种限制,后面还会在公众号上发布一些短小精干,以小见大的干货文章哦~

扫下方的公众号二维码并点击关注,期待与您的共同成长~

公众号:程序员维他命
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容