6.UIView与CALayer有什么区别
UIView管理绘制与事件处理(尤其是触摸事件).CALayer完全关乎绘制.事实上,UIView依靠CALayer来管理绘制.CALayer不处理用户的交互
每个UIView都有一个CALayer用于绘制.而且每个CALayer都可以拥有子图层
7.iOS怎么做数据的持久化
沙箱目录
iOS应用程序只能访问自己的目录,这个目录称为沙箱目录,应用程序间禁止数据的共享和访问
1>Documents目录:用于存储非常大的文件或需要频繁更新的数据,能够进行iTunes或iCloud备份.
// documentDirectory是只有一个元素的数组
NSArray *documentDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *myDocPath = [documentDirectory objectAtIndex:0];
或
NSString *myDocPath = [documentDirectory lastObject];
2>Library目录:下有Preferences(用于存放应用程序的设置数据)和Caches目录(存储缓存文件)
3>tmp目录:临时文件目录,用户可以访问它.不能进行iTunes和iCloud的备份
NSString *tmpDirectory = NSTemporaryDirectory();
持久化方式:属性列表,对象归档,SQLite数据库,Core Data
属性列表:集合对象可以读写到属性列表文件中
NSArray类的方法(NSDictionary的方法类似):
- arrayWithContentsOfFile
- initWithContentOfFile
-
writeToFile:atomically 该方法把NSArray对象写入到属性列表文件中,第一个参数是文件名,第二个参数为是否使用辅助文件,如果为YES,则先写入一个辅助文件,然后辅助文件再重新命名为目标文件,如果为NO,则直接写入到目标文件
// NoteDAO.h
#import <Foundation/Foundation.h>
#import "Note.h"
@interface NoteDAO : NSObject
+ (NoteDAO *)sharedManager;
- (NSString *)applicationDocumentsDirectoryFile;
- (void)createEditableCopyOfDatabaseIfNeeded;
// 插入备忘录的方法
- (int)create:(Note *)model;
// 删除备忘录的方法
- (int)remove:(Note *)model;
// 修改备忘录的方法
- (int)modify:(Note *)model;
// 查询所有数据方法
- (NSMutableArray *)findAll;
// 按照主键查询数据方法
- (Note *)findById:(Note *)model;
@end
// NoteDAO.m
#import "NoteDAO.h"
@implementation NoteDAO
static NoteDAO *sharedManager = nil;
- (void)createEditableCopyOfDatabaseIfNeeded {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *writableDBPath = [self applicationDocumentsDirectoryFile];
BOOL dbexits = [fileManager fileExistsAtPath:writableDBPath];
if (!dbexits) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"NotesList.plist"];
NSError *error;
BOOL success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, @"错误写入文件:'%@'.", [error localizedDescription]);
}
}
}
- (NSString *)applicationDocumentsDirectoryFile {
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [documentDirectory stringByAppendingPathComponent:@"NotesList.plist"];
return path;
}
+ (NoteDAO *)sharedManager {
static dispatch_once_t once;
dispatch_once(&once, ^{
sharedManager = [[self alloc] init];
[sharedManager createEditableCopyOfDatabaseIfNeeded];
});
return sharedManager;
}
- (int)create:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDictionary *dict = [NSDictionary dictionaryWithObjects:@[[dateFormat stringFromDate:model.date], model.content] forKeys:@[@"date", @"content"]];
[array addObject:dict];
[array writeToFile:path atomically:YES];
return 0;
}
- (int)remove:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];
for (NSDictionary *dict in array) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [dateFormatter dateFromString:[dict objectForKey:@"date"]];
// 比较日期主键是否相等
if ([date isEqualToDate:model.date]) {
[array removeObject:dict];
[array writeToFile:path atomically:YES];
break;
}
}
return 0;
}
- (int)modify:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];
for (NSDictionary *dict in array) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [dateFormatter dateFromString:[dict objectForKey:@"date"]];
NSString *content = [dict objectForKey:@"content"];
if ([date isEqualToDate:model.date]) {
[dict setValue:content forKey:@"content"];
[array writeToFile:path atomically:YES];
break;
}
}
return 0;
}
- (NSMutableArray *)findAll {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *listData = [[NSMutableArray alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];
for (NSDictionary *dict in array) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
Note *note = [[Note alloc] init];
note.date = [dateFormatter dateFromString:[dict objectForKey:@"date"]];
note.content = [dict objectForKey:@"content"];
[listData addObject:note];
}
return listData;
}
- (Note *)findById:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];
for (NSDictionary *dict in array) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
Note *note = [[Note alloc] init];
note.date = [dateFormatter dateFromString:[dict objectForKey:@"date"]];
note.content = [dict objectForKey:@"content"];
if ([note.date isEqualToDate:model.date]) {
return note;
}
}
return nil;
}
@end
对象归档:对象归档是一种序列化方式,首先将归档对象序列化为一个文件,然后在通过反归档将数据恢复到对象中.但是不适用于大量数据和频繁读写的情况.
使用要求:该对象的类必须实现NSCoding协议,而且每个成员变量应该是基本数据类型或都是实现NSCoding协议的某个类的实例
// NoteDAO_Archive.h
#import <Foundation/Foundation.h>
#import "Note.h"
// 归档文件名
#define FILE_NAME @"NotesList.archive"
// 归档数据的键
#define ARCHIVE_KEY @"NotesList"
@interface NoteDAO_Archive : NSObject
+ (NoteDAO_Archive *)sharedManager;
- (NSString *)applicationDocumentsDirectoryFile;
- (void)createEditableCopyOfDatabaseIfNeeded;
// 插入备忘录的方法
- (int)create:(Note *)model;
// 删除备忘录的方法
- (int)remove:(Note *)model;
// 修改备忘录的方法
- (int)modify:(Note *)model;
// 查询所有数据方法
- (NSMutableArray *)findAll;
// 按照主键查询数据方法
- (Note *)findById:(Note *)model;
@end
// NoteDAO_Archive.m
#import "NoteDAO_Archive.h"
@implementation NoteDAO_Archive
static NoteDAO_Archive *sharedManager = nil;
- (void)createEditableCopyOfDatabaseIfNeeded {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *writableDBPath = [self applicationDocumentsDirectoryFile];
BOOL dbexits = [fileManager fileExistsAtPath:writableDBPath];
if (!dbexits) {
NSString *path = [self applicationDocumentsDirectoryFile];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *date1 = [dateFormatter dateFromString:@"2010-08-04 16:01:03"];
Note *note1 = [[Note alloc] init];
note1.date = date1;
note1.content = @"Welcome to MyNotes.";
NSDate *date2 = [dateFormatter dateFromString:@"2011-12-04 16:01:03"];
Note *note2 = [[Note alloc] init];
note2.date = date2;
note2.content = @"欢迎使用MyNotes.";
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:note1];
[array addObject:note2];
NSMutableData *theData = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];
// 归档数据是放置在NSArray对象中的,将NSArray对象进行归档,NSArray对象内部没哟个元素都是Note对象,而Note对象也必须是能够被归档的,所以Note类实现了NSCoding协议
[archiver encodeObject:array forKey:ARCHIVE_KEY];
[archiver finishEncoding];
[theData writeToFile:path atomically:YES];
}
}
- (NSString *)applicationDocumentsDirectoryFile {
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [documentDirectory stringByAppendingPathComponent:@"NotesList.plist"];
return path;
}
+ (NoteDAO_Archive *)sharedManager {
static dispatch_once_t once;
dispatch_once(&once, ^{
sharedManager = [[self alloc] init];
[sharedManager createEditableCopyOfDatabaseIfNeeded];
});
return sharedManager;
}
- (int)create:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *array = [self findAll];
[array addObject:model];
/**
* 首先实例化NSMutableData对象theData
* 然后把theData作为参数,再实例化NSKeyedArchiver对象archiver
* archiver对象的encodeObject:方法可以键对实现NSCoding协议的对象进行归档
* [archiver finishEncoding]发出归档完成消息
*/
NSMutableData *theData = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];
[archiver encodeObject:array forKey:ARCHIVE_KEY];
[archiver finishEncoding];
[theData writeToFile:path atomically:YES];
return 0;
}
- (int)remove:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *array = [self findAll];
for (Note *note in array) {
// 比较日期主键是否相等
if ([note.date isEqualToDate:model.date]) {
[array removeObject:note];
NSMutableData *theData = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];
[archiver encodeObject:array forKey:ARCHIVE_KEY];
[archiver finishEncoding];
[theData writeToFile:path atomically:YES];
break;
}
}
return 0;
}
- (int)modify:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *array = [self findAll];
for (Note *note in array) {
// 比较日期主键是否相等
if ([note.date isEqualToDate:model.date]) {
note.content = model.content;
NSMutableData *theData = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];
[archiver encodeObject:array forKey:ARCHIVE_KEY];
[archiver finishEncoding];
[theData writeToFile:path atomically:YES];
break;
}
}
return 0;
}
- (NSMutableArray *)findAll {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *listData = [[NSMutableArray alloc] init];
NSData *theData = [NSData dataWithContentsOfFile:path];
if (theData.length > 0) {
NSKeyedUnarchiver *archiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
listData = [archiver decodeObjectForKey:ARCHIVE_KEY];
[archiver finishDecoding];
}
return listData;
}
- (Note *)findById:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *listData = [[NSMutableArray alloc] init];
NSData *theData = [NSData dataWithContentsOfFile:path];
if (theData.length > 0) {
NSKeyedUnarchiver *archiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
listData = [archiver decodeObjectForKey:ARCHIVE_KEY];
[archiver finishDecoding];
for (Note *note in listData) {
// 比较日期主键是否相等
if ([note.date isEqualToDate:model.date]) {
return note;
}
}
}
return nil;
}
@end
SQLite数据库:关系数据库SQLite采用C语言编写,具有可移植性强,可靠性高,小而容易使用的特点.
运行时与它的应用程序之间共用相同的进程空间,而不是单独的两个进程.支持多表,索引,事务,视图和触发是无数据类型的数据库.
虽然SQLite可以忽略数据类型,但从编程规范上讲,应该在Create Table语句中指定数据类型
INTEGER
有符号的整数类型
REAL
浮点类型
TEXT
字符串类型
BLOB
二进制大对象类型,能够存放任何二进制数据
// NoteDAO_SQLite.h
#import <Foundation/Foundation.h>
#import "Note.h"
#import "sqlite3.h"
#define DBFILE_NAME @"NotesList.sqlite3"
@interface NoteDAO_SQLite : NSObject
{
sqlite3 *db;
}
+ (NoteDAO_SQLite *)sharedManager;
- (NSString *)applicationDocumentsDirectoryFile;
- (void)createEditableCopyOfDatabaseIfNeeded;
// 插入备忘录的方法
- (int)create:(Note *)model;
// 删除备忘录的方法
- (int)remove:(Note *)model;
// 修改备忘录的方法
- (int)modify:(Note *)model;
// 查询所有数据方法
- (NSMutableArray *)findAll;
// 按照主键查询数据方法
- (Note *)findById:(Note *)model;
@end
// NoteDAO_SQLite.m
#import "NoteDAO_SQLite.h"
@implementation NoteDAO_SQLite
static NoteDAO_SQLite *sharedManager = nil;
- (void)createEditableCopyOfDatabaseIfNeeded {
NSString *writableDBPath = [self applicationDocumentsDirectoryFile];
if (sqlite3_open([writableDBPath UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(NO, @"数据库打开失败");
} else {
char *err;
NSString *createSQL = [NSString stringWithFormat:@"create table if not exists Note (cdate text primary key, content text);"];
if (sqlite3_exec(db, [createSQL UTF8String], NULL, NULL, &err) != SQLITE_OK) {
sqlite3_close(db);
NSAssert1(NO, @"建表失败, %s", err);
}
sqlite3_close(db);
}
}
- (NSString *)applicationDocumentsDirectoryFile {
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [documentDirectory stringByAppendingPathComponent:@"NotesList.plist"];
return path;
}
+ (NoteDAO_SQLite *)sharedManager {
static dispatch_once_t once;
dispatch_once(&once, ^{
sharedManager = [[self alloc] init];
[sharedManager createEditableCopyOfDatabaseIfNeeded];
});
return sharedManager;
}
- (int)create:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(NO, @"数据库打开失败");
} else {
NSString *sqlStr = @"insert or replace into note (cdate,content) values (?,?)";
sqlite3_stmt *statement;
// 预处理过程
if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *nsdate = [dateFormatter stringFromDate:model.date];
// 绑定参数开始
sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL);
sqlite3_bind_text(statement, 2, [model.content UTF8String], -1, NULL);
// 执行插入
if (sqlite3_step(statement) != SQLITE_OK) {
NSAssert(NO, @"插入数据失败");
}
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
return 0;
}
- (int)remove:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(NO, @"数据库打开失败");
} else {
NSString *sqlStr = @"delete from note where cdate = ?";
sqlite3_stmt *statement;
// 预处理过程
if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *nsdate = [dateFormatter stringFromDate:model.date];
// 绑定参数开始
sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL);
// 执行插入
if (sqlite3_step(statement) != SQLITE_DONE) {
NSAssert(NO, @"删除数据失败");
}
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
return 0;
}
- (int)modify:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(NO, @"数据库打开失败");
} else {
NSString *sqlStr = @"update note set content=? where cdate = ?";
sqlite3_stmt *statement;
// 预处理过程
if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *nsdate = [dateFormatter stringFromDate:model.date];
// 绑定参数开始
sqlite3_bind_text(statement, 1, [model.content UTF8String], -1, NULL);
sqlite3_bind_text(statement, 2, [nsdate UTF8String], -1, NULL);
// 执行插入
if (sqlite3_step(statement) != SQLITE_DONE) {
NSAssert(NO, @"修改数据失败");
}
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
return 0;
}
- (NSMutableArray *)findAll {
NSString *path = [self applicationDocumentsDirectoryFile];
NSMutableArray *listData = [[NSMutableArray alloc] init];
if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(NO, @"数据库打开失败");
} else {
NSString *qsql = @"select cdate,content from Note";
sqlite3_stmt *statement;
// 预处理过程
if (sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, NULL) == SQLITE_OK) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
while (sqlite3_step(statement) == SQLITE_ROW) {
char *cdate = (char *)sqlite3_column_text(statement, 0);
NSString *nscdate = [[NSString alloc] initWithUTF8String:cdate];
char *content = (char *)sqlite3_column_text(statement, 1);
NSString *nscontent = [[NSString alloc] initWithUTF8String:content];
Note *note = [[Note alloc] init];
note.date = [dateFormatter dateFromString:nscdate];
note.content = nscontent;
[listData addObject:note];
}
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
return listData;
}
- (Note *)findById:(Note *)model {
NSString *path = [self applicationDocumentsDirectoryFile];
if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(NO, @"数据库打开失败");
} else {
NSString *qsql = @"select cdate,content from Note where cdate = ?";
sqlite3_stmt *statement;
// 预处理过程,将SQL编译成二进制代码,提高SQL语句的执行速度
if (sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, NULL) == SQLITE_OK) {
// 准备参数
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *nsdate = [dateFormatter stringFromDate:model.date];
// 绑定参数开始
sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL);
// 执行
if (sqlite3_step(statement) == SQLITE_ROW) {
char *cdate = (char *)sqlite3_column_text(statement, 0);
NSString *nscdate = [[NSString alloc] initWithUTF8String:cdate];
char *content = (char *)sqlite3_column_text(statement, 1);
NSString *nscontent = [[NSString alloc] initWithUTF8String:content];
Note *note = [[Note alloc] init];
note.date = [dateFormatter dateFromString:nscdate];
note.content = nscontent;
sqlite3_finalize(statement);
sqlite3_close(db);
return note;
}
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
return nil;
}
@end
Core Data:苹果为Mac OS X和iOS系统应用开发提供的数据持久化技术.基于高级数据持久化API,底层最终是SQLite数据库,二进制文件和内存数据保存.
Core Data是一种ORM技术(对象关系映射
)
被管理对象上下文类(Managed Object Context, MOC)类,在上下文中可以查找,删除和插入对象,然后通过栈同步到持久化对象存储
被管理对象模型(Manaaged Object Model, MOM)类,是系统中的"实体",与数据库中的表等对象对应
持久化存储协调器(Persistent Store Coordinator, PSC)类,在持久化对象存储之上提供了一个接口,可以把它考虑成为数据库的连接
MOC,MOM,PSC和持久化对象存储,它们一起构成了Core Data堆栈
持久化对象存储(Persistent Object Store, POS)执行所有底层的从对象到数据的转换,并负责打开和关闭数据文件.它有3种持久化实现方式:SQLite,二进制文件和内存形式
10.BAD_ACCESS在什么情况下出现?
在访问一个已经释放的对象或向它发送消息时,EXC_BAD_ACCESS就会出现.造成EXC_BAD_ACCESS最常见的原因是,在初始化方法中初始化变量时用错了所有权修饰符,这会导致对象被释放.
例:在viewDidLoad方法中为UITableViewController创建了一个包含元素的NSMutableArray,却将该数组的所有权修饰符设成了unsafe_unretained或assign而不是strong.现在在cellForRowAtIndexPath:中,若要访问已经释放掉的对象时,就会得到名为EXC_BAD_ACCESS的崩溃.
通过设置NSZombieEnabled环境变量,来调试EXC_BAD_ACCESS