sqlite从SQLite获取数据已毕一个产品新闻显示

     在ios实际付出当中,我们日常用到Core
Data做为数据存储首选。但在拍卖部分大方扑朔迷离的多寡值且数据里面相互关系的时候,那就只能动用关系型数据库来兑现。例如一个导航程序,自身应有包罗大量的地形图自身数据同时数据必要在app启动的时候就早先读取加载。而且数量我改变不是特意频仍。重复向服务器发送请求获取音讯是一件分外荒废的事体。由此我们得以用一个当地数据文件来直接配置。做为轻量级关系型数据库的sqlite是ios开发首选。而xcode本身富含了sqlite库,因而在ios使用的时候不必要卓殊布置文件,格外造福。上边就用一个概括例子讲述一下从安装sqlite3到一个大约demo的编写进度。

其落实效益如下:点击左侧cell,可以来得商品详细新闻

sqlite 1

     首先需求设置
sqlite,当前一大半用到版本为3以上。mac版传送门:https://www.sqlite.org/2016/sqlite-dll-win32-x86-3150100.zip。安装完成,在终端输入$sqlite3
,突显版本音信即安装成功

   
其次须求一个简易的数据库。那里的须要是一个店铺的产品目录,每个产品包罗有成立商、产品名称等详细音信必要出示。sqlite有成百上千可视化创造渠道,用户比较多的如SQlite
Manager
或者Navicat,后者是一个支撑多种数据库可视化编辑的软件。在本文中不考虑可视化创设,直接使用命令行的款式。

打开mac终端输入sqlite3 (file name).db,此语句启动sqlite3
并创设一个db数据文件,(file
name)为自定义文件名字。输入指令之后终端进入sqlite编辑格局,在命令提醒符处输入语句:

 CREATE TABLE “main”.”product” (“ID” INTEGER PRIMARY KEY AUTOINCREMENT NOT
NULL,”Name” TEXT,”ManufacturerID”
INTEGER,”Details” TEXT,”Price”
DOUBLE,”QuantityOnHand”INTEGER,”CountryOfOriginID” INTEGER,”Image” TEXT);
语句可随意换行,以分行结尾回车执行就得到了一个创建好的表格,其语句内容解释如下图(只解释了前三行,后序内容同样,只是数目格式差距):

sqlite 2

为了更好的诠释sqlite的关系型数据特质,我们还亟需成立八个表格
语句如下:

CREATE TABLE “main”.”Manufacturer”(“ManufacturerID”INTEGER PRIMARY KEY AUTOINCREMENT NOT
NULL,”Name” TEXT NOT NULL);

CREATE TABLE “main”.”Country”(“CountryId” INTEGER PRIMARY KEY AUTOINCREMENT NOT
NULL, “Country” TEXT NOT NULL);

现在我们早已有了一个大约的数据库,它拥有多少个表格,但还不曾多少填充,没有何样实际价值,接下去应该把数量整理到数据库里,在指令行里,我们可以动用INSERT
INTO
关键字来插入一行消息到表格中。但以此法子成效及其低下,一般是做为程序运行时进行多少增进的时候利用,在后台数据整理的时候,一般是把要求的多寡整理成文本文档进行导入,文本内容如下:所有文件内容和完全代码贴于
https://github.com/huafushengweirui/data/tree/master/two

1   widget A    1   details of widget A 1.29    5   1   Canvas_1
2   widget B    1   details of widget B 4.29    15  2   Canvas_2
3   widget X    1   details of widget X 0.29    25  3   Canvas_3
4   widget Y    1   details of widget Y 1.79    5   3   Canvas_4
5   widget Z    1   details of widget Z 6.26    15  4   Canvas_5
6   widget R    1   details of widget R 2.29    45  1   Canvas_6
7   widget S    1   details of widget S 3.29    55  1   Canvas_7
8   widget T    1   details of widget T 4.29    15  2   Canvas_8
9   widget L    1   details of widget L 5.29    50  3   Canvas_9
10  widget N    1   details of widget N 6.29    89  3   Canvas_10
11  widget E    1   details of widget E 17.29   26  4   Canvas_11
12  Part alpha  2   details of widget apla  1.49    25  1   Canvas_12
13  Part bata   2   details of widget bata  1.89    35  1   Canvas_13
14  Part gamma  2   details of widget gamma 3.46    45  2   Canvas_14
15  device N    3   details of device N 9.29    15  3   Canvas_15
16  device O    3   details of device O 21.29   15  3   Canvas_16
17  device P    3   details of device P 51.29   15  4   Canvas_17
18  tool A  4   details of tool A   14.99   5   1   Canvas_18
19  tool B  4   details of tool B   44.57   5   1   Canvas_19
20  tool C  4   details of tool C   6.99    5   1   Canvas_20
21  tool D  4   details of tool D   8.29    5   1   Canvas_21

  

   
 自行编排的必定要专注,字段的相继一定要与创立时候的逐一一致并且一定要用制表符tab键来划分。处理好了文本文档在sqlite命令提示符出输入.separator
