iOS本地存储的方式

    技术2022-07-11  90

    iOS本地存储的方式

    1.NSUserDefaunts (Preference偏好设置) 2.plist存储 3.归档 4.SQLite3 5.CoreData**

    应用沙盒 Document :适合存储重要的数据,iTunes同步应用时会同步该文件下的内容。(比如游戏中的存档)。 Library/Caches:适合存储体积大,不需要备份的非重要数据,iTunes不会同步该文件。 tmp:保存应用的临时文件,用完就删除,系统可能在应用没在运行时删除该目录下的文件,iTunes不会同步。

    获取沙盒路径 Document:

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES); NSString *documentFilePath = paths.fistObject;

    1.NSuserDefault NSuserDefault 适合存储轻量级的本地数据,支持的数据类型:NSNumber,NSString,NSDate,NSArray,NSDictionary,BOOL,NSData 沙盒路径为Library/Preferences 文件格式为.plist

    优点: 1.不需要关心文件名; 2.快速进行键值对存储; 3.直接存储基本数据类型;

    缺点: 1.不能存储自定义数据 2.取出的数据是不可变的

    -void)userDefaultSave{ NSArray *testArray = @[@"test1",@"test1",@"test3"]; [ [NSUserDefaults standardUserDefaults] setObject:testArray forKey:@"arraykey"]; [[NSUserDefaults standarUserDefaults] synchronize]; } - (void)userDefaultLoad{ NSArray *testArray = [[NSUserDefaults standardUserDefaults] objectForKey:@"arrayKey"]; NSLog(@"%@",testArray); }

    封装调用

    #pragma mark 保存本地数据 void saveUserInfo(NSString *keyName,id valueName) { NSUserDefaults *def = [NSUserDefaults standardUserDefaults]; [def setObject:valueName forKey:keyName]; [def synchronize]; } #pragma mark 获取本地数据 NSString * getUserInfo(NSString *keyName) { NSUserDefaults *def = [NSUserDefaults standardUserDefaults]; return [def objectForKey:keyName]; } #pragma mark 删除本地数据 void removeUserInfo(NSString *key) { NSUserDefaults *def = [NSUserDefaults standardUserDefaults]; [def removeObjectForKey:key]; [def synchronize]; }

    2.plist存储

    plist支持的数据类型:NSArray,NSMutableArray,NSDictionary,NSMutableDictionary,NSData,NSMutableData,NSString,NSMutableString,NsNumber,NSDate; 不支持BOOL,而且最外层好像要用NSArray或NSDictionary;

    - (void)plistSave{ NSSring *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirecttory,NSUserDomainMask,YES).firstObject; NSString *filePath = [cachPath stringByAppendingPathComponent:"testPlist.plist"]; NSMutableDitionary *dict = [NSMutableDictionary dictionary]; dict setObject:@"jack" forKey:@"name"; dict setObject:@"18" forKey:@"age"; [dict writeToFile:filepath atomically:YES]; } - (void)plistLoad{ NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; NSString *filePath = [cachePath stringByAppendingPathComponent:@"testPlist.plist"]; NSDictionary *t = [NSDictionary dictionaryWithContentsOfFile:filePath]; NSLog(@"%@",t); }

    3.归档 存储自定义对象

    1.首先新建Person类,并遵守NSCoding协议 #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface Person : NSObject<NSCoding> @property (nonatomic,strong) NSString *name; @property (nonatomic,strong) NSString *age; @end NS_ASSUME_NONNULL_END 2.实现协议方法 #import "Person.h" @implementation Person - (instancetype)initWithCoder:(NSCoder *)coder { self = [super init]; if (self) { _name = [coder decodeObjectForKey:@"name"]; _age = [coder decodeObjectForKey:@"age"]; } return self; } - (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.name forKey:@"name"]; [coder encodeObject:self.age forKey:@"age"]; } @end 3.归档解档 #pragma mark - 一个对象归档 - (void)archive{ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentFilePath = paths.firstObject; NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"]; Person *p1 = [[Person alloc]init]; p1.name = @"jack"; p1.age = @"18"; [NSKeyedArchiver archiveRootObject:p1 toFile:filePath]; } #pragma mark - 一个对象解档 - (void)unarchive{ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentFilePath = paths.firstObject; NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"]; Person *p1 = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; NSLog(@"%@",p1.name); NSLog(@"%@",p1.age); } #pragma mark - 多个对象归档 - (void)archiveManyObject { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentFilePath = paths.firstObject; NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"]; NSMutableData *data = [[NSMutableData alloc]init]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data]; Person *p1 = [[Person alloc]init]; p1.name = @"jack"; p1.age = @"18"; [archiver encodeObject:p1 forKey:@"person1"]; Person *p2 = [[Person alloc]init]; p2.name = @"stuart"; p2.age = @"28"; [archiver encodeObject:p2 forKey:@"person2"]; [archiver finishEncoding]; [data writeToFile:filePath atomically:YES]; } #pragma mark - 多个对象解档 - (void)unarchiveManyObject { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentFilePath = paths.firstObject; NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"]; NSData *data = [NSData dataWithContentsOfFile:filePath]; NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data]; Person *p1 = [unarchiver decodeObjectForKey:@"person1"]; Person *p2 = [unarchiver decodeObjectForKey:@"person2"]; [unarchiver finishDecoding]; NSLog(@"%@",p1.name); NSLog(@"%@",p2.name); }

    4.SQLite3

    数据库(splite) splite是一个轻量级,跨平台的小型数据库,可移植性比较高,有着和MySpl几乎相同的数据库语句,以及无需服务器即可使用的优点:

    数据库的优点: 1.该方案可以存储大量的数据,存储和检索的速度非常快。 2.能对数据进行大量的聚合,这样比起使用对象来讲操作要快。 数据库的缺点: 1.它没有提供数据库的创建方式。 2.它的底层是基于c语言框架设计的,没有面向对象的API,用起来非常麻烦 3.发杂的数据模型的数据建表,非常麻烦; 在实际开发中我们都是使用的是FMDB第三方开源的数据库,该数据库是基于splite封装的面向对象的框架。

    SQL语句: 注释:SQL语句对大小写不敏感。

    create database --- 创建新数据库 alter database --- 修改数据库 create table --- 创建新表 alter table --- 变更(改变)数据库表 drop table --- 删除表 create index --- 创建索引(搜索键) drop index --- 删除索引 select 语句 select 语句用于从表中选取数据。 select 列名称 from 表名称 以及:select * from 表名称 星号(*)是选取所有列的快捷方式 例: SELECT LastName,FirstName FROM Persons 获取Persons表的LastName列,FirstName列数据 select distinct 语句 distinct 用于返回唯一不同的值,不会出现重复数据 select distinct 列名称 from 表名称 例: select distinct Company from Orders select 列名称 from 表名称 where 列 运算符 值 例: select * from Person where City = ‘beijing’ AND 和OR运算符 AND 和 OR 可在 WHERE 子语句中把两个或多个条件结合起来。 如果第一个条件和第二个条件都成立,则 AND 运算符显示一条记录。 如果第一个条件和第二个条件中只要有一个成立,则 OR 运算符显示一条记录。 AND 运算符实例 使用 AND 来显示所有姓为 "Carter" 并且名为 "Thomas" 的人: SELECT * FROM Persons WHERE FirstName='Thomas' AND LastName='Carter' OR 运算符实例 使用 OR 来显示所有姓为 "Carter" 或者名为 "Thomas" 的人: SELECT * FROM Persons WHERE firstname='Thomas' OR lastname='Carter' 结合起来使用 SELECT * FROM Persons WHERE (FirstName='Thomas' OR FirstName='William') AND LastName='Carter' order by 语句 ORDER BY 语句用于根据指定的列对结果集进行排序。 ORDER BY 语句默认按照升序对记录进行排序。 如果您希望按照降序对记录进行排序,可以使用 DESC 关键字。 例: 以字母顺序显示公司名称: select Company,OrderNumber FROM Order order by company insert into 语句 insert into 语句用于向表格插入新的行 insert into 表名称 values(值1,值2,....) 指定所要插入数据的列: insert into table_name(1,列2) values (值1,值2.....) 例1: insert into persons values (‘Gstes’,‘Bill’,‘Xuanwumen 10’,‘Beijing’) 例2: INSERT INTO Persons (LastName, Address) VALUES ('Wilson', 'Champs-Elysees') update 语句 update 语句用于修改表中数据。 update 表名称 set 列名称 = 新值 where 列名称 = 某值 例:更新某一行中的一列 我们为 lastname 是 "Wilson" 的人添加 firstname: update Person set firstName = ‘Fred’ where lastName = ‘Wilson’; 例: 更新某一行中的若干列 update Person set Address = 'zhongshan23',City = "NanJing" where lastName = 'Wilson'; delete 语句 delete 语句用于删除表中的行。 delete from 表名称 where 列名称 = 值 例: 删除某行 delete from Person where lastName = ‘Wilson’; 例: 删除所有行 delete form table_name 或 delete * from table_name

    代码:

    #import "JHSQlite.h" @interface JHSQlite () { sqlite3 *_db; } @end @implementation JHSQlite - (instancetype)init { self = [super init]; if (self) { [self open]; [self insert]; [self update]; } return self; } #pragma mark - 打开数据库 - (void)open { // 创建文件名 NSString *fileName = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"student.sqlite"]; NSLog(@"fileName = %@",fileName); // 创建(打开)数据库,如果数据库不存在,会自动创建,数据库文件的路径必须以C字符串(而非)NSString传入 int result = sqlite3_open(fileName.UTF8String, &_db); if(result == SQLITE_OK){ NSLog(@"成功打开数据库"); char *errorMsg = NULL; const char *sql = "create table if not exists t_person (id integer primary key autoincrement,name text,age integer);"; // sqlite3_exec()可以执行任何SQL语句,比如创表、更新、插入和删除操作。但是一般不用它执行查询语句,因为它不会返回查询到的数据 int result = sqlite3_exec(_db, sql, NULL, NULL, &errorMsg); if(result == SQLITE_OK){ NSLog(@"成功创建t_person表"); }else { NSLog(@"成功创建t_person表失败:%s:",errorMsg); } }else { NSLog(@"打开数据库失败"); } } #pragma mark - 插入数据 - (void)insert { for (int i = 0; i < 30; i++) { NSString *name = [NSString stringWithFormat:@"person-%d",arc4random()%100]; int age = arc4random() %100; char *errorMsg = NULL; NSString *sql = [NSString stringWithFormat:@"insert into t_person (name,age) values ('%@',%d);",name,age]; int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMsg); if (result == SQLITE_OK) { NSLog(@"添加数据成功"); }else { NSLog(@"添加数据失败"); } } } #pragma mark - 删除数据 - (void)delete { char *errorMsg = NULL; NSString *sql = @"delete from t_person where age >= 0"; int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMsg); if (result == SQLITE_OK) { NSLog(@"删除成功"); }else{ NSLog(@"删除失败"); } } #pragma mark - 查询数据 - (void)query { const char *sql = "select id, name, age from t_person;"; //"select id, name, age from t_person where age >= 50;" sqlite3_stmt *stmt = NULL; //定义一个stmt存放结果集 // 检测SQL语句的合法性 int result = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL); if(result == SQLITE_OK) { NSLog(@"查询语句合法"); while (sqlite3_step(stmt) == SQLITE_ROW) { int ID = sqlite3_column_int(stmt, 0); const unsigned char *sname = sqlite3_column_text(stmt, 1); NSString *name = [NSString stringWithUTF8String:(const char*)sname]; int age = sqlite3_column_int(stmt, 2); NSLog(@"%d %@ %d",ID,name,age); } }else { NSLog(@"查询语句非法"); } } #pragma mark - 更新数据 - (void)update { NSString *sql = @"update t_person set name = '及格' where age > 60"; char *errorMsg = NULL; int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMsg); if (result == SQLITE_OK) { NSLog(@"更改成功"); }else { NSLog(@"更改失败"); } } @end #import <Foundation/Foundation.h> // 导入数据库 #import <sqlite3.h> NS_ASSUME_NONNULL_BEGIN @interface DBManager : NSObject + (DBManager *)getShareInstance; - (BOOL)createDB; - (BOOL)saveData:(NSString *)registerNumber name:(NSString *)name department:(NSString *)department year:(NSString *)year; - (NSArray *)findByRegisterNumber:(NSString *)registerNumber; @end NS_ASSUME_NONNULL_END

    使用单例封装数据库

    #import "DBManager.h" // 声明单例 static DBManager *sharedInstance = nil; // 声明数据库 static sqlite3 *database = nil; // 声明缓存区 static sqlite3_stmt *statement = nil; @interface DBManager () { NSString *databasePath; } @end @implementation DBManager // 单例 + (DBManager *)getShareInstance { if (!sharedInstance) { sharedInstance = [[super allocWithZone:NULL]init]; [sharedInstance createDB]; } return sharedInstance; } // 创建数据库 - (BOOL)createDB{ NSString *docsDir; NSArray *dirPaths; // 获取沙盒路径,Document目录 dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); docsDir = dirPaths[0]; // 创建数据库文件 databasePath = [[NSString alloc]initWithString:[docsDir stringByAppendingPathComponent:@"student.db"]]; BOOL isSuccess = YES; // 初始化文件管理器 NSFileManager *filemgr = [NSFileManager defaultManager]; // 判断文件是否存在,如果不存在则执行 if ([filemgr fileExistsAtPath:databasePath] == NO) { // NSString转成UTF8String类型,oc字符串转c字符串 声明一个指向字符或字符串常量的指针(p所指向的内容不可修改) const char *dbpath = [databasePath UTF8String]; // 打开数据库,SQLITE_OK打开成功 if (sqlite3_open(dbpath, &database) == SQLITE_OK) { char *errMsg; // 创建数据库表名studentsDetail(表里面数据标题类型) const char *sql_stmt = "create table if not exists studentsDetail (regno integer primary key, name text, department text, year text)"; // 插入数据库表格 if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK) { isSuccess = NO; NSLog(@"Failed to create table"); } //关闭数据库 sqlite3_close(database); return isSuccess; }else { isSuccess = NO; NSLog(@"Failed to open/create database"); } } return isSuccess; } -(BOOL)checkName:(NSString *)name{ char *err; NSString *sql = [NSString stringWithFormat:@"select student form sqlite_master where type='table' and name='%@';",name]; const char *sql_stmt = [sql UTF8String]; if(sqlite3_exec(database, sql_stmt, NULL, NULL, &err) == 1){ return YES; }else{ return NO; } } // 保存数据 - (BOOL)saveData:(NSString *)registerNumber name:(NSString *)name department:(NSString *)department year:(NSString *)year{ // 获取路径 const char *dbpath = [databasePath UTF8String]; // 打开数据库 if(sqlite3_open(dbpath, &database) == SQLITE_OK){ // 插入数据到studentsDetail表 NSString *insertSQL = [NSString stringWithFormat:@"insert into studentsDetail (regno,name, department, year) values(\"%ld\",\"%@\", \"%@\", \"%@\")",[registerNumber integerValue],name,department,year]; // 插入 const char *insert_stmt = [insertSQL UTF8String]; // 执行查询语句 sqlite3_prepare_v2(database, insert_stmt, -1, &statement, NULL); // 执行完毕,返回SQLITE_DONE,反之 if (sqlite3_step(statement) == SQLITE_DONE) { return YES; } // 重置 sqlite3_reset(statement); } return NO; } // 取出数据 - (NSArray *)findByRegisterNumber:(NSString *)registerNumber{ // 获取数据库路径 const char *dbpath = [databasePath UTF8String]; // 打开数据库 if (sqlite3_open(dbpath, &database) == SQLITE_OK) { // 查询数据库studentsDetail表 NSString *querySQL = [NSString stringWithFormat:@"select name, department, year from studentsDetail where regno=\"%@\"",registerNumber]; // oc转成c const char *query_stmt = [querySQL UTF8String]; // 创建数组保存数据 NSMutableArray *resultArray = [[NSMutableArray alloc]init]; // 执行查询语句 if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK) { // 查询结束 if (sqlite3_step(statement) == SQLITE_ROW) { // 取出数据 NSString *name = [[NSString alloc]initWithUTF8String:(const char*)sqlite3_column_text(statement, 0)]; [resultArray addObject:name]; NSString *department = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)]; [resultArray addObject:department]; NSString *year = [[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 2)]; [resultArray addObject:year]; return resultArray; } sqlite3_reset(statement); } } return nil; } @end

    5.coreData coreData是苹果官方在iOS5之后推出的综合性数据库,其使用了对象关系映射技术,将对象转换成数据,将数据存储在本地的数据库中; coreData 为了提高效率,需要将数据存储在不同的数据库中,比如:在使用的时候,最好是将本地的数据保存到内存中,这样的目的是访问速度比较快。

    coreData 与 SQLite进行对比 SQLite 1、基于C接口,需要使用SQL语句,代码繁琐 2、在处理大量数据时,表关系更直观 3、在OC中不是可视化,不易理解

    CoreData 1、可视化,且具有undo/redo能力 2、可以实现多种文件格式:

    NSSQLiteStoreTypeNSBinaryStoreTypeNSInMemoryStoreTypeNSXMLStoreTyp 3、苹果官方API支持,与iOS结合更紧密

    CoreData核心类与结构 NSManageObjectContext(数据上下文) 对象管理上下文,负责数据的实际操作(重要) 作用:插入数据,查询数据,删除数据,更新数据

    NSPersistentStoreCoordinator(持久化存储助理) 相当于数据库的连接器 作用:设置数据存储的名字,位置,存储方式,和存储时机

    NSMangedObject(数据模型) 数据库所有表格或数据结构,包含各实体的定义信息 作用:添加实体的属性,建立属性之间的关系 操作方法:视图编辑器,或代码

    NSManagedObject(被管理的数据记录) 数据库中的表格记录

    NSEntityDescription(实体结构) 相当于表格结构

    NSFetchRequest(数据请求) 相当于查询语句 后缀为.xcdatamodeld的包 里面是.xcdatamodel文件,用数据模型编辑器编辑 编译后为.momd或.mom文件

    步骤: 1.创建模型文件 2.创建实体

    3.创建实体类 结果文件

    代码:

    #import "ViewController.h" #import <CoreData/CoreData.h> #import "Student+CoreDataProperties.h" //#import "August-Bridging-Header.h" @interface ViewController () @property (nonatomic,strong) NSManagedObjectContext *context; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self createSql]; [self inster]; [self query]; [self update]; } #pragma mark - 创建 - (void)createSql { // 获取模型路径 NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"PersonModel" withExtension:@"momd"]; // 根据模型文件创建模型对象 NSManagedObjectModel *model = [[NSManagedObjectModel alloc]initWithContentsOfURL:modelURL]; // 利用模型对象创建持久化存储助理 NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:model]; // 数据库的名称和路径 NSString *docStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *sqlPath = [docStr stringByAppendingPathComponent:@"coreData.sqlite"]; NSURL *sqlUrl = [NSURL fileURLWithPath:sqlPath]; // 设置数据库相关信息,添加一个持久化存储并设置类型和路径,NSSQLiteStoreType:SQLite作为存储库 NSError *error = nil; [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sqlUrl options:nil error:&error]; if (error) { NSLog(@"添加数据库失败:%@",error); }else { NSLog(@"添加数据库成功"); } // 3.创建上下文 保存信息 对数据进行操作 关联持久化助理 NSManagedObjectContext *context = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSMainQueueConcurrencyType]; context.persistentStoreCoordinator = store; _context = context; } #pragma mark - 插入 - (void)inster { Student *student = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:_context]; student.name = [NSString stringWithFormat:@"stu-%d",arc4random()%100]; student.age = arc4random()%30; NSError *error = nil; if ([_context save:&error]) { NSLog(@"数据插入到数据库成功"); }else{ NSLog(@"数据插入到数据库失败"); } } #pragma mark - 删除 - (void)delete { //创建删除请求 NSFetchRequest *deleRequest = [NSFetchRequest fetchRequestWithEntityName:@"Student"]; //删除条件 没有任何条件就是读取所有的数据 //NSPredicate *pre = [NSPredicate predicateWithFormat:@"age < %d", 10]; //deleRequest.predicate = pre; //返回需要删除的对象数组 NSArray *deleArray = [_context executeFetchRequest:deleRequest error:nil]; //从数据库中删除 for (Student *stu in deleArray) { [_context deleteObject:stu]; } NSError *error = nil; if ([_context save:&error]) { NSLog(@"删除数据成功"); }else{ NSLog(@"删除数据失败, %@", error); } } #pragma mark - 查询 - (void)query { //创建查询请求 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"]; //查询条件 没有任何条件就是读取所有的数据 NSPredicate *pre = [NSPredicate predicateWithFormat:@"age >= 0"]; request.predicate = pre; // 从第几页开始显示 通过这个属性实现分页 //request.fetchOffset = 0; // 每页显示多少条数据 //request.fetchLimit = 6; //发送查询请求 NSArray *resArray = [_context executeFetchRequest:request error:nil]; //打印查询结果 for (Student *stu in resArray) { NSLog(@"name=%@, age=%d",stu.name, stu.age); } } #pragma mark - 更新 - (void)update { //创建查询请求 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"]; NSPredicate *pre = [NSPredicate predicateWithFormat:@"age >= 0"]; request.predicate = pre; //发送请求 NSArray *resArray = [_context executeFetchRequest:request error:nil]; //修改 for (Student *stu in resArray) { stu.name = @"ran"; } NSError *error = nil; if ([_context save:&error]) { NSLog(@"更新数据成功"); }else{ NSLog(@"更新数据失败, %@", error); } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
    Processed: 0.013, SQL: 9