豆瓣项目中 收藏按钮
当用户点击收藏按钮 他会判断用户当前状态 这里状态分为 登陆 和 没有登陆状态
没登陆状态:他会调用登陆界面(这里必须是登陆界面已经设计好)让用户登陆 用户登陆后自动判断是否已经收藏
#pragma mark 收藏按钮
- (void)addButtonItem
{
//收藏按钮
UIBarButtonItem * rightButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"收藏" style:(UIBarButtonItemStylePlain) target:self action:@selector(actionRightButton:)];
self.navigationItem.rightBarButtonItem = rightButtonItem;
[rightButtonItem release];
}
上面是添加收藏按钮 以及点击收藏按钮方法 : actionRightButton:
下面是实现 actionRightButton: 方法
- (void)actionRightButton:(UIBarButtonItem *)button
{
// 判断是否登录 利用单例判断登陆状态
BOOL isLogin = [[FileManager shareFileManager] islogin];
if (isLogin == YES) {
// 如果登陆 直接操作数据库了 把数据插入到数据库 收藏
// favorite 是操作数据库方法 下面会 出现
[self favorite];
} else {
// loginVC 是调用登陆界面 方法
[self loginVC];
}
}
当用户没有登陆时会调用 loginVC 登陆方法
// 登录界面
- (void)loginVC
{
// LoginViewController 是登陆界面
LoginViewController *loVC = [[LoginViewController alloc] init];
__block AcyivitySecondViewController *mySelf = self;
loVC.block = ^void(){
NSLog(@"OK");
// 调用操作数据库方法
[mySelf favorite];
};
// 给登录界面添加导航条
UINavigationController *nac = [[UINavigationController alloc] initWithRootViewController:loVC];
[self presentViewController:nac animated:YES completion:nil];
}
当用户登陆后 也会自动把当前收藏的 数据模型(model) 和数据库中已经添加过的model进行对比 如果已经收藏 也会弹出已经收藏提示 如果还没有收藏 那就会调用数据库 把model 插入到数据库中 并且弹出 收藏成功提示。
下面是调用添加到数据中的方法
// 收藏 去数据库中查询
- (void)favorite
{
// 当已经登陆 也要去判断是否已经收藏
// 先判断 是否收藏 去查数据库
BOOL isFavorite = [[SqLiteManager shareManager] isFavoriteActivityWithID:self.model.ID];
if (isFavorite == YES) {
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"该活动已经被收藏过" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
[alertView show];
[alertView release];
return;
} else {
// 没收藏就收藏下
// 更改model的收藏属性 再插入
self.model.isFavorite = YES;
// 把model插入到数据库
[[SqLiteManager shareManager] insertWithModel:self.model];
//显示alertView提示用户
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"收藏成功" delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
[alertView show];
[alertView release];
//0.3秒后alertView消失
[self performSelector:@selector(p_removeAlertView:) withObject:alertView afterDelay:0.3];
}
}
下面是关于 数据库 单例
// 先把声明 数据库 需要用到的方法
+ (SqLiteManager *)shareManager;
// 打开数据库
- (sqlite3 *)openDB;
// 关闭数据库
- (void)closeDB;
// 创建表
- (void)createTable;
// 插入数据
- (void)insertWithModel:(ActivityModel *)model;
// 删除数据
- (void)deleteActivity:(ActivityModel *)activity;
// 查询 根据ID
- (ActivityModel *)queryID:(NSString *)ID;
//获取所有活动
- (NSArray *)selectAllActivity;
//判断活动是否被收藏
- (BOOL)isFavoriteActivityWithID:(NSString *)ID;
实现 单例 数据库 中声明的方法
+ (SqLiteManager *)shareManager
{
static SqLiteManager *manager = nil;
if (manager == nil) {
manager = [[SqLiteManager alloc] init];
// 创建表
[manager createTable];
}
return manager;
}
// 定义一个静态区指针 连接数据库 让数据库再程序结束后自动释放
static sqlite3 *db = nil;
// 打开数据库
- (sqlite3 *)openDB
{
if (db != nil) {
return db;
}
NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"ActivityList.sqlite"];
NSLog(@"--------------%@", dbPath);
// 有这个库 就打开 没有就创建一个
int result = sqlite3_open(dbPath.UTF8String, &db);
if (result == SQLITE_OK) {
NSLog(@"打开数据库成功");
} else {
NSLog(@"打开数据库失败");
}
return db;
}
// 关闭数据库
- (void)closeDB
{
int result = sqlite3_close(db);
if (result == SQLITE_OK) {
// 切记 不要忘掉 在关闭数据库的时候 把db置为空
db = nil;
NSLog(@"关闭数据库成功");
} else {
NSLog(@"关闭数据库失败");
}
}
// 创建表
- (void)createTable
{
db = [self openDB];
// 创建一张表的时候 最重要的就是 这个唯一码 (主键)
// 主键 ID
// 属性: title imageUrl
// 数据模型归档后 data 因为数据库存放的数据类型有限 不能存放数据模型 必须把数据模型 归档成数据库 能接受的模型 这里把 数据模型转化为 NSData类型
NSString *sql = @"CREATE TABLE IF NOT EXISTS ActivityList (ID TEXT PRIMARY KEY not NULL, title TEXT not NULL, imageUrl TEXT not NULL, data BLOB not NULL)";
// 创建多张表
// @"CREATE TABLE IF NOT EXISTS ActivityList (ID TEXT PRIMARY KEY not NULL, title TEXT not NULL, imageUrl TEXT not NULL, data BLOB not NULL);CREATE TABLE IF NOT EXISTS MoveList (ID TEXT PRIMARY KEY not NULL, title TEXT not NULL, imageUrl TEXT not NULL, data BLOB not NULL)"
// 第三个参数 是一个回调的函数
// 第四个参数 是函数携带的参数
// 最后一个是错误信息
int result = sqlite3_exec(db, sql.UTF8String, NULL, NULL, NULL);
if (result == SQLITE_OK) {
NSLog(@"创建表成功");
} else {
NSLog(@"创建表失败");
}
[self closeDB];
}
// 插入数据 接收传过来的model 需要把model 归档 再放入数据库
- (void)insertWithModel:(ActivityModel *)model
{
db = [self openDB];
sqlite3_stmt * stmt = nil;
NSString * sql = @"insert into ActivityList (ID,title,imageUrl,data) values (?,?,?,?)";
// 如果程序中插入的数据中有data文件 使用sqlite3_exec 执行语句的话
// 程序会把这个data文件 转化成字符串存进数据库 而不是 咱们要的数据
int result = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL);
if (result == SQLITE_OK) {
// 绑定? 参数二 插入字段顺序 从1开始
sqlite3_bind_text(stmt, 1, [model.ID UTF8String], -1, NULL);
sqlite3_bind_text(stmt, 2, [model.title UTF8String], -1, NULL);
sqlite3_bind_text(stmt, 3, [model.image UTF8String], -1, NULL);
// 拼接归档时的key 保证唯一
// 数据模型归档后 data 因为数据库存放的数据类型有限 不能存放数据模型 必须把数据模型 归档成数据库 能接受的模型 这里把 数据模型转化为 NSData类型
NSString * archiverKey = [NSString stringWithFormat:@"%@%@",kActivityArchiverKey,model.ID];
// 把model进行归档 得到插入数据库的data
NSData * data = [[FileManager shareFileManager] dataOfArchiverObject:model forKey:archiverKey];
// blob 表示 data类型在数据库中的类型
// 参数3 data 的大小
// 参数4 data 的长度 注意转换类型 需要int类型
// 参数5
sqlite3_bind_blob(stmt, 4, [data bytes], (int)[data length], NULL);
// 执行上面命令
sqlite3_step(stmt);
}
sqlite3_finalize(stmt);
[self closeDB];
}
// 删除数据
- (void)deleteActivity:(ActivityModel *)activity
{
db = [self openDB];
NSString *sql = [NSString stringWithFormat:@"delete from ActivityList where ID = '%@'",activity.ID];
int result = sqlite3_exec(db, sql.UTF8String, NULL, NULL, NULL);
if (result == SQLITE_OK) {
NSLog(@"删除成功");
} else {
NSLog(@"删除失败");
}
[self closeDB];
}
#pragma mark 查询
- (ActivityModel *)queryID:(NSString *)ID
{
NSString * archiverKey = [NSString stringWithFormat:@"%@%@",kActivityArchiverKey,ID];
db = [self openDB];
// 根据ID 查询对应的Data
// 原来是 * 查询所有的字段 现在咱们就把对应的data取出来就行
// 查询 这里也用到反归档
// data是归档后 放入到数据库中的data 这里是根据 ID 查询出来 data
NSString *sql = [NSString stringWithFormat:@"select data from ActivityList where ID = '%@'",ID];
// 创建一个跟随指针
sqlite3_stmt *stmt = nil;
// 执行sql语句
sqlite3_prepare_v2(db, sql.UTF8String, -1, &stmt, NULL);
// 绑定 查询字段ID 根据ID查询 从1开始
//
sqlite3_bind_text(stmt, 1, ID.UTF8String, -1, NULL);
// 定义一个model接收 从库中查出的数据
ActivityModel *model = nil;
while (sqlite3_step(stmt) == SQLITE_ROW) {
// 第二个参数 列数 查询的列数 从零开始
// * 的时候查询数据库中所有的 要按照顺序写第二个参数
// 如果 只查询一个 这个参数 要按照你查询的列数来写
// 把取出来的data和字节数转换成 oc的data
NSData *data = [NSData dataWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)];
// 把取出来的model 反归档 返回
model = [[FileManager shareFileManager] unarchiverObject:data forKey:archiverKey];
}
sqlite3_finalize(stmt);
[self closeDB];
return model;
}
//判断活动是否被收藏
- (BOOL)isFavoriteActivityWithID:(NSString *)ID
{
// 插入数据库之前 先查询数据库 如果返回的model有值 说明已经收藏了
ActivityModel * model = [self queryID:ID];
if (model == nil) {
return NO;
}
return YES;
}
//获取所有活动
- (NSArray *)selectAllActivity
{
[self openDB];
sqlite3_stmt * stmt = nil;
// 查询所有的 ID,data
NSString * sql = @"select ID,data from ActivityList";
int result = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL);
NSMutableArray * activityArray = [NSMutableArray array];
if (result == SQLITE_OK) {
while (sqlite3_step(stmt) == SQLITE_ROW) {
NSString * ID = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(stmt, 0)];
NSData * data = [NSData dataWithBytes:sqlite3_column_blob(stmt, 1) length:sqlite3_column_bytes(stmt, 1)];
NSString * archiverKey = [NSString stringWithFormat:@"%@%@",kActivityArchiverKey,ID];
// 查询出来反归档 把model放在数组里面 返回去
ActivityModel * model = [[FileManager shareFileManager] unarchiverObject:data forKey:archiverKey];
[activityArray addObject:model];
}
}
sqlite3_finalize(stmt);
[self closeDB];
return activityArray;
}
上面是数据库的操作 在数据库操作中 用到 对数据的归档
对数据的归档 就是 以一种存放数据的形式
下面介绍归档 与接档
#pragma mark 归档方法(存数据) 你要注意归档的 属性的类型 要与 调用的方法对应 这是把数据模型中的声明的属性 进行归档 与 接档
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.ID forKey:@"ID"];
[aCoder encodeObject:self.title forKey:@"title"];
[aCoder encodeObject:self.begin_time forKey:@"begin_time"];
[aCoder encodeObject:self.end_time forKey:@"end_time"];
[aCoder encodeObject:self.address forKey:@"address"];
[aCoder encodeObject:self.category_name forKey:@"category_name"];
[aCoder encodeObject:self.image forKey:@"image"];
[aCoder encodeObject:self.content forKey:@"content"];
[aCoder encodeObject:self.wisher_count forKey:@"wisher_count"];
[aCoder encodeObject:self.participant_count forKey:@"participant_count"];
[aCoder encodeObject:self.imagePath forKey:@"imagePath"];
[aCoder encodeBool:self.isDownloading forKey:@"isDownloading"];
[aCoder encodeBool:self.isFavorite forKey:@"isFavorite"];
}
#pragma mark 反规当(取数据) 你要注意归档的 属性的类型 要与 调用的方法对应
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
self.ID = [aDecoder decodeObjectForKey:@"ID"];
self.title = [aDecoder decodeObjectForKey:@"title"];
self.begin_time = [aDecoder decodeObjectForKey:@"begin_time"];
self.end_time = [aDecoder decodeObjectForKey:@"end_time"];
self.address = [aDecoder decodeObjectForKey:@"address"];
self.category_name = [aDecoder decodeObjectForKey:@"category_name"];
self.image = [aDecoder decodeObjectForKey:@"image"];
self.content = [aDecoder decodeObjectForKey:@"content"];
self.wisher_count = [aDecoder decodeObjectForKey:@"wisher_count"];
self.participant_count = [aDecoder decodeObjectForKey:@"participant_count"];
self.imagePath = [aDecoder decodeObjectForKey:@"imagePath"];
self.isDownloading = [aDecoder decodeBoolForKey:@"isDownloading"];
self.isFavorite = [aDecoder decodeBoolForKey:@"isFavorite"];
}
return self;
}
在单例中用到 也要归档和接档
#pragma mark -- 将对象归档 反归档
//将对象归档 数据操作调用到 dataOfArchiverObject 方法 传进来一个model
// 把传进来的model 归档成数据库接受的类型 NSMutableData
- (NSData *)dataOfArchiverObject:(id)object forKey:(NSString *)key
{
NSMutableData * data = [NSMutableData data];
// NSKeyedArchiver 归档方法
NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:object forKey:key];
[archiver finishEncoding];
[archiver release];
// 返回归档后的 data
return data;
}
//反归档(接档 / 反编码)
- (id)unarchiverObject:(NSData *)data forKey:(NSString *)key
{
NSKeyedUnarchiver * unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
id object = [unarchiver decodeObjectForKey:key];
[unarchiver finishDecoding];
[unarchiver release];
return object;
基本思路:当用户点击页面上 收藏按钮的时候 他会自动判断当前用户的状态
这里的状态分为 登陆状态 和 未登陆状态
登陆状态 :
在登陆状态下 他会去数据库中查找是否已经存在判断当前的 数据模型 是否已经收藏 如果已经收藏 他就会自动弹出 已经收藏
如果没有收藏 他会把数据模型插入到 数据库中 由于数据库存放的数据类型有限制 所以 不能直接把数据模型 插入到数据库中 这里就用到了 对数据模型的 归档和接档
归档 : 基本用在往数据库中插入数据的时候
接档:基本用在 从数据库中查询的时候
未有登录状态:
在用户点击收藏没有登陆状态下 会自动弹出登陆界面 让用户登陆 只有登陆后才能进行收藏
当用户登陆后 会自动调用数据库 把当前的数据模型和 数据库中已经添加过得数据模型 进行对比 是否存在 如果已经存在 就会弹出已经收藏 如果没有收藏 那就会往数据库中插入数据模型