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中,添加后需要对更改进行提交


CoreData实例分析学习(1)

CoreData实例分析学习(1)补

2 Comments

  1. Leo 说:

    貌似现在新的版本推荐使用NSFetchedResultsController来替代原来的NSFetchRequest了

  2. HeChian 说:

    想請教該怎樣用Core Data實現Update的功能
    Core Data可以INSERT INTO、DELETE,那麼要怎樣UPDATE?

Leave a Reply