12&13day-私人通讯录&qq主流的界面框架示例

来源:互联网 发布:中文域名icp备案 编辑:程序博客网 时间:2024/06/03 19:43

前言

掌握(iOS应用数据存储的常用方式):
1、XML属性列表归档(plist)
2、preference偏好设置
3、NSKeyedArchiver归档(NSCoding)
4、SQLite3 https://github.com/ccgus/fmdb
5、Core Data http://m.blog.csdn.net/article/details?id=8563438
6、UITabBarController
7、modal原理和常规使用

一、应用沙盒(文件夹)

这里写图片描述
每个iOS应用都有自己的应用沙盒,来与其他文件系统隔离。
1、应用沙盒的文件系统目录结构分析
1>应用程序包:(上图中的Layer)包含了所有的资源文件和可执行文件
2>Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录
3>tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
4>Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据
5>Library/Preference:保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录
2、应用沙盒目录的获取方式
0>tmp:
FOUNDATION_EXPORT NSString *NSTemporaryDirectory(void);
1> 沙盒根目录:
FOUNDATION_EXPORT NSString *NSHomeDirectory(void);

NSLog(@"%@",NSHomeDirectory());//: /Users/devzkn/Library/Developer/CoreSimulator/Devices/5A6E02FF-A156-455B-AE43-C207F4E7FBC4/data/Containers/Data/Application/E3F77B8B-C88C-4577-A943-187151AB19CC

2>Documents:(2种方式)

NSString *home = NSHomeDirectory();NSString *documents = [home stringByAppendingPathComponent:@"Documents"];// 不建议采用,因为新版本的操作系统可能会修改目录名

方式二:FOUNDATION_EXPORT NSArray

// NSUserDomainMask 代表从用户文件夹下找// YES 代表展开路径中的波浪字符“~”NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, NO);~/Documents/data.plist,yes的话,就展开全路径// 在iOS中,只有一个目录跟传入的参数匹配,所以这个集合里面只有一个元素NSString *documents = [array objectAtIndex:0];

3> Library/Caches (类似Documents)
4 >lLibrary/Preference:通过NSUserDefaults类存取该目录下的设置信息

二、属性列表(属性列表是一种XML格式的文件,拓展名为plist)

如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中

只有具备writeToFile:方法的对象才可以向plist文件存储数据

- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;+ (nullable NSDictionary<KeyType, ObjectType> *)dictionaryWithContentsOfFile:(NSString *)path;

这里写图片描述

三、偏好设置
针对应用的字体大小、是否保存用户名等偏好设置,IOS的每个应用都有个NSUserDefaults实例,通过它来存取偏好设置。
NSUserDefaults设置数据的时候,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题,可以通过调用synchornize方法强制写入- (BOOL)synchronize;
1、偏好设置的好处:
1》不用关心文件名
2》快速的进行键值对存储
四、NSKeyedArchiver
只有遵守了NSCoding协议的对象才可以使用NSKeyedArchiver进行归档。

protocol NSCoding- (void)encodeWithCoder:(NSCoder *)aCoder;//每次归档对象的时候都会调用这个方法,来指定归档对象的每个实例变量- (void)encodeObject:(nullable id)objv forKey:(NSString *)key;/**每次从文件中恢复对象时,都会调用这个方法来指定如何解码文件中的数据为对象的实例变量--- (nullable id)decodeObjectForKey:(NSString *)key;*/- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder; // NS_DESIGNATED_INITIALIZER@end//例子:@interface HSPersonModel () <NSCoding>@end@implementation HSPersonModel/** 对象规定的时候调用*/#if 1- (void)encodeWithCoder:(NSCoder *)aCoder{    NSLog(@"%s",__func__);    [aCoder encodeInt:self.age forKey:@"age"];    [aCoder encodeObject:self.name forKey:@"name"];}#endif/**  对象解挡的时候调用 */- (instancetype)initWithCoder:(NSCoder *)aDecoder{    NSLog(@"%s",__func__);    self = [super init];//继承父类的属性    if (self) {        //定义如何解挡        self.age = [aDecoder decodeIntForKey:@"age"];        self.name = [aDecoder decodeObjectForKey:@"name"];    }    return self;}

p s:NS_DESIGNATED_INITIALIZER 宏的使用 如果存在继承关系,记得调用父类的NSCoding协议方法。
—UIView 就是个典型的例子,UIView的子类必须实现initWithCoder:decoder,否则无法继承父类属性。
initWithCoder:decoder的优先级比- (void)awakeFromNib 还高。

