FMDB数据库的简单使用、VIewController的生命周期、关于导航栏的一些知识

学习内容

欢迎关注我的iOS学习总结——每天学一点iOS:https://github.com/practiceqian/one-day-one-iOS-summary

FMDB数据库的使用

  • 什么是FMDB

    • FMDB使用OC语言封装了sqlite的C语言API,可以在iOS平台使用
  • FMDB的优点

    • 使用起来比较方便,省去了麻烦,冗余的C代码

    • 相比coreData框架更加轻量级和灵活

    • 提供了多线程安全的数据库操作方法,防止数据读取的混乱

  1. 创建数据库

    • 根据数据库名创建数据库(已存在则打开)

      //懒加载数据库
      - (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连接关闭时,数据库被删除

  2. 数据库操作

    • 在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]];
      
  3. 使用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大数据分析",@"上午九点",@"孙老师"];
      }];
      
  4. 事务操作

    • 事务操作是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么不执行,是一个不可分割的工作单位,事务由事务开始和事务结束之间的全部数据库操作组成

    • //使用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)

  1. 单个ViewController的生命周期
    • initWithCoder:(NSCoder*)coder(如果使用StoryBoard或者xib)
    • loadView:加载或创建一个view,赋值给self(视图控制器自身)
    • viewDidLoad:view加载完毕
    • viewWillAppear:控制器的view将要显示
    • viewWillLayoutSubViews:控制器的view将要布局子控件
    • viewDidLayoutSubViews:控制器的view布局子控件完成
    • viewDidAppear:控制器的view完全显示
    • viewWillDisappear:控制器的view即将消失
    • viewDidDisappear:控制器的view完全消失
  2. 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)
  3. pop的情况下(从ViewController2—>ViewController1)
    • viewWillDisappear(ViewController2)
    • viewWIllAppear(ViewController1)
    • viewDidDisappear(ViewController2)
    • viewDidAppear(ViewController1)

导航栏样式的修改(UINavigationController)

  1. 在NavigationController的Stack存储结构下,每当Stack中的任意ViewController修改了导航栏的样式,那么也会影响到其他视图控制器导航栏的样式

    • A控制器导航栏为绿色,push->B控制器,修改B控制器导航栏颜色为紫色,pop->A,那么A控制器的导航栏也会为紫色
    • 在导航栏的Stack中,每一个ViewController对导航栏的操作都会永久的改变其样式,在开发中需要坚持“谁修改谁复原的原则”,否则会造成导航栏样式的混乱(在一些极端的情况下还会引起Stack混乱),造成crash
  2. 导航栏样式转换的时机(一般都是在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
      }
      
  3. 导航栏的样式变化(主要有两种)

    • 导航栏的显示与否

      • [self.navigationController setNavigationBarHidden:YES animated:YES]
        
      • 尽量使用带有animated参数的API,如果不带有animated可能会造成导航栏转场过程中的闪现,背景错乱等问题

    • 导航栏的颜色改变

      • 当translucent属性(透明)为yes时,直接设置backgroundColor
      • 当translucent属性为no时,需要设置setBackgroundImage:[UIImage new] forBarMetrics:方法
  4. 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];
      
  5. 设置导航栏的图标

    • //设置返回标志图
      self.navigationController.navigationBar.backIndicatorImage = [UIImage imageNamed:@"back"];
      //设置返回标志过渡遮罩图
      self.navigationController.navigationBar.backIndicatorTransitionMaskImage = [UIImage imageNamed:@"back"];
      
原文地址:https://www.cnblogs.com/chenprice/p/12874372.html