“\t” ,即指定制表符做为数据的分隔符,接着输入.import “(filename).txt”
Priduct
回车执行,没有不当警告的话,数据内容早已导入到表格内,如若有可视化软件可以一贯打开查看,要是没有,可以在极端用sql语句select
* from Product查询 结果命令行出示文本内容则数据导入无误。同样办法为Manufacturer和Country填充数据,数据内容如下:

country的内容:
1   USA
2   Taiwan
3   China
4   Singapore


manufacyure的内容:
1   sprit industries
2   industrial designs
3   design intl
4   tool masters  

     
在正式进入demo此前,或许应该提一下关系型数据库的优势与风味。认真察看一下product表格会发现在创建商以及原产地国家那样的数据栏里,大家填写的是数字integer,那明摆着与事实不符合,因为成立商和原产地都不容许是数字。但只顾观看会发现而country和Manufacturer表格里,创制商和江山独家有例外的数码来代表,在极端输入SELECT
name,country FROM Product,Country where Product.CountryOfOriginID =
Country.CountryID;结果如下图:

sqlite 3

     
可以在命令行看到查询结果,所有的数码内容被沟通为country表格中的id对应国家,那么难点豁然明了,大家并不在主产品的数据表中肯定输入创设商和原产地,而是关乎其余表格中的数据标识,那样的艺术在很大程度上幸免了我们输入大批量的再度数据,那正是关系型数据库最大的风味。例如可能是数百件产品来自同一原产地。同理大家得以经过sql关联语句询问出产品的创设商。同时,还能直接对数据开展过滤,例如查询所有中国创设的产品
语句SELECT name,country FROM Product,Country where
Product.CountryOfOriginID = Country.CountryID AND Country.Country =
“China”; 其结果如下图:

sqlite 4

   
 在处理好数据库之后,剩下就是在代码里读取数据并浮现。关于详情体现,为了有利于。那里直接使用Master-details模板。那是一个简练的中坚界面,能高效到位多少突显,而不用额外去规划代码。直接打开xcode,新建一个系列,接纳Master-details模板。其界面如下图所示:

sqlite 5

 

   
项目开首界面如上,在storyboard一共能够见见多少个控制器视图,分别是根控制器,八个Navagation控制器,剩下俩个需要着重关心也是急需编制代码的展现视图,即master和details。按照MVC的原则分析一下项目文件,还缺一个模型类用于封装解析的多少,该模型对象内容应当包含数据表中的字段。新建一个oc类命名为Product,在头文件中增进对应每个数据库字段的质量代码如下:

#import <Foundation/Foundation.h>

