单例就是在我们的项目中这个类只有一个对象,像数据库的操作、一键换肤、开关全局全局推送、切换字号等等功能都用到了这中模式,我们以数据库操作来举一个例子
// DBManger.m
#import "DBManger.h"
@implementation DBManger{
// 数据库成员变量
FMDatabase *_fmdb;
// 线程锁
NSLock *_lock;
}
static DBManger *_db;
+ (instancetype)shareDBManger{
static dispatch_once_t predicate;
// 这里的代码只执行一次
dispatch_once(&predicate,^{
_db = [[DBManger alloc] init];
});
return _db;
}
//初始化数据库 创建数据库和表(只需要创建一次)
- (instancetype)init{
self = [super init];
if (self) {
// 初始化线程锁
_lock = [[NSLock alloc] init];
/**
* 1.创建数据库
*
*/
//根据路径创建数据库
NSString *dataBasePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/ljh.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
LJXLog(@"-=-=-=-=-=%@",dataBasePath);
if (![fileManager fileExistsAtPath:dataBasePath]) {
_fmdb = [FMDatabase databaseWithPath:dataBasePath];
LJXLog(@"数据库创建成功");
}else{
_fmdb = [[FMDatabase alloc] initWithPath:dataBasePath];
LJXLog(@"数据库已存在");
}
/**
*2.打开数据库
*/
BOOL isOpen = [_fmdb open];
if (isOpen) {
LJXLog(@"打开数据库成功!");
// 资产列表
if ([self isTableOK:_fmdb andTableName:@"asset_list"]) {
LJXLog(@"资产列表已经存在");
}else{
NSString *assetList=@"CREATE TABLE IF NOT EXISTS asset_list(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, type INTEGER NOT NULL, status INTEGER NOT NULL);";
BOOL isSuccess2=[_fmdb executeUpdate:assetList];
if (isSuccess2) {
LJXLog(@"资产列表创建成功");
}else{
LJXLog(@"资产列表表创建失败");
}
}
// 交易记录
if ([self isTableOK:_fmdb andTableName:@"deal_record"]) {
LJXLog(@"交易记录表已经存在");
}else{
NSString *dealRecord=@"CREATE TABLE IF NOT EXISTS deal_record(id INTEGER PRIMARY KEY AUTOINCREMENT, dealnum TEXT NOT NULL, type INTEGER NOT NULL, status INTEGER NOT NULL , date TEXT NOT NULL);";
BOOL isSuccess2=[_fmdb executeUpdate:dealRecord];
if (isSuccess2) {
LJXLog(@"交易记录表创建成功");
}else{
LJXLog(@"交易记录表创建失败");
}
}
// 投资记录
if ([self isTableOK:_fmdb andTableName:@"invest_record"]) {
LJXLog(@"投资记录表已经存在");
}else{
NSString *investRecord=@"CREATE TABLE IF NOT EXISTS invest_record(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, money TEXT NOT NULL, date TEXT NOT NULL);";
BOOL isSuccess2=[_fmdb executeUpdate:investRecord];
if (isSuccess2) {
LJXLog(@"投资记录表创建成功");
}else{
LJXLog(@"投资记录表创建失败");
}
}
NSArray *investArr = [self getAllInvestData];
if (investArr.count == 0) {
for(int i = 0; i < 20 ;i ++){
if ([self insertDataWithName:@"张三" andMoney:@"10000000.00" andDate:nil]) {
LJXLog(@"插入成功");
}else{
LJXLog(@"插入失败");
}
}
}
NSInteger test = @1;
NSArray *assetArr = [self getAllAssetData];
if (assetArr.count == 0) {
for(int i = 0; i < 20 ;i ++){
if ([self insertDataWithName:@"这仅仅是一条测试数据啊" andType:test andStatus:test]) {
LJXLog(@"插入成功");
}else{
LJXLog(@"插入失败");
}
}
}
NSArray *dealArr = [self getAllDealData];
if (dealArr.count == 0) {
for(int i = 0; i < 20 ;i ++){
if ([self insertDataWithDealNum:@"测试数据" andType:test andStatus:test andDate:nil]) {
LJXLog(@"插入成功");
}else{
LJXLog(@"插入失败");
}
}
}
// [_fmdb close];
}else{
LJXLog(@"打开数据库失败!");
[_fmdb close];
}
}
return self;
}
#pragma mark 插入一条数据
//1.投资记录
- (BOOL)insertDataWithName:(NSString *)name andMoney:(NSString *)money andDate:(NSString *)date{
//当对数据库的数据做修改(插入,修改,删除)操作的 时候,为了保证数据的原子性,所以需要加锁
//加锁:为了保证只有同一个线程在操作此数据
[_lock lock];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"YYYY-MM-dd HH:mm"];
NSString *time = [formatter stringFromDate:[NSDate date]];
//1.创建sql语句
NSString *sqlStr=@"INSERT INTO invest_record(name,money,date) values(?,?,?)";
//2.执行sql语句
BOOL isSuccess=[_fmdb executeUpdate:sqlStr,name,money,time];
//3.3 判断是否成功
//解锁:当前线程操作完成之后,可以让其它线程访问
[_lock unlock];
return isSuccess;
}
//判断数据库中是否存在某张表
- (BOOL)isTableOK:(FMDatabase *)db andTableName:(NSString *)tableName{
FMResultSet *rs = [db executeQuery:@"select count(*) as 'count' from sqlite_master where type ='table' and name = ?", tableName];
while ([rs next]){
// just print out what we've got in a number of formats.
NSInteger count = [rs intForColumn:@"count"];
NSLog(@"isTableOK %ld", count);
if (0 == count){
return NO;
}
else{
return YES;
}
}
return NO;
}
@end