随笔杂记
- 类别
- 是一种为现有的类添加新方法的方式
- 利用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];
});
- /**始终记住, 通过模型来修改显示. 而不要试图直接修改显示*/
异步获取图片,主线程刷新图片 ( 使用SDWebImage来完成这个功能. 针对ImageView.就是一句话 )
- [self.queue addOperationWithBlock: ^{
- NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]]; //得到图像数据
- UIImage *image = [UIImage imageWithData:imgData];
- //在主线程中更新UI
- [[NSOperationQueue mainQueue] addOperationWithBlock: ^{
- //通过修改模型, 来修改数据
- app.image = image;
- //刷新指定表格行
- [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
- }];
- }];