CoreData实例分析学习(2)
在我们分析了程序主代理文件(AppDelegate)之后,我们先来看看一对自动生成的文件Event.h/.m
@interface Event : NSManagedObject {} @property (nonatomic, retain) NSDate *creationDate; @property (nonatomic, retain) NSNumber *latitude; @property (nonatomic, retain) NSNumber *longitude; @end |
#import "Event.h" @implementation Event @dynamic creationDate; @dynamic latitude; @dynamic longitude; @end |
从上面我们能看出来,一个实体Event也就会被生成一个NSManagedObject(被管理对象),然后任何accessor和getter都是被动态生成的,我们其实完全不用操任何的心,只需要在xcdatamodel文件里面配置后,点击添加文件,添加NSManagedObject文件,就会看到自动感知的类对象,然后生成就可以了。
下面是根视图控制器,是一个列表视图(UITableViewController)
#import <CoreLocation/CoreLocation.h> @interface RootViewController : UITableViewController <CLLocationManagerDelegate> { //看到是UITableViewController的子类,由于需要使用Core Location, //所以在后面履行其protocal NSMutableArray *eventsArray; NSManagedObjectContext *managedObjectContext; //这个被管理对象内容器就是我们真正对Core Data数据的操作对象 CLLocationManager *locationManager; //用来得到地理位置的Core Location对象 UIBarButtonItem *addButton; //右上角的添加键 } @property (nonatomic, retain) NSMutableArray *eventsArray; @property (nonatomic, retain) NSManagedObjectContext *managedObjectContext; @property (nonatomic, retain) CLLocationManager *locationManager; @property (nonatomic, retain) UIBarButtonItem *addButton; - (void)addEvent; @end |
#import "RootViewController.h" #import "LocationsAppDelegate.h" #import "Event.h" @implementation RootViewController @synthesize eventsArray, managedObjectContext, addButton, locationManager; - (void)viewDidLoad { [super viewDidLoad]; self.title = @"Locations"; //设置列表视图的标题 self.navigationItem.leftBarButtonItem = self.editButtonItem; //导航栏左边的编辑按钮 addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addEvent)]; //初始化添加按钮, addButton.enabled = NO; //在Core Location初始化之前将其关闭 self.navigationItem.rightBarButtonItem = addButton; //把这个添加按钮添加到导航栏右侧 // 启动CLocation [[self locationManager] startUpdatingLocation]; //初始化一个“获取请求”到我们的实体“Event” NSFetchRequest *request = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectContext]; [request setEntity:entity]; // 将时间以建立时间排序,最新的在最上 NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO]; NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; [request setSortDescriptors:sortDescriptors]; [sortDescriptor release]; [sortDescriptors release]; // 执行“获取”操作,得到一个“可变数组”的拷贝 NSError *error = nil; NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy]; if (mutableFetchResults == nil) { //如果结果为空,在这作错误响应 } // 将得到的本地数组赋值到本类的全局数组,然后清理无用的对象 [self setEventsArray:mutableFetchResults]; [mutableFetchResults release]; [request release]; } - (void)viewDidUnload { // 当视图被卸载后,将以下指针置空 self.eventsArray = nil; self.locationManager = nil; self.addButton = nil; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // 只有一个章节 return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // 在数组里面有多少个对象,在列表视图就有多少行 return [eventsArray count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 一个“日期格式化器”(凑合明白就好...)用来以特定的格式创建得到的日期 static NSDateFormatter *dateFormatter = nil; if (dateFormatter == nil) { dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]; [dateFormatter setDateStyle:NSDateFormatterMediumStyle]; } static NSNumberFormatter *numberFormatter = nil; if (numberFormatter == nil) { numberFormatter = [[NSNumberFormatter alloc] init]; [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; [numberFormatter setMaximumFractionDigits:3]; } static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; UITableViewCellStyleSubtitle; } // 从数组中得到这个Event对象 Event *event = (Event *)[eventsArray objectAtIndex:indexPath.row]; cell.textLabel.text = [dateFormatter stringFromDate:[event creationDate]]; NSString *string = [NSString stringWithFormat:@"%@, %@", [numberFormatter stringFromNumber:[event latitude]], [numberFormatter stringFromNumber:[event longitude]]]; cell.detailTextLabel.text = string; return cell; } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // 删除被惯例对象在索引路径(index path) NSManagedObject *eventToDelete = [eventsArray objectAtIndex:indexPath.row]; [managedObjectContext deleteObject:eventToDelete]; // 更新数组和列表视图 [eventsArray removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]; // 提交更改到Core Data NSError *error; if (![managedObjectContext save:&error]) { // Handle the error. } } } - (void)addEvent { //如果得不到位置,就返回. CLLocation *location = [locationManager location]; if (!location) { return; } //建立一个Event实体对象 Event *event = (Event *)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:managedObjectContext]; //得到经纬度,然后赋值到event对象去 CLLocationCoordinate2D coordinate = [location coordinate]; [event setLatitude:[NSNumber numberWithDouble:coordinate.latitude]]; [event setLongitude:[NSNumber numberWithDouble:coordinate.longitude]]; // 实例里面并没有使用CL的时间标签,因为在模拟器中会是一样的 // [event setCreationDate:[location timestamp]]; [event setCreationDate:[NSDate date]]; //所以现在使用的是现在的时间,而不是得到位置的时候的时间 // 保存更改 NSError *error; if (![managedObjectContext save:&error]) { // Handle the error. } // 将新Event放到最上面,所以添加到0的位置 // 然后滚动列表视图到最上面,如果没有那么多的数据是看不出来区别的 [eventsArray insertObject:event atIndex:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES]; } - (CLLocationManager *)locationManager { //自定义的CLocation的getter,方便初始化 if (locationManager != nil) { return locationManager; } //初始化CL对象,然后设置精准度,然后将代理对象设为本地 locationManager = [[CLLocationManager alloc] init]; [locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters]; [locationManager setDelegate:self]; return locationManager; } //CLocation的一个代理方法,如果成功就开启右侧添加按钮 - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { addButton.enabled = YES; } //CLocation的一个代理方法,如果失败了就关闭(disable)右侧添加按钮 - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { addButton.enabled = NO; } - (void)dealloc { //释放对象 [managedObjectContext release]; [eventsArray release]; [locationManager release]; [addButton release]; [super dealloc]; } @end |
从上面的源代码,我们可以看出,
1,在这里数据并不是每次都由NSManagedContext对象得到,而是由一个数组得出。
2,数组是一个可变数组,由第一次载入的视图的时候从NSManagedContext中得到
3,从NSManagedContext对象中得到数据需要使用NSFetchRequest来初始化一个“获取”
4,每次获得新的数据的时候,同时保存到数组和NSManagedContext中,添加后需要对更改进行提交