@interface Product : NSObject
@property(nonatomic)int ID;
@property(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *manufacture;
@property(nonatomic,copy)NSString *details;
@property(nonatomic)float price;
@property(nonatomic)int quantity;
@property(nonatomic,copy)NSString *countryforgin;
@property(nonatomic,copy)NSString *image;
@end

   
 在处理完模型类之后,就相应从数据库从中获取数据并赋值给模型中的代码,在开发中,对于一个职能拓展独立类包装能极好的下跌耦合性,由此,如若编写一个通用类来施行访问数据库并获取数据的效应,会使代码越发灵活直观。所以我们需求创立一个类来与数据库交互,提供初叶化数据库,关闭数据库,以及获取数据并再次回到为Product模型对象集合。在iOS中要拔取sqlite,首先需求把sqlite的模块添加进项目。添加办法如下图sqlite 6

   
 添加完sqlite3相关库之后,把编写好的数据库db文件,拖入项目文件夹,尽量放在接济文件中有益直接读取。然后成立用来和数据库交互的类,新建一个oc类,命名为Dbaccess,开首入sqlite3.h,因为大家需求用到相关函数,然后导入Product,因为我们要在获得数量的同时对Product举办赋值,所以自然会拔取到这些类。然后分析一下类的章程须求,首先是一个初叶化数据库的艺术,然后是关门数据库,那中档要求一个办法赢得到数码来成立模型对象、赋值,并重返数据。大约须要几个艺术。分别命名initializeDatebase、closeDatabase、getAllproducts。前八个方法没有重临对象,最终一个用来重返已经赋好值得模型对象,所以,应该是一个数组。模型对象是逐一生成的,由此不能三遍性全体拍卖,所以为可变数组。这三个艺术都须求给外界调用。所以须求在.h文件之中申明。到此停止Dbaccess.h文件的代码如下:

#import <Foundation/Foundation.h>
#import "Product.h"
#import <sqlite3.h>
@interface Dbaccess : NSObject
- (void)initializeDatebase;
-(void)closeDatabase;
-(NSMutableArray *)getAllproducts;
@end

  然后是在.m文件里开展艺术完成,已毕代码如下:

#import "Dbaccess.h"

@implementation Dbaccess
sqlite3 *database; // 添加一个类变量保存对数据库的引用
-(id)init{ 重新类初始化方法
    if (self = [super init]) {
        [self initializeDatebase]; //在类初始化的时候 调用initializeDatebase方法
    }
    return self;
}
-(void)initializeDatebase{ //初始化数据库
    NSString *path = [[NSBundle mainBundle] pathForResource:@"catalog" ofType:@"db"];定义数据表格路径
    if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) { //打开数据表格,如果成功 输出log
        NSLog(@"opening database");
    }else{// 否则 关闭数据库,并用NSAssert1函数调试,抛出异常

        sqlite3_close(database); //
        NSAssert1(0, @"faildd to open database:'%s'.", sqlite3_errmsg(database));
    }
}
-(void)closeDatabase{ // 关闭数据库
    if (sqlite3_close(database) != SQLITE_OK) {// 如果没有正常关闭,抛异常
        NSAssert1(0, @"error:faild to close database:'%s'.", sqlite3_errmsg(database));
    }
}
-(NSMutableArray *)getAllproducts{ 获取所有的数据,封装成模型,并返回所有的模型对象
    NSMutableArray *products = [[NSMutableArray alloc]init]; // 生成一个可变数组
    const char *sql = "SELECT product.ID,product.Name,\ \\设置一个变量来储存需要用到的sql语句
    Manufacture.name,product.details,product.Price,\
    product.Quantityonhand,country.country, \
    product.Image FROM Product,Manufacture, \
    Country where manufacture.manufactureID = product.manufactureID \
    and product.countryforginID = country.countryid"; \\语句设置完毕
    sqlite3_stmt *statement; // 创建一个sqlite语句对象 该对象用于执行sql语句
    int sqlresult = sqlite3_prepare_v2(database, sql, -1, &statement, nil);//,连接数据库与sql语句,并返回结果
    if (sqlresult == SQLITE_OK) { 如果返回结果为SQLTME_OK 对表格行数进行遍历
        while (sqlite3_step(statement) == SQLITE_ROW) {
            Product *product = [[Product alloc]init]; 每返回一行,生成一个product对象
            char *name = (char *)sqlite3_column_text(statement, 1); 定义字符串name 保存从表格中取到的第一列
            该函数索引是基于0的所以name是第1列
            product.name = (name) ? [NSString stringWithUTF8String:name]:@""; 对Product的name属性进行赋值。
            如果name不为空,则product.name = name(字符串内容),如果为空,则product.name = ""(即空字符串)
            char *manufacture = (char *)sqlite3_column_text(statement, 2);
            product.manufacture = (manufacture) ? [NSString stringWithUTF8String:manufacture] : @"";
            char *details = (char *)sqlite3_column_text(statement, 3);
            product.details = (details) ? [NSString stringWithUTF8String:details] : @"";
            char *countryforgin = (char *)sqlite3_column_text(statement, 6);
            product.countryforgin = (countryforgin) ? [NSString stringWithUTF8String:countryforgin] : @"";
            char *image = (char *)sqlite3_column_text(statement, 7);
            product.image = (image) ? [NSString stringWithUTF8String:image] : @"";
            // 以上为字符串属性赋值,为了安全,校验了一下是否为空,而对于int数据类型,则直接获取赋值
            product.ID = sqlite3_column_int(statement, 0);直接取出数据对Product的ID属性赋值
            product.price = sqlite3_column_double(statement, 4);
            product.quantity = sqlite3_column_int(statement, 5);
            [products addObject:product];// 将赋值好的模型添加进数组
        }
        sqlite3_finalize(statement);
    }else{
        NSLog(@"problem with the database:");
        NSLog(@"%d",sqlresult);
    }
    return products;// 返回包含Product的数组 
}

  先在数量已经整整读取完毕,剩下的就是体现界面代码编写了,首先是master界面的控制器,先河入自定义的四个类,因为肯定要用到模型和数据库访问类。,然后大家必要一个特性来保存DBAccess获取到的有着模型对象,也就是一个数组,所以MasterViewController.h的代码如下:

#import <UIKit/UIKit.h>
#import "Product.h" // 导入模型类
#import "Dbaccess.h" // 导入数据访问类
@class DetailViewController;

