zoukankan      html  css  js  c++  java
  • runtime 任意类型 model 数据库方便存储

    //这里边直接上代码 之后我在慢慢地讲解  之后我的QQ:378254160 我有DEMO 方便你们的使用联系我备注 runtime+数据库+任意model类型  当然有时候也是有局限的

    //DataBasehandle.m

    #import "DataBasehandle.h"

    #import <objc/runtime.h>

    #import <sqlite3.h>

    //http://www.sjsjw.com/kf_mobile/article/4_17043_17742.asp

    @interface DataBasehandle ()

    @property (nonatomic, copy)NSString *tabelename;

    @property (nonatomic, copy)NSDictionary *dic;

    @end

    @implementation DataBasehandle

    /* 获取对象的所有属性和属性内容 */

    //这个方法 返回的是一个大字典 里边放着所有不为空 的属性和他们的值 属性是Key 值 是 Value

    - (NSDictionary *)getAllPropertiesAndVaulesModel:(id)model

    {

        NSMutableDictionary *props = [NSMutableDictionary dictionary];

        unsigned int outCount, i;

        objc_property_t *properties = class_copyPropertyList([model class], &outCount);

        for (i = 0; i<outCount; i++)

        {

            objc_property_t property = properties[i];

            const char* char_f =property_getName(property);

            NSString *propertyName = [NSString stringWithUTF8String:char_f];

            id propertyValue = [model valueForKey:(NSString *)propertyName];

            

            /*下面注释的这条语句是这个函数 最开始的语句 目的获取值不为空的属性 我修改之后就可以获取model全部属

             性当然model 属性必须全部写成NSString 类型的 不管实际的类型是什么!*/

             //if (propertyValue) [props setObject:propertyValue forKey:propertyName];

            

            //这样做 就可以获取model对象的全部属性!!!! 下面的代码是我修改的!

            if (propertyValue == nil) {

                [props setObject:@"nil" forKey:propertyName];

            }else

            {

              [props setObject:propertyValue forKey:propertyName];

            }

        }

        free(properties);

        return props;

    }

    static DataBasehandle * shareDataManager = nil;

    //这样可以防止多进程的访问 GCD 写法!!!!!

    +(DataBasehandle *) sharedDataBasehandle

    {

        static dispatch_once_t once;

        dispatch_once(&once

                      , ^{

                           if (shareDataManager == nil)

                          {

                              shareDataManager = [ [ DataBasehandle alloc ] init ];

                          }

                          

                      });

        return shareDataManager;

    }

    static sqlite3 *db = nil;

    -(void)openDB

    {

        //已经打开完了之后 就不需要再打开了

        if(db != nil)return;

        //获取沙河路径 拼接一个文件的名字

        NSString *document = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];

        NSString *path = [document stringByAppendingPathComponent:[NSString stringWithFormat:@"/%@",@"adress.sqlite"]];

        NSLog(@"%@",path);

        //打开数据库 初始化数据库了 已经 静态区不为nil了

        int result = sqlite3_open(path.UTF8String, &db);

        if(result == SQLITE_OK)

        {

            //打开成功!

            NSLog(@"打开成功");

        }else

        {

            NSLog(@"打开失败");

        }

    }

    -(void)closeDB

    {

        int result = sqlite3_close(db);

        if (result == SQLITE_OK) {

            NSLog(@"关闭成功");

        }else

        {

            NSLog(@"关闭失败");

        }

    }

    //根据表的名字 和 运行时的model对象 创建一个表!

    -(void)createtableName:(NSString *)name Model:(id)model

    {

        //根据模型拼接字符串

        NSDictionary *dicstart = [self getAllPropertiesAndVaulesModel:model];

        //这里 必须这样操作一下 变成不可变的字典要不然 遍历的时候 表属性的顺序对应不上!

        NSDictionary *dic = [NSDictionary dictionaryWithDictionary:dicstart];

        self.dic = dic;

        self.tabelename = name;

        NSMutableString *str = [NSMutableString string];

        

        for (id obj in [dic allKeys] )

        {

          [str appendFormat:@" %@ text,",obj];

        }

        NSString *str1 = [str substringToIndex:str.length-1];

        //创建表的SQL语句 CREATE TABLE + 表名(字段 类型 ,...,字段 类型)

        NSString *createStr = [NSString stringWithFormat:@"CREATE TABLE  IF NOT EXISTS  %@(%@)",name,str1];

        NSLog(@"createStr === %@",createStr );

        //第一个参数:在那个数据库里边操作

        //第二个参数:代表要去执行那一条SQL 语句

        //第三个参数:代表那个回调函数

        //第四个参数:回调的一些参数

        //第五个参数:错误信息

        char *error = NULL;

        int result = sqlite3_exec(db, createStr.UTF8String, NULL, NULL, &error);

         printf("massage = %s",error);

        if(result == SQLITE_OK)

        {

            NSLog(@"创表成功");

        }else

        {

            NSLog(@"创表失败");

        }

    }

    //根据当前创建的表的名字 和运行时model对象 把model对象写入数据库

    -(void)insertIntoTableModel:(id)model

    {

        NSDictionary *dicstart = [self getAllPropertiesAndVaulesModel:model];

        NSDictionary *dic = [NSDictionary dictionaryWithDictionary:dicstart];

        NSString *name = self.tabelename;

        NSMutableString *strkey = [NSMutableString string];

        NSMutableString *strvalue = [NSMutableString string];

        for (id obj in [dic allKeys] )

        {

            [strkey appendFormat:@" %@,",obj];

            [strvalue appendFormat:@" '%@',",[dic objectForKey:obj]];

        }

        NSString *strkey1 = [strkey substringToIndex:strkey.length-1];

        NSString *strvalue1 = [strvalue substringToIndex:strvalue.length-1];

        

        //插入语句

        NSString *insertStr = [NSString stringWithFormat:@"INSERT INTO %@(%@) VALUES(%@)",name,strkey1,strvalue1];

        //第一个参数:在那个数据库里边操作

        //第二个参数:代表要去执行那一条SQL 语句

        //第三个参数:代表那个回调函数

        //第四个参数:回调的一些参数

        //第五个参数:错误信息

        NSLog(@"%@",strkey1);

        char *message = NULL;

        int result = sqlite3_exec(db, insertStr.UTF8String, NULL, NULL, &message);

        printf("massage ======= %s",message);

        if(result == SQLITE_OK)

        {

            NSLog(@"插入成功");

        }else

        {

            NSLog(@"插入失败");

        }

    }

    //根据当前的表的名字和运行时model对象  删除 model对象所对应的 一条数据!

    -(void)deleteFromTableModel:(id )model

    {

        NSDictionary *dicstart = [self getAllPropertiesAndVaulesModel:model];

        NSDictionary *dic = [NSDictionary dictionaryWithDictionary:dicstart];

        NSString *name = self.tabelename;

        NSMutableString *strkey = [NSMutableString string];

        for (id obj in [dic allKeys] )

        {

            if ([ [dic objectForKey:obj ] isKindOfClass:[NSNumber class]] || [ [dic objectForKey:obj ] isKindOfClass:[NSString class]]   )

            {

                [strkey appendFormat:@" %@ = '%@' and",obj,[dic objectForKey:obj]];

            }

        }

            //去掉最后 四个字符

        NSString *strNew = [strkey substringToIndex:strkey.length-4];

        NSString *deleteStr = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@",name,strNew];

        char *message = NULL;

        int result = sqlite3_exec(db, deleteStr.UTF8String, NULL, NULL, &message);

        printf("%s",message);

        if(result == SQLITE_OK)

        {

            NSLog(@"删除成功");

        }else

        {

            NSLog(@"删除失败");

        }

    }

    //根据 运行时的model对象 和表的名字 获取所有的 model对象数组

    -(NSArray *)selectAllTableModel:(id)model

    {

         NSMutableArray  *dataArray = nil;

        //根据模型拼接字符串

        NSDictionary *adddic = self.dic;

        NSString *name = self.tabelename;

        // 查询SQL 语句

        // SELECT * FROM + 表名

        NSString *selectStr = [NSString stringWithFormat:@"SELECT * FROM %@",name];

        sqlite3_stmt *stmt = nil;

        int result = sqlite3_prepare(db, selectStr.UTF8String, -1, &stmt, NULL);

        if (result == SQLITE_OK)

        {

            //定义一个泛型 的指针 在下面会初始化这个泛型具体是什么类型的!不用担心!!!!

            id Model;

            //初始化数组

            dataArray = [NSMutableArray array ];

            

            while (sqlite3_step(stmt) == SQLITE_ROW)

            {

                //这里做的 工作最重要 要不然保存的模型 你是没办法拿到值的!!!!

                //这里根据runtime运行时 创建运行时的对象 这样就可以面对所有的对象!!!! 哈哈哈!

                model = [[ [model class] alloc] init];

                Model = model;

                //记录 表一条数据的位置每次循环的时候 增加!!!!!

                int i = 0;

                for (NSString *key in [adddic allKeys])

                {

                    if ([[adddic objectForKey:key] isKindOfClass:[NSString class]] || [[adddic objectForKey:key] isKindOfClass:[NSNumber class]]) {

                      

                        if ([[adddic objectForKey:key] isKindOfClass:[NSString class]])

                        {

                            //这里注意一下可能是 NULL 空的 之后处理一下 避免KVC crash

                            if ((const char *)sqlite3_column_text(stmt, i) == NULL) {

                                [Model setValue:@" " forKey:key];

                            }else

                            {

                                NSString *string = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(stmt, i)];

                                [Model setValue:string forKey:key];

                            }

                        } else

                        {

                            NSInteger index = sqlite3_column_int(stmt, i);

                            //这里不用担心 一定能

                            NSString *string = [NSString stringWithFormat:@"%ld", (long)index];

                            [Model setValue:string forKey:key];

                        }

                        i++;

                    }

                }

                [dataArray addObject:Model];

              }

        }

        //释放伴随指针

        sqlite3_finalize(stmt);

        return dataArray;

    }

     @end

    //DataBasehandle.h 中的文件 

    #import <Foundation/Foundation.h>

    @interface DataBasehandle : NSObject

    +(DataBasehandle *) sharedDataBasehandle;

    -(void)openDB;

    -(void)closeDB;

    /* 获取对象的所有属性和属性内容 */

    - (NSDictionary *)getAllPropertiesAndVaulesModel:(id)model;

    -(void)createtableName:(NSString *)name Model:(id)model;

    -(void)insertIntoTableModel:(id )model;

    -(void)deleteFromTableModel:(id )model;

    -(NSArray *)selectAllTableModel:(id)model;

     @end

    //根据我写的这个 工具类 你可以很方便的存储 根据任意类型的 model 存储到数据库里边 而不用担心数据库不用写 当然前提是你非常明白runtime 运行机制才行  你可以直接存储任意类型的model 当然前提model 里边的所有属性都是 NSString *obj; 类型的这是网络下载下来的数据,当然网络下载的数据可能是 NSNumber类型的 但是不用担心 用NSString接收 之后 显示的时候用 格式化字符串 皆可以解决这个问题!

    下面说一下 这个工具类的用法! 很简单!如果现在没有 我就以后会加上的 当然也可以联系我!

    //首先创建 一个工具类

        db = [[DataBasehandle alloc] init];

        [db openDB];

        //为了获取这个类 运行时的属性与对象值 创建model而已

        model = [[ActivityModelevent1 alloc] init];

        //创建 固定格式的表 这里注意一个类型的model 对应一个表格的名字

        [db createtableName:@"activitymodel" Model:model];

       //读取数据库里边的所有 model 组成的数组 变成可变数组 付给self.dataArray

        self.dataArray =  [NSMutableArray arrayWithArray:[db selectAllTableModel:model]];

     当然你也可以 增加和修改 如下

          //创建一个新的model1 任意类型都可以 你的model 但是必须和你的 表名 是一直的 这也就是 runtime 的优点 也是缺点

          model1 = [[ActivityModelevent1 alloc] init];

    //增加 一个model1 在当前表名

          [db insertIntoTableModel:model1];

    //删除 一个model1 在当前表名

          [db deleteFromTableModel:model1];

    通过上面的简单的操作 根据runtime 运行时的好处 大家就可以 通过我的工具类 不必操作 数据库 就能把 model 数据存储和 删除了 非常简单! 当然这样虽然方便 也有他的弊端 大家了解了我的 思想就会 非常明白这个 弊端了 ,劝大家还是好好学习一下Sqlite 这才是王道,我现在懒得学习哈哈,就这样,大家下次见。

  • 相关阅读:
    G. Yash And Trees 线段树 + dfs序 + bitset
    网络流最小割 H
    P2764 最小路径覆盖问题 网络流重温
    P4016 负载平衡问题 网络流重温
    D. Yet Another Subarray Problem 思维 难 dp更好理解
    J
    20190709 暑训 区间种类数 莫队的学习
    E
    线段树 离散化 E. Infinite Inversions E. Physical Education Lessons
    CbsPersist
  • 原文地址:https://www.cnblogs.com/yuzhouwjl/p/4868499.html
Copyright © 2011-2022 走看看