随笔杂记

  • 类别
    • 是一种为现有的类添加新方法的方式
    • 利用Objective-C的动态运行时分配机制,可以为现有的类添加新方法

添加的方法不可以添加新的实例变量,类别生命中没有实例变量部分

类别的局限性有两方面局限性:

  • (1)无法向类中添加新的实例变量,类别没有位置容纳实例变量。
  • (2)名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。无法添加实例变量的局限可以使用字典对象解决

类别主要有3个作用:(与继承的区别)

  • (1)将类的实现分散到多个不同文件或多个不同框架中。
  • (2)创建对私有方法的前向引用。
  • 三、使用类别创建前向引用
  • 如果其他类中的方法未实现,在你访问其他类的私有方法时编译器报错
  • 这时使用类别,在类别中声明这些方法(不必提供方法实现),编译器就不会再产生警告
    • (3)向对象添加非正式协议。 继承可以增加,修改或者删除方法,并且可以增加属性。

类别只能扩充方法,而不能扩充成员变量。

 

无法添加实例变量的局限可以使用字典对象解决

runtime 机制 为类别填加实例变量。

定义:

@interface UIView(AddVariables)

 

@property (nonatomic, retain) NSString *viewName;

 

@end

实现:

// 定义存取的Key

static const char *viewNameKey = "viewNameKey";

@implementation UIView(AddVariables)

// get方法

- (NSString *)viewName {

    return (NSString *)objc_getAssociatedObject(self, viewNameKey);

}

// set方法

- (void)setViewName:(NSString *)newViewNameKey {

    objc_setAssociatedObject(self, viewNameKey, newViewNameKey, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

 

 

 

协议

  • 协议(protocol)类似于java语言里的接口(interface),定义了一组方法,而不提供具体实现, 只有那些“遵守”(conform to)或“采用”(adopt)了这些Protocol的类来给出自己的实现。
  • 协议不是类本身,它们仅定义了其它对象有责任实现的接口。

 

 

跳转至tableView顶端

[_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] 

atScrollPosition:UITableViewScrollPositionTop animated:YES];

 

刷新当前行的图片数据

   self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

[self.tableView reloadata],因为会刷新整个cell,浪费性能。

 

 

正则匹配

NSError*error =nil;

NSMutableAttributedString *string;

[string addAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f]} range:NSMakeRange(0, string.length)];

 

NSRegularExpression*re = [NSRegularExpression regularExpressionWithPattern:string 

options:NSRegularExpressionCaseInsensitive error:&error];

 

 

主线程

(iOS UI操作必须在主线程执行)。 

 

 

iOS异步任务一般有3种实现方式:

  • NSOperationQueue
  • GCD
  • NSThread

 

 

关于block闭包:就是能够读取其它函数内部变量的函数

block 配合上 dispatch_queue,可以方便地实现简单的多线程编程和异步编程(GCD)

(1)遍历数组或者字典

(2)视图动画

(3)排序

(4)通知

(5)错误处理

(6)多线程

(7)封装变化点

block的实现是基于指针和函数指针。

注意点:

1.在使用block前需要对block指针做判空处理。不判空直接使用,一旦指针为空直接产生崩溃

2.将block赋值为空,是解掉循环引用的重要方法。

3.使用方将self或成员变量加入block之前要先将self变为__weak

4.在多线程环境下(block中的weakSelf有可能被析构的情况下),需要先将self转为strong指针,避免在运行到某个关键步骤时self对象被析 构。

 

 

Runloop

3、Runloop内部逻辑:关键在两个判断点(是否睡觉,是否退出)

         - 代码实现:

         - 函数作用栈显示:

 

4、Runloop本质:mach port和mach_msg()。

 

5、如何处理事件:

         - 界面刷新:

         - 手势识别:

         - GCD任务:

         - timer:(与CADisplayLink)

         - 网络请求:

 

6、应用:

         - 滑动与图片刷新;

         - 常驻子线程,保持子线程一直处理事件

Runloop的寄生于线程:

一个线程只能有唯一对应的runloop;但这个根runloop里可以嵌套子runloops;

 

自动释放池寄生于Runloop:

程序启动后,主线程注册了两个Observer监听runloop的进出与睡觉。

一个最高优先级OB监测Entry状态;

一个最低优先级OB监听BeforeWaiting状态和Exit状态。

 

