学习内容
欢迎关注我的iOS学习总结——每天学一点iOS:https://github.com/practiceqian/one-day-one-iOS-summary
FMDB数据库的使用
-
什么是FMDB
- FMDB使用OC语言封装了sqlite的C语言API,可以在iOS平台使用
-
FMDB的优点
-
使用起来比较方便,省去了麻烦,冗余的C代码
-
相比coreData框架更加轻量级和灵活
-
提供了多线程安全的数据库操作方法,防止数据读取的混乱
-
-
创建数据库
-
根据数据库名创建数据库(已存在则打开)
//懒加载数据库 - (FMDatabase *)fmDB{ if (!_fmDB) { //获取Documents文件夹路径 NSString* dbPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; //在Documents文件夹路径后追加数据库名"picture.sqlite"(Documents/picture.sqlite) NSString* path = [dbPath stringByAppendingPathComponent:@"picture.sqlite"]; //根据指定的路径创建数据库 _fmDB = [FMDatabase databaseWithPath:path]; } return _fmDB; }
-
path为空字符则在临时目录中创建数据库,当fmdb的连接关闭时,数据库也会被删除
-
path为nil时会在内存中创建数据库,fmdb连接关闭时,数据库被删除
-
-
数据库操作
-
在FMDB中除了查询以外的操作都被称作更新,使用executeUpdate:方法更新
-
//创建数据库 NSString* sql = @"insert into t_schedule" NSString* createSql = @"create table if not exists t_schedule (id integer primary key autoincrement, name text not null, teacher text not null, weekId integer not null, time text not null, weekday integer not null)"
-
//插入数据 NSStrng* sql = @"insert into t_schedule (name,teacher,weekId,time,weekday) values (?,?,?,?,?)"; //第一个参数为sql语句,后面跟着参入的数据 BooL res = [db executeUpdate:sql,params];
-
//查询数据 NSString* sql = @"select * from t_schedule"; FMResultSet* res = [db executeQuery:sql]; while([res next]){ //可以根据列名或者列的下标来取数据 NSString* name = [res stringForColumn:@"name"]/[res stringForColumnIndex:0]; ... }
-
//关闭数据库 [db close]
-
//如果sql中含有空值,那么应该使用[NSNull null]来代替nil NSStrng* sql = @"insert into t_schedule (name,teacher,weekId,time,weekday) values (?,?,?,?,?)"; BooL res = [db executeUpdate:sql,@"Computer",@"Jack",@(1),@"08:00~09:40",[NSNull null]];
-
-
使用FMDataBaseQueue确保线程安全
-
尽量不要创建一个FMDatabase对象并在多个线程中使用该对象,否则的话容易读到脏数据或者造成写入异常
-
可以实例化一个FMDatabaseQueue对象,并在不同的线程中使用该对象,FMDatabaseQueue会在多个线程中同步和协调
-
NSString* path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString* dbPath = [path stringByAppendingPathComponent:@"schedule_queue.sqlite"]; FMDatabaseQueue* queue = [FMDatabaseQueue databaseQueueWithPath:dbPath]; [queue inDatabase:^(FMDatabase *db) { [db executeUpdate:@"create table if not exists t_schedule (id integer primary key autoincrement, name text not null, time text not null, teacher text not null)"]; [db executeUpdate:@"insert into t_schedule (name,time,teacher) values (?,?,?)",@"Hadoop大数据分析",@"上午九点",@"孙老师"]; }];
-
-
事务操作
-
事务操作是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么不执行,是一个不可分割的工作单位,事务由事务开始和事务结束之间的全部数据库操作组成
-
//使用FMDatabaseQueue开启事务操作 [queue inTransaction:^(FMDatabase * _Nonnull db, BOOL * _Nonnull rollback) { NSString *sql = @""; NSString *sql2 = @""; BOOL res1 = [db executeUpdate:sql]; BOOL res2 = [db executeUpdate:sql2]; if (res1&&res2) { PSLog(@"success"); }else{ PSLog(@"fail,start rollback"); [db rollback]; } }];
-
UIViewController的生命周期(ARC环境下、PUSH)
- 单个ViewController的生命周期
- initWithCoder:(NSCoder*)coder(如果使用StoryBoard或者xib)
- loadView:加载或创建一个view,赋值给self(视图控制器自身)
- viewDidLoad:view加载完毕
- viewWillAppear:控制器的view将要显示
- viewWillLayoutSubViews:控制器的view将要布局子控件
- viewDidLayoutSubViews:控制器的view布局子控件完成
- viewDidAppear:控制器的view完全显示
- viewWillDisappear:控制器的view即将消失
- viewDidDisappear:控制器的view完全消失
- push的情况下(假设这里有ViewController1和ViewController2)
- initWithCoder:(ViewController2)
- loadView(ViewController2)
- viewDidLoad(ViewController2)
- viewWillDisAppear(ViewController1)
- viewWillAppear(ViewController2)
- viewWillLayoutSubViews(ViewController2)
- viewDidLayoutSubViews(ViewController2)
- viewWllLayoutSubViews(ViewController1)
- viewDidLayoutSubViews(ViewController1)
- viewDidDisAppear(ViewController1)
- viewDidAppear(ViewController2)
- pop的情况下(从ViewController2—>ViewController1)
- viewWillDisappear(ViewController2)
- viewWIllAppear(ViewController1)
- viewDidDisappear(ViewController2)
- viewDidAppear(ViewController1)
导航栏样式的修改(UINavigationController)
-
在NavigationController的Stack存储结构下,每当Stack中的任意ViewController修改了导航栏的样式,那么也会影响到其他视图控制器导航栏的样式
- A控制器导航栏为绿色,push->B控制器,修改B控制器导航栏颜色为紫色,pop->A,那么A控制器的导航栏也会为紫色
- 在导航栏的Stack中,每一个ViewController对导航栏的操作都会永久的改变其样式,在开发中需要坚持“谁修改谁复原的原则”,否则会造成导航栏样式的混乱(在一些极端的情况下还会引起Stack混乱),造成crash
-
导航栏样式转换的时机(一般都是在viewwillappear和viewwilldisappear中进行设置)
-
- (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; //MARK:change the navigationbar style } - (void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; //MARK:restore the navigationbar style }
-
-
导航栏的样式变化(主要有两种)
-
导航栏的显示与否
-
[self.navigationController setNavigationBarHidden:YES animated:YES]
-
尽量使用带有animated参数的API,如果不带有animated可能会造成导航栏转场过程中的闪现,背景错乱等问题
-
-
导航栏的颜色改变
- 当translucent属性(透明)为yes时,直接设置backgroundColor
- 当translucent属性为no时,需要设置setBackgroundImage:[UIImage new] forBarMetrics:方法
-
-
Transparent、translucent、opaque、opacity区别
-
Transparent 完全透明
-
translucent 半透明
-
Opaque 不透明
-
这三个词都是一种状态不需要量化,所以与这三个词相关的属性一般都是布尔类型
-
opacity和Alpha一般都是用来形容透明度,在前端中,opacity用来给整个元素设置透明度,而Alpha是给元素的某个属性设置透明度(backgroundColor、bordercolor等)
- view中的alpha属性和view.layer.opacity属性是相等作用的
-
设置全透明导航栏的正确方法
-
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault]; self.navigationController.navigationBar.shadowImage = [UIImage new];
-
-
设置导航栏的图标
-
//设置返回标志图 self.navigationController.navigationBar.backIndicatorImage = [UIImage imageNamed:@"back"]; //设置返回标志过渡遮罩图 self.navigationController.navigationBar.backIndicatorTransitionMaskImage = [UIImage imageNamed:@"back"];
-