*如果父类也遵守了NSCoding协议,请注意:---UIView 就是个典型的例子,UIView的子类必学实现initWithCoder:decoder,否则无法继承父类属性。应该在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];确保继承的实例变量也能被编码,即也能被归档同样地,应该在initWithCoder:方法中加上一句 self = [super initWithCoder:decoder];--确保继承的实例变量也能被解码,即也能被恢复*/

http://useyourloaf.com/blog/xcode-6-objective-c-modernization/
http://stackoverflow.com/questions/26185239/ios-designated-initializers-using-ns-designated-initializer
实例化对象的规范

/**1.The designated initializer guarantees the object is fully initialised by sending an initialization message to the superclass. The implementation detail becomes important to a user of the class when they subclass it. The rules for designated initializers in detail:2.A designated initializer must call (via super) a designated initializer of the superclass. Where NSObject is the superclass this is just [super init].3.Any convenience initializer must call another initializer in the class - which eventually leads to a designated initializer.4.A class with designated initializers must implement all of the designated initializers of the superclass.

1、归档NSArray

这里写图片描述

+ (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path;//归档+ (nullable id)unarchiveObjectWithFile:(NSString *)path;//恢复解码- (IBAction)savePerson:(id)sender {    //存储自定义对象    HSPersonModel *model = [HSPersonModel new];    model.age= 122;    [model setName:@"Lydia"];    NSString *cachPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];    NSString *filePath = [cachPath stringByAppendingPathComponent:@"person.arc"];    BOOL isSuccess=  [NSKeyedArchiver archiveRootObject:model toFile:filePath];    if (isSuccess) {        NSLog(@"%@",filePath);    }}- (IBAction)readPerson:(id)sender {    NSString *cachPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];    NSString *filePath = [cachPath stringByAppendingPathComponent:@"person.arc"];    NSLog(@"%@",filePath);    HSPersonModel *model = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];    NSLog(@"%d,%@",model.age,model.name);}

五、NSData

可以将多个对象写入到同一个文件中,那么就要使用NSData来进行归档对象。
NSData可以为一些数据提供临时存储空间,以便随后写入文件,或者存放从磁盘读取的文件内容。可以使用[NSMutableData data]创建可变数据空间。

FMDB例子:使用NSData 来存储多个对象到数据库中

+(void)savestatusesWithStatuses:(NSArray *)statuses{    if (statuses.count <= 0) {        return;    }//    [_db open];    // 插入数据    for (NSDictionary *obj in statuses) {        //先查询        BOOL isExistsStatus = [self isExistsStatus:obj[@"idstr"]];        NSError *error;#warning 只有将自定义对象实现nscoding 协议,才可以使用archivedDataWithRootObject 进行nsdata 的转换        NSData *data = [NSKeyedArchiver  archivedDataWithRootObject:obj];//以2进制        if (isExistsStatus) {            //更新             [_db executeUpdateWithFormat:@"update   t_status set status= %@ where idStr=%@ and access_token =%@;",data,obj[@"idstr"],[HWAccountTool account].access_token];//不能自己使用//        [NSString stringWithFormat:(nonnull NSString *), ...] 拼写sql        }else{            //插入            [_db executeUpdateWithFormat:@"INSERT  into   t_status (status , idStr,access_token) VALUES (%@,%@,%@);",data,obj[@"idstr"],[HWAccountTool account].access_token];//不能自己使用//        [NSString stringWithFormat:(nonnull NSString *), ...] 拼写sql        }        if (error) {            NSLog(@"%@",error);        }    }    [_db commit];//    [_db close];}

例子2: NSData-归档2个Person对象到同一文件中

//1.(编码)// 新建一块可变数据区NSMutableData *data = [NSMutableData data];// 将数据区连接到一个NSKeyedArchiver对象NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];// 开始存档对象,存档的数据都会存储到NSMutableData中[archiver encodeObject:person1 forKey:@"person1"];[archiver encodeObject:person2 forKey:@"person2"];// 存档完毕(一定要调用这个方法)[archiver finishEncoding];// 将存档的数据写入文件[data writeToFile:path atomically:YES];//2.恢复(解码)// 从文件中读取数据NSData *data = [NSData dataWithContentsOfFile:path];// 根据数据,解析成一个NSKeyedUnarchiver对象NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];Person *person1 = [unarchiver decodeObjectForKey:@"person1"];Person *person2 = [unarchiver decodeObjectForKey:@"person2"];// 恢复完毕[unarchiver finishDecoding];

这里写图片描述

例子3:利用NSData实现深copy

// 临时存储person1的数据NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person1];// 解析data,生成一个新的Person对象Student *person2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];// 分别打印内存地址NSLog(@"person1:0x%x",person1);// person1:0x7177a60NSLog(@"person2:0x%x",person2);// person2:0x7177cf0

六、SQLite3(开源的嵌入式关系型数据库)

可移植性好、易使用、开销小--无类型的(可以保存任意类型的数据到任意表的任意字段)
1、SQLite3常用的5种数据类型:text、integer、float、boolean、blob
2、在iOS中使用SQLite3,首先要添加库文件libsqlite3.dylib和导入主头文件sqlite3
3、创建、打开、关闭数据库

SQLITE_API int SQLITE_STDCALL sqlite3_open(  const char *filename,   /* Database filename (UTF-8) */  sqlite3 **ppDb          /* OUT: SQLite db handle */);SQLITE_API int SQLITE_STDCALL sqlite3_open16(  const void *filename,   /* Database filename (UTF-16) */  sqlite3 **ppDb          /* OUT: SQLite db handle */);SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(  const char *filename,   /* Database filename (UTF-8) */  sqlite3 **ppDb,         /* OUT: SQLite db handle */  int flags,              /* Flags */  const char *zVfs        /* Name of VFS module to use */);//创建或打开数据库// path为:~/Documents/person.dbsqlite3 *db;int result = sqlite3_open([path UTF8String], &db);/**代码解析:usqlite3_open()将根据文件路径打开数据库,如果不存在,则会创建一个新的数据库。如果result等于常量SQLITE_OK,则表示成功打开数据库usqlite3 *db:一个打开的数据库实例数据库文件的路径必须以字符串(而非NSString)传入*///关闭数据库:sqlite3_close(db);