线程(创建)-->runloop将进入-->最高优先级OB创建释放池-->runloop将睡-->最低优先级OB销毁旧池创建新池-->runloop将退出-->最低优先级OB销毁新池-->线程(销毁)

 

Runloop有两个关键判断点,一个是通过msg决定Runloop是否等待,一个是通过判断退出条件来决定Runloop是否循环

 

 

网络请求:

关于网络请求的接口:

最底层是CFSocket层,

然后是CFNetwork将其封装,

然后是NSURLConnection对CFNetwork进行面向对象的封装

 

 

SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL。

 

SQLLite

. 弱类型:数据存储类型可以不同(主键除外)

SQLite采用的是动态数据类型

 

SQLite中采用了Page Cache的缓冲优化机制

优化策略: 1. 编译时参数SQLITE_TEMP_STORE:

2. 运行时指令temp_store pragma:

3. 临时文件的大小:

4.SQLITE_DEFAULT_TEMP_CACHE_SIZE编译期参数可以用于指定临时表和索引

在占用多少 Cache Page时才需要被刷新到磁盘文件,该参数的缺省值为500页。

ACID(Atomic, Consistent, Isolated, and Durable)原子性,一致性,独立性,持久性

1.在SQLite中,锁和并发控制机制都是由pager_module模块负责处理

2.它不关心数据的存储结构,如B-tree ,编码格式,索引,默认统一大小为一页(page),1024字节

 

文件锁:

1). UNLOCKED:(无锁)缺省状态。

2). SHARED:(共享锁)只能读操作(并发的),不能写操作

3). RESERVED: (保留锁)一个进程将来的某个时间会执行写操作,同一时间只能存在一个保留锁(写)和多个共享锁(读)

(即如果存在了一个保留锁,则其他的写操作就被屏蔽啦,其他写操作失败)

4). PENDING: (等待锁)此时所有的读操作都不被允许(禁止新的读取),等待现有的共享锁全部消失,进行写操作(俗称挂起状态)

5). EXCLUSIVE:(排他锁)为了最大化并发效率,SQLite将会最小化排他锁被持有的时间总量。

 

 

某一进程要想在数据库上执行写操作,

那么必须先获取共享锁,

在共享锁获取之后再获取 保留锁,  -----------------------------    同一时刻只有一 个进程可以持有一把保留锁

当准备写的时候如果还有共享锁存在,就换成等待锁————————没有共享锁就直接获取排他锁

写操作的时候必须获取该数据库的排他锁

1、成功获取保留锁之后,该写进程将创建回滚日志

2、进行完写操作之后,一定要删除日志文件和从所有数据库中删除掉排他锁和PENDING锁,解除对文件的控制。

 

 

 

 

先将sql语句编译成字节码,之后交给自带的虚拟机去执行(无需解析成复杂的数据结构)

核心接口

sqlite3_open    返回的 database_connection对象

sqlite3_prepare   将SQL文本转换为prepared_statement对象 ,返回该对象的指针,初始化为待 执行的状态

sqlite3_step    评估prepared_statement对象 prepared_statement对象的内部指针将指向其返回的结果集的第一行

sqlite3_column  由一组相关的接口函数来完成该功能,其中每个函数都返回不同 类型的数据

sqlite3_finalize 用于销毁prepared statement对象,防止内存泄露

sqlite3_close 关闭之前打开的database_connection对象,之前必须销毁所有与其有关的prepared_statements

 

通过SQLite自带 的ATTACH命令可以在一个连接中方便的访问多个数据库

 

参数绑定 

涉及的API接口:sqlite3_reset和sqlite3_bind。

1.占位符的使用

2.sqlite3_prepare_v2的执行效率往往要低于 sqlite3_step

3.

不带参数绑定的情况下