@interface MasterViewController : UITableViewController

@property (strong, nonatomic) DetailViewController *detailViewController; 模板自带属性,保存从控制器
@property(strong,nonatomic)NSMutableArray *products; 定义数组属性保存模型对象
@end

  然后编写MasterViewController.m的内容代码如下:移除了有的无需使用的代码,同时移除了模版本身提供的edit和add按钮的默许代码,因为大家只须要展现即可

#import "MasterViewController.h"
#import "DetailViewController.h"

@interface MasterViewController ()

@property NSMutableArray *objects;
@end

@implementation MasterViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    Dbaccess *dbaccess = [[Dbaccess alloc]init]; //初始化dba类对象 同时初始化数据库
    self.products = [dbaccess getAllproducts]; 调用getallproduct方法 赋值给数组
    [dbaccess closeDatabase];//关闭数据库
    self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];//设置界面
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.products count]; // 设返回值为数组的长度即product的个数
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifire = @"cell";//
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifire];
    if (cell == nil) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifire];
        Product *product = [self.products objectAtIndex:indexPath.row];
        cell.textLabel.text = product.name;// 设置cell标题为product的name
    }
    return cell;
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return NO if you do not want the specified item to be editable.
    return NO; // 禁止编辑 因为模板的cell是可编辑的,我们只需要展示
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    self.detailViewController.detailItem = [self.products objectAtIndex:indexPath.row];
// 在选中某一个cell的时候为detailViewController的detailItem属性赋值
[self.navigationController pushViewController:self.detailViewController animated:YES]; // push到从界面
}
 @end

     
在编制从界面也就是商品详情界面的代码此前,首先要搭一下界面的UI,效果如下:值得注意的是,最外层有一个晶莹剔透按钮,为了页面美观一些,禁用了回去按钮,可以用透明按钮来落实轻点界面即重回的职能

sqlite 7  

   
 在从界面控制器种关联标签属性,并且大家须要一个detailItem来保存在master界面中选中的商品,因而DetailViewController.h代码如下:

#import <UIKit/UIKit.h>
#import "Product.h"//导入模型类,因为需要用到模型
@interface DetailViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *namelabel;//设置文本标签关联,一定要与storyboard里的文本对应连线
@property (weak, nonatomic) IBOutlet UILabel *manufacturelabel;
@property (weak, nonatomic) IBOutlet UILabel *detailslabel;
@property (weak, nonatomic) IBOutlet UILabel *pricelabel;
@property (weak, nonatomic) IBOutlet UILabel *quantitylabel;
@property (weak, nonatomic) IBOutlet UILabel *countrylabel;
@property (strong, nonatomic) id detailItem;// 设置属性保存选中的商品信息
@end

    然后举行DetailViewController.m的编纂,代码如下:

#import "DetailViewController.h"

@interface DetailViewController ()

@end

@implementation DetailViewController

#pragma mark - Managing the detail item

- (void)setDetailItem:(id)newDetailItem {// 重写Detailitemset方法,可以适时刷新展示的商品内容
    if (_detailItem != newDetailItem) {
        _detailItem = newDetailItem;

        // Update the view.
        [self configureView];// 重新对展示内容赋值
    }
}

- (void)configureView {// 对文本进行赋值具体实现
    Product *theproduct = (Product *) self.detailItem;
    self.namelabel.text = theproduct.name;
    self.manufacturelabel.text = theproduct.manufacture;
    self.detailslabel.text = theproduct.details;
    self.detailslabel.text = theproduct.details;
    self.pricelabel.text = [NSString stringWithFormat:@"%.2f",theproduct.price];
    self.quantitylabel.text = [NSString stringWithFormat:@"%d",theproduct.quantity];
    self.countrylabel.text = theproduct.countryforgin;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [self configureView];// 对文本进行赋值
}
- (IBAction)comback:(id)sender {//监听覆盖界面的按钮点击,触发则返回上一界面
    [self.navigationController popViewControllerAnimated:YES];// 返回产品栏页面
}
@end

   
以上,所有内容达成,博客代码可能跟源代码略有出入,所有数据都足以在https://github.com/huafushengweirui/data/tree/master/two拿到。数据和知识点来自Patrick
Alessi的ios数据库应用高级编程一书当然大家从不接纳到一些数据,如图片编号等,那事关到自定义cell来突显,本篇重点在于如何从数据库获取数据而不是tableview的用法。在实际上利用中,可能还涉嫌到对数据的参数化查询,以及将读取的多寡缓存等各种方面。那里只是不难介绍一下ios和sqlite的相互。

网站地图xml地图