4、执行不返回数据的sql语句

SQLITE_API int SQLITE_STDCALL sqlite3_exec(  sqlite3*,                                  /* An open database */  const char *sql,                           /* SQL to be evaluated */  int (*callback)(void*,int,char**,char**),  /* Callback function */  void *,                                    /* 1st argument to callback */  char **errmsg                              /* Error msg written here */);char *errorMsg;  // 用来存储错误信息char *sql = "create table if not exists t_person(id integer primary key autoincrement, name text, age integer);";int result = sqlite3_exec(db, sql, NULL, NULL, &errorMsg);/**可以执行任何SQL语句,比如创表、更新、插入和删除操作。但是一般不用它执行查询语句,因为它不会返回查询到的数据usqlite3_exec()还可以执行的语句:①开启事务:begin transaction;②回滚事务:rollback;③提交事务:commit;*/

5、带占位符进行数据插入

SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(  sqlite3 *db,            /* Database handle */  const char *zSql,       /* SQL statement, UTF-8 encoded */  int nByte,              /* Maximum length of zSql in bytes. */  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */  const char **pzTail     /* OUT: Pointer to unused portion of zSql */);char *sql = "insert into t_person(name, age) values(?, ?);";sqlite3_stmt *stmt;if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {   //usqlite3_prepare_v2()返回值等于SQLITE_OK,说明SQL语句已经准备成功,没有语法问题    sqlite3_bind_text(stmt, 1, "母鸡", -1, NULL);      sqlite3_bind_int(stmt, 2, 27);}if (sqlite3_step(stmt) != SQLITE_DONE) {   //执行SQL语句返回SQLITE_DONE代表成功执行完毕    NSLog(@"插入数据错误");}sqlite3_finalize(stmt);//销毁sqlite3_stmt *对象/**  usqlite3_bind_text():大部分绑定函数都只有3个参数①第1个参数是sqlite3_stmt *类型②第2个参数指占位符的位置,第一个占位符的索引从开始1,不是0③第3个参数指占位符要绑定的值④第4个参数指在第3个参数中所传递数据的长度,对于C字符串,可以传递-1代替字符串的长度⑤第5个参数是一个可选的函数回调,一般用于在语句执行后完成内存清理工作*/

6、查询数据
查询数据

char *sql = "select id,name,age from t_person;";sqlite3_stmt *stmt;if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {      while (sqlite3_step(stmt) == SQLITE_ROW) {//代表遍历到一条新记录        int _id = sqlite3_column_int(stmt, 0);        char *_name = (char *)sqlite3_column_text(stmt, 1);        NSString *name = [NSString stringWithUTF8String:_name];        int _age = sqlite3_column_int(stmt, 2);        NSLog(@"id=%i, name=%@,age=%i", _id, name, _age);      }}sqlite3_finalize(stmt);//销毁stmt对象/**代码解析usqlite3_step()返回SQLITE_ROW代表遍历到一条新记录usqlite3_column_*()用于获取每个字段对应的值,第2个参数是字段的索引,从0开始*/

七、coreDate (对象-关系映射ORM)

能够将OC对象转化成数据,保存在SQLite3数据库文件中,也能够将保存在数据库中的数据还原成OC对象。在此数据操作期间,不需要编写任何SQL语句(只须操作对象)。使用此功能,要添加CoreData.framework和导入主头文件

<CoreData/CoreData.h>

这里写图片描述

1、模型文件
在Core Data,需要进行映射的对象称为实体(entity),而且需要使用Core Data的模型文件来描述应用的所有实体和实体属性.
1>这里以Person和Card(身份证)2个实体为例子,先看看实体属性和之间的关联关系
这里写图片描述

*添加Person实体的基本属性

这里写图片描述

*在Person中添加card属性

这里写图片描述

*在Card中添加person属性

这里写图片描述
2、NSManagedObject
通过Core Data从数据库取出的对象,默认情况下都是NSManagedObject对象;
NSManagedObject的工作模式有点类似于NSDictionary对象,通过键-值对来存取所有的实体属性:setValue:forKey: 存储属性值(属性名为key);valueForKey: 获取属性值(属性名为key)

这里写图片描述

3、coredata 主要对象

这里写图片描述
4、搭建coredate上下文

/1.从应用程序包中加载模型文件NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];//2.传入模型,初始化NSPersistentStoreCoordinatorNSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];//构建SQLite文件路径NSString *docs =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES) lastObject];NSURL *url = [NSURL fileURLWithPath:[docs stringByAppendingPathComponent:@"person.data"]];//3.添加持久化存储库,这里使用SQLite作为存储库NSError *error = nil;NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];if (store == nil) { // 直接抛异常  [NSException raise:@"添加数据库错误" format:@"%@",[error localizedDescription]];}//4.初始化上下文,设置persistentStoreCoordinator属性NSManagedObjectContext *context =[[NSManagedObjectContext alloc] init];context.persistentStoreCoordinator = psc;

5、添加数据

//1.传入上下文,创建一个Person实体对象NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];//设置简单属性[person setValue:@"MJ" forKey:@"name"];[person setValue:[NSNumber numberWithInt:27] forKey:@"age"];//传入上下文,创建一个Card实体对象NSManagedObject *card = [NSEntityDescription insertNewObjectForEntityForName:@"Card" inManagedObjectContext:context];[card setValue:@"4414241933432" forKey:@"no"];//2.设置Person和Card之间的关联关系[person setValue:card forKey:@"card"];//3.利用上下文对象,将数据同步到持久化存储库NSError *error = nil;BOOL success = [context save:&error];if (!success) {    [NSException raise:@"访问数据库错误" format:@"%@",[error localizedDescription]];}// 如果是想做更新操作:只要在更改了实体对象的属性后调用[context save:&error],就能将更改的数据同步到数据库

6、查询数据

//1.初始化一个查询请求NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];//设置要查询的实体NSEntityDescription *desc = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context];//1>设置排序(按照age降序)NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];request.sortDescriptors = [NSArray arrayWithObject:sort];//2>设置条件过滤(name like '%Itcast-1%')NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@", @"*Itcast-1*"];request.predicate = predicate;//2.执行请求NSError *error = nil;NSArray *objs = [context executeFetchRequest:request error:&error];if (error) {      [NSException raise:@"查询错误" format:@"%@",    [error localizedDescription]];}//3.遍历数据for (NSManagedObject *obj in objs) {      NSLog(@"name=%@", [obj valueForKey:@"name"]}

7、删除数据

//传入需要删除的实体对象[context deleteObject:managedObject];//将结果同步到数据库NSError *error = nil;[context save:&error];if (error) {      [NSException raise:@"删除错误" format:@"%@",    [error localizedDescription]];}

8、打开coredata的s q l日志输出 开关

这里写图片描述

9、coredata 的延迟加载(不会根据实体中的关联关系立即获取相应的关联对象)
比如通过Core Data取出Person实体时,并不会立即查询相关联的Card实体;当应用真的需要使用Card时,才会查询数据库,加载Card实体的信
10、NSManagedObject子类
默认情况下,利用Core Data取出的实体都是NSManagedObject类型的,能够利用键-值对来存取数据
使用场景:存取数据的基础上,添加一些业务方式完成一些其他任务

例子:保存未读消息

#pragma mark - 保存未读消息/** 先查询,在修改 */+ (void)saveMessageWithMessage:(IPMessageDetailData*)data{    if (data.messageId == nil || data == nil){        return;    }    NSManagedObjectContext *context = [IPMessageDataTool shareContext];    NSFetchRequest *request = [[NSFetchRequest alloc] init];    request.entity = [NSEntityDescription entityForName:@"Message" inManagedObjectContext:context];    // 设置排序(按照messageId降序)    NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"messageId" ascending:NO];    request.sortDescriptors = [NSArray arrayWithObject:sort];    // 设置条件过滤(搜索name中包含字符串"Itcast-1"的记录,注意:设置条件过滤时,数据库SQL语句中的%要用*来代替,所以%Itcast-1%应该写成*Itcast-1*)    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"messageId = %@  AND operateID = %@",data.messageId,[SessionMgr Instance].operateID];    request.predicate = predicate;    // 执行请求    //    request.fetchLimit = 50;    NSError *error = nil;    NSArray *objs = [context executeFetchRequest:request error:&error];    if (error) {        [NSException raise:@"查询错误" format:@"%@", [error localizedDescription]];    }    Message *tmpMessage;    if (objs.count>0) {        tmpMessage = objs[0];        return;    }else{        tmpMessage = [NSEntityDescription insertNewObjectForEntityForName:@"Message" inManagedObjectContext:context];    }    tmpMessage.messageExpiredTime = data.messageExpiredTime;    tmpMessage.messageIssueTime = data.messageIssueTime;    tmpMessage.messageId = data.messageId;    tmpMessage.messageTitle = data.messageTitle;    tmpMessage.operateID = [SessionMgr Instance].operateID;    tmpMessage.isRead = NO;    BOOL success = [context save:&error];    if (!success) {        [NSException raise:@"访问数据库错误" format:@"%@", [error localizedDescription]];    }}

NSPredicate 的使用举例

谓词技术的使用 NSPredicate (以一定的条件(特定日期)过滤maTemp数组,即进行大数据搜索。)

谓词的使用例子

八、UITabBarController

//UITabBarItem view显示的内容由对应子控制器的tabBarItem属性决定

[redVc.tabBarItem setTitle:@"red"]; redVc.tabBarItem setImage:(UIImage * _Nullable)

正文

一、QQ主流框架

这里写图片描述

1、push的时候隐藏buttomBar
这里写图片描述

2、自定义@interface HSAddContactTableViewController : UITableViewController的时候,在与storyboard进行连线的时候,记得注视掉自动实现的代码。

3、staticcells类型的tableView,已经确定了分组和分组的cell个数,在vc中实现的代理方法应该返回分组数字不应该小于xib的分组数。

总结

一、框架设计
1、设计一个主头文件,来包含框架内部所有的头文件
2、如何接口文件只是用于声明的话,尽量使用@class,而不是#import

#import <UIKit/UIKit.h>@class HSContactsModel;

3、数据的装配时候,要确保已经存在视图

@property (nonatomic,strong) HSContactsModel *model;//模型属性,的setter方法如果在跳转到VC之前调用,不会达到装配view的结果--因为VC的View只有在要显示的时候才加载,

4、自定义cell的小知识点

 #pragma mark 模版提高的方法/**   初始化方法 使用代码创建cell的时候会被调用;若使用xib或者storyBoard创建cell控件的话,此方法不会被调用 */- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];//继承父类信息    if (self) {        //设置个性信息    }    return self;}/** Prepares the receiver for service after it has been loaded from an Interface Builder archive, or nib file. xib文件每次被加载之后,会调用此方法;若使用纯代码创建cell控件的时候,不会调用此方法 */- (void)awakeFromNib {    // Initialization code}/** Sets the selected state of the cell, optionally animating the transition between states. 1.cell控件被选中或者取消选中的时候,都会调用此方法 2.如果是自定义cell,则cell的子控件都应该添加到contentView中 */- (void)setSelected:(BOOL)selected animated:(BOOL)animated {    [super setSelected:selected animated:animated];    // Configure the view for the selected state    if (selected) {        [self.contentView setBackgroundColor:[UIColor lightGrayColor]];    }else{        [self.contentView setBackgroundColor:[UIColor whiteColor]];    }}

p s:cell的frame,由tableView决定(父视图的frame改变的时候,会重新布局子控件)

#pragma mark - setTransform 处理//Tells the view that its superview changed. 当前的控件加载到父控件(tableview)的时候调用- (void)didMoveToSuperview{    NSLog(@"%s 9999",__func__);    //2.对button的imageView的image进行平移、翻滚--先加载数据,在设置平移    CGFloat angle = (self.friendsGroup.isOpen) ? M_PI_2 :0;    [self.titleButtonView.imageView setTransform:CGAffineTransformMakeRotation(angle)];}/**当父控件(self)frame发生改变的时候会调用此方法,进行子控件的重新布局  */- (void)layoutSubviews{    [self.titleButtonView setFrame:self.bounds];    CGFloat onlineWidth = 150 ;    CGFloat onlineX =CGRectGetWidth(self.frame) - onlineWidth - KPading ;    CGFloat onlineY = KPading ;    CGFloat onlineHright =CGRectGetHeight(self.frame)- 2*KPading;    [self.onlineLableView setFrame:CGRectMake(onlineX, onlineY, onlineWidth, onlineHright)];}

5、语法
1》类目
类目

@interface HSContactsModel ()@end

2》使用一个新方法,需明确本方法什么时候调用,以及方法的作用

6、 归档的注意事项(NSCoding协议的使用)

//  HSCustomView.m//  20160407-plist方式存储////  Created by devzkn on 4/7/16.//  Copyright © 2016 hisun. All rights reserved.//#import "HSCustomView.h"@implementation HSCustomView/*1、优先级 2016-04-07 18:51:21.396 20160407-plist方式存储[5546:241416] -[HSCustomView initWithCoder:] 2016-04-07 18:51:21.398 20160407-plist方式存储[5546:241416] -[HSCustomView awakeFromNib]2/如果父类也遵守了NSCoding协议,请注意:-[super encodeWithCode:encode];确保继承的实例变量也能被编码,即也能被归档p s:--UIView 就是个典型的例子,UIView的子类必学实现initWithCoder:decoder,否则无法继承父类属性。*/- (instancetype)initWithCoder:(NSCoder *)aDecoder{    NSLog(@"%s",__func__);    self = [super initWithCoder:aDecoder];//实现父类,继承父类属性    return self;}- (void)awakeFromNib{    NSLog(@"%s",__func__);}

7、开发规范(开发技巧)
1》宏的变量名称以项目名前缀开头:e g.HS

8、本地化设置--针对iOS官方控件
这里写图片描述

另:CFBundleAllowMixedLocalizations 开启系统预定义的本地化功能

info plist 的配置信息:

<key>CFBundleAllowMixedLocalizations</key> <true/>

9.Launch Screen Constraints

The system loads the launch screen file before launching the app which creates some constraints on what it can contain (some of which may force you back to static image files):
The app is not yet loaded so the view hierarchy does not exist and the system can not call any custom view controller setup code you may have in the app (e.g. viewDidLoad)
You can only use standard UIKit classes so you can use UIView or UIViewController but not a custom subclass. If you try to set a custom class you will get an Illegal Configuration error in Xcode.
The launch screen file can only use basic UIKit views such as UIImageView and UILabel. You cannot use a UIWebView.
If you are using a storyboard you can specify multiple view controllers but there are again some limitations. For example you can embed view controllers in a navigation or tab bar controller but more complex container classes such as UISplitViewController do not work (at least not yet).
Localizing the launch screen file does not currently seem to have any effect. The base localization is always used so you will probably want to avoid text on the launch screen.
You cannot specify different launch screen files for iPad and iPhone. This may be a problem if you have significantly different interfaces for those devices as there is only so much you can do with auto layout and size classes.

另:**640 × 960 pixels、640 × 1136 pixels。
如果不设置这两种的尺寸启动页的话,在4英寸、3.5英寸的设备上展示不了启动页,app 的高度也默认都是矮的960px.**

• 注意@3x 提供给开发的px 为1242*2208 ,但真实的px 是1080*1920,系统API会自动进行等比例缩小;

10、判断对象的class

//        [self isMemberOfClass:]// 判断是否为本类  whether the receiver is an instance of a given class.//    [self isKindOfClass:];//   判断是否为本类 或者子类 whether the receiver is an instance of given class or an instance of any class that inherits from that class.

11、像素与点的转换:
通常将像素除以2的到点,iOS都是以点(point)为单位。
这里写图片描述

@3x 的时候,逻辑分辨率与点的关系就是3倍。