strSQL=(“insert into testtable values(%d)",i);

 sqlite3_prepare_v2(strSQL); 

sqlite3_step(prepared_statement); 

sqlite3_finalize(prepared_stmt);

2. 参数绑定的情况下插入多条数据。

string strSQLWithParameter = "insert into testtable values(?)"; 

sqlite3_prepare_v2(..., strSQL);
 for (int i = 0; i < MAX_ROWS; ++i) {

sqlite3_bind(...,i);

 sqlite3_step(prepared_stmt); 

sqlite3_reset(prepared_stmt);

}

 

总结:

使用动态绑定,可以节省大量的sqlite3_prepare_v2函数调用次数,从而节省了多次将同一SQL语句编译成SQLite内部识别的字节码所用的时间

 

SQL 语句

1. schema

sqlite> .schema testtable2
 CREATE TABLE testtable2(first_col INT);

.schema命令是sqlite3命令行工具的内置命令,用于显示当前数据表的CREATE TABLE语 句。

 .header on --查询结果将字段名作为标题输出。

 

2. 在指定数据库创建表:

sqlite> ATTACH DATABASE 'd:/mydb.db' AS mydb;

  sqlite> CREATE TABLE mydb.testtable (first_col integer); 需要指定,默认会在当前连接的main数据库中创建

 

Detach  卸载数据库

 

3."IF NOT EXISTS"从句:

sqlite> CREATE TABLE IF NOT EXISTS testtable (first_col integer);

 

4. CREATE TABLE ... AS SELECT:

. 在SQLite中,NULL值被视为和其他任何值都是不同的 

sqlite> CREATE TABLE testtable2 AS SELECT * FROM testtable;

5. 主键约束

sqlite> CREATE TABLE testtable2 (

＀  first_col integer, 

＀  second_col integer, 

＀   PRIMARY KEY (first_col,second_col) >

＀   ); 

. 6. 唯一性约束: 
--直接在字段的定义上指定唯一性约束。 
sqlite> CREATE TABLE testtable (first_col integer UNIQUE); 

 

. 7. 为空(NOT NULL)约束: 

. 8. 检查性约束: 
sqlite> CREATE TABLE testtable (first_col integer CHECK (first_col < 5));


 

. 转换表达式:

.  CAST(expr AS target_type)

 

比较运算中

如果其中一个操 作数为NULL,那么它们的结果亦为NULL

 

 

. 1. 修改表名: 

.  sqlite> ALTER TABLE testtable RENAME TO testtable2; 

. 2. 新增字段: 

sqlite> ALTER TABLE testtable ADD COLUMN second_col integer; 

 

. 表的删除: 

. DROP TABLE IF EXISTS testtable; 

 

聚合函数

返回一个把所有查询结果用逗号连接的字符串

SELECT group_concat(app.appName ,  ', ') FROM app

 

 

内置函数

返回移除包含天的字符串

SELECT ltrim(app.appName,'天') from app

--返回当前年中10月份的第一个星期二是日期。
  SELECT date('now','start of year','+9 months','weekday 2');

 

索引和数据分析

--创建唯一性索引,该索引规则和数据表的唯一性约束的规则相同,即NULL和任何值都不 同,包括NULL本身。

CREATE UNIQUE INDEX table_idx ON table(second_col DESC);

.indices命令的输出可以看出当前表的所有索引

数据分析

和PostgreSQL非常相似,SQLite中的ANALYZE命令也同样用于分析数据表和索引中的数 据,并将统计结果存放于SQLite的内部系统表中,以便于查询优化器可以根据分析后的统计 数据选择最优的查询执行路径,从而提高整个查询的效率

 

数据清理:

在SQLite中,仅支持清理当前连接中的主数据库,而不能清理其它Attached数据库。

sqlite> VACUUM;

 

 

SQLite中主要产生以下七种临时文件,如:

1). 回滚日志。
2). 主数据库日志。
3). SQL语句日志。
4). 临时数据库文件。
5). 视图和子查询的临时持久化文件。
6). 临时索引文件。
7). VACUUM命令使用的临时数据库文件。

 

 

 

数据库和事物

如果一个事务包含多个Attached数据库操作,那么该事务仍然是原子的

 

 

 

 

 

 

线程

注意回到主线程,有些回调并不在主线程中,所以这里必须回到主线程

   dispatch_async(dispatch_get_main_queue(), ^{

        

       [self showMsg:str];

  });

 

  1. /**始终记住, 通过模型来修改显示. 而不要试图直接修改显示*/  

异步获取图片,主线程刷新图片 ( 使用SDWebImage来完成这个功能. 针对ImageView.就是一句话  )

  1. [self.queue addOperationWithBlock: ^{  
  2. NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]]; //得到图像数据  
  3. UIImage *image = [UIImage imageWithData:imgData];  
  4. //在主线程中更新UI  
  5. [[NSOperationQueue mainQueue] addOperationWithBlock: ^{  
  6. //通过修改模型, 来修改数据  
  7. app.image = image;  
  8. //刷新指定表格行  
  9. [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];  
  10. }];  
  11. }];  

 

posted @ 2015-11-19 21:27  韩小醋  阅读(198)  评论(0编辑  收藏  举报