IOS之征战豆瓣案例--收藏 (数据库操作)

豆瓣项目中 收藏按钮
当用户点击收藏按钮 他会判断用户当前状态 这里状态分为 登陆 和 没有登陆状态

没登陆状态:他会调用登陆界面(这里必须是登陆界面已经设计好)让用户登陆 用户登陆后自动判断是否已经收藏

#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;

基本思路:当用户点击页面上 收藏按钮的时候 他会自动判断当前用户的状态
这里的状态分为 登陆状态 和 未登陆状态

登陆状态 :
在登陆状态下 他会去数据库中查找是否已经存在判断当前的 数据模型 是否已经收藏 如果已经收藏 他就会自动弹出 已经收藏

如果没有收藏 他会把数据模型插入到 数据库中 由于数据库存放的数据类型有限制 所以 不能直接把数据模型 插入到数据库中 这里就用到了 对数据模型的 归档和接档
归档 : 基本用在往数据库中插入数据的时候
接档:基本用在 从数据库中查询的时候

未有登录状态:
在用户点击收藏没有登陆状态下 会自动弹出登陆界面 让用户登陆 只有登陆后才能进行收藏
当用户登陆后 会自动调用数据库 把当前的数据模型和 数据库中已经添加过得数据模型 进行对比 是否存在 如果已经存在 就会弹出已经收藏 如果没有收藏 那就会往数据库中插入数据模型

你可能感兴趣的:(ios,数据库,归档,豆瓣,接档)