Effective Objective-C 2.0 学习记录
由于最近入职,公司安排自由学习,于是有时间将Effective Objective-C 2.0一书学习了一遍。由于个人知识面较窄,对于书中有些内容无法理解透彻,现将所学所理解内容做一遍梳理,将个人认为常用且重要的知识记录下来,以供日后参考。
1.在类的头文件中尽量少引入其他头文件
将头文件引入的时机尽量延后,在确有需要的时才引入(比如.m文件中)。因为头文件中引入其他类头文件,会增加编译时间(可能是现在运行硬件比较好,所以对此点没啥感觉)。在头文件中若要使用其他类,则用"向前声明"-->@class + 类名。
2.多用类型常量,少用#define预处理指令
因为用预处理指令定义出来的常量不含类型信息,编译器只会进行查找替换,即使有人重新定义了常量值,编译器也不会产生警告。建议使用方法如下
//将#define
#define ANIMATION_DURATION 0.3
//用此句代码表示
static const NSTimeInterval kAnimationDuration = 0.3;
这样不仅可以知道常量类型 还可以将数据局限于本类文件中使用
3.用枚举表示状态、选项、状态码
初级编写代码人员可能直接写出枚举,编写其状态
typedef enum PSPConnectionState{
PSPConnectionStateDisconnected = ,
PSPConnectionStateConnecting,
PSPConnectionStateConnected,
}PSPConnectionState;
初看好像并无不妥,但如果改变一下编写枚举的方式,写成如下所示
//单选状态枚举
typedef NS_ENUM(NSUInteger, PSPConnectionState){
PSPConnectionStateDisconnected = ,
PSPConnectionStateConnecting,
PSPConnectionStateConnected,
};
//复选状态枚举
typedef NS_OPTIONS(NSUInteger, PSPConnectionState){
PSPConnectionStateDisconnected = << ,
PSPConnectionStateConnecting = << ,
PSPConnectionStateConnected = << ,
};
这样用NS_ENUM和NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型,除了可以确保枚举是开发者所选的底层数据类型实现出来外,还能够方便其他开发人员查看和使用。另外注意在处理枚举类型时可以尽量使用switch语句,并且不要实现default分支,这样的话,在新加如枚举之后,编译器就会提醒开发者switch语句没有处理所有的枚举。
4.在对象内部尽量直接访问实例变量
直接访问实例变量由于不经过Objective-C的"方法派发"步骤,所以访问速度会比较快,但由于直接访问实例变量不会触发"键值观测"(KVO),因此建议读数据时直接通过实例变量来读,而写入数据的时候,则通过属性来写(点语法)。当然对于惰性加载的属性,需要通过属性来读取数据。
5.理解消息转发机制
消息转发分为两大阶段:第一阶段先征询接受者所属类,看其是否能动态添加方法,以处理当前这个“未知的选择器”,这个叫做“动态方法解析”。第二阶段涉及“完整的消息转发机制”。消息整体转发流程通过下图来表示
这里模拟在动态方法解析中添加方法 下面为代码示例
=======.h文件中=========
@interface BQAutoDictionary : NSObject //随意创建的属性
@property (nonatomic, copy) NSString *string;
@property (nonatomic, strong) NSNumber *number;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) id opaqueObject; @end
=======.m文件中=========
@interface BQAutoDictionary() @property (nonatomic, strong) NSMutableDictionary *backingStore; @end @implementation BQAutoDictionary
//不动态生成get,set方法
@dynamic string, number, date, opaqueObject; - (instancetype)init
{
self = [super init];
if (self) {
_backingStore = [NSMutableDictionary new];
}
return self;
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
//获得无法处理消息名字
NSString *selectorString = NSStringFromSelector(sel);
NSLog(@"%s",__func__);
//动态添加set和get方法
if ([selectorString hasPrefix:@"set"]) {
/**
* 动态添加set方法
* @param self 类别
* @param sel 方法选择器
* @param IMP 需要增加的方法
*/
class_addMethod(self, sel, (IMP)autodictionarySetter, "v@:@");
}else{
class_addMethod(self, sel, (IMP)autodictionaryGetter, "@@:");
}
return YES;
//若不能处理消息时需要返回下面方法,进行消息转发
//return [super resolveInstanceMethod:sel];
}
id autodictionaryGetter(id self, SEL _cmd){
//得到实例中的字典
BQAutoDictionary *typedSelf = (BQAutoDictionary *)self;
NSMutableDictionary *backingStore = typedSelf.backingStore;
//根据选择器获取名字
NSString *key = NSStringFromSelector(_cmd);
NSLog(@"Getter Name = %@",key);
//返回值
return [backingStore objectForKey:key];
}
void autodictionarySetter(id self, SEL _cmd, id value){
BQAutoDictionary *typedSelf = (BQAutoDictionary *)self;
NSMutableDictionary *backingStore = typedSelf.backingStore;
NSString *selectorString = NSStringFromSelector(_cmd);
NSMutableString *key = [selectorString mutableCopy];
NSLog(@"Setter Name = %@",key);
//移除‘:’字符
[key deleteCharactersInRange:NSMakeRange(key.length - , )];
//移除'set'字符
[key deleteCharactersInRange:NSMakeRange(, )];
//首字母改小写
NSString *lowercaseFirstChar = [[key substringToIndex:] lowercaseString];
[key replaceCharactersInRange:NSMakeRange(, ) withString:lowercaseFirstChar];
if (value) {
[backingStore setObject:value forKey:key];
}else{
[backingStore removeObjectForKey:key];
}
}
@end
6.用前缀避免命名空间冲突
由于开发人员文件整合的时候经常出现命名重复的问题,但Objective-C没有命名空间机制。因此避免文件重命名的办法就是:为所有的名称都加上适当的前缀。Apple宣称其保留使用所有“两字母前缀”的权利,所以我们选用的前缀应该是三个字母的!
7.尽量使用不可变对象
属性是read-write,这样出来的类对象都是可变的。一般情况下我们要建模的数据未必都需要改变。比如网络服务的数据请求后,我们只是将数据进行展示。当然若希望某属性仅可于对象内部修改,则可在延展中将其属性由readonly扩展为readwrite。示例如下
=====.h文件======
@interface BQAutoDictionary : NSObject
@property (nonatomic, readonly) NSString *name;
@end
=====.m文件======
@interface BQAutoDictionary ()
@property (nonatomic, readwrite, copy) NSString *name;
@end
8.在dealloc方法中只释放引用并解除监听
对象在经历其生命周期后,最终会被系统回收,这时就要执行dealloc方法,因为此时对象已处于回收状态,因此不应在此方法内再做其他事情。只需要在里面释放指向其他对象的引用,并取消原来订阅的“键值观测”(KVO)或NSNotificationCenter等通知!注意对象所拥有的其他非Objective-C对象需要在这里手动释放,如果是手动管理内存,那么在最后还需要调用[super dealloc]
9.多用派发队列,少用同步锁
在以前的代码编写中,对于线程安全问题通常采用的做法是直接加线程锁。加线程锁的方法很好不过也有其缺陷,比如说,在极端情况下,同步块回导致死锁,另外其效率也不够高。这里就需要引入一个简单而高效的办法就是使用“串行同步队列”,用法如下
_syncQueue = dispatch_queue_create("PSP", ); - (NSString *)name{
__block NSString *localName;
dispatch_sync(_syncQueue, ^{
localName = _name;
});
return localName;
}
- (void)setName:(NSString *)name{
dispatch_sync(_syncQueue, ^{
_name = name;
});
}
当然还有一种更高效的方法用栅栏(barrier),栅栏块必须单独执行,不能与其它块并行(只对并发队列有意义)
//并行队列
_syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
//用同步
- (NSString *)name{
__block NSString *localName;
dispatch_sync(_syncQueue, ^{
localName = _name;
});
return localName;
}
//利用异步栅栏块
- (void)setName:(NSString *)name{
dispatch_barrier_async(_syncQueue, ^{
_name = name;
});
}
10.构建缓存时选用NSCache而非NSDictionary
在进行网络请求是如何缓存,大部分程序员可能是直接使用NSDictionary,其实NSCache类更好,它是Foundation框架专为处理这种任务而设计的NScache胜过NSDicitionary之处在于,当系统资源将要耗尽时,它可以自动删除缓存。如果采用普通的字典,那么就需要自己编写挂钩(我也不懂啥意思)。此外NSCache还会先行删除“最久未使用的”对象。另外还有个类叫做NSPurgeableData(NSMutableData子类),和NSCache搭配起来使用效果很好。具体使用方法可以自行百度!
以上便是个人觉得需要整理的知识,若其中有什么错误之处,请大家指出,谢谢!
Effective Objective-C 2.0 学习记录的更多相关文章
- tempo 2.0 学习记录
最近在做项目时使用了tempo,感觉还不错,但是发现网上对于tempo 2.0 的介绍比较少,我也是在GitHub才找到了比较完整的使用说明,我也简单记录一下自己的使用过程,重新学习一下tempo 2 ...
- html5.0学习记录(一)——可拖动视频播放器
最近自己在重新学习html5新特性,了解到有视频标签和拖动标签,于是自己用这两个特性写了一个小demo,主要功能就是可以通过拖动视频来直接播放.效果图如下: 页面使用了<video>标签和 ...
- .net core 2.0学习记录(三):内置IOC与DI的使用
本篇的话介绍下IOC和ID的含义以及如何使用.Net Core中的DI. 一.我是这么理解IOC和DI的: IOC:没有用IOC之前是直接new实例来赋值,使用IOC之后是通过在运行的时候根据配置来实 ...
- webpack4.0学习记录
2019/04/28 1.本质上,webpack基于node node跟webpack为最新稳定版,才能更好,更快的打包 安装 1.卸载node 直接在控制面板 卸载 2.安装 从官网下载 然后 ...
- .net core 2.0学习记录(四):Middleware使用以及模拟构建Middleware(RequestDelegate)管道
.net Core中没有继续沿用以前asp.net中的管道事件,而是开发了一个新的管道(Middleware): public class MiddlewareDemo { private reado ...
- .net core 2.0学习记录(一):搭建一个.Net Core网站项目
.Net Core开发可以使用Visual Studio 2017或者Visual Studio Code,下面使用Visual Studio 2017搭建一个.net Core MVC网站项目. 一 ...
- Spark2.0学习记录
Hadoop与Spark的关系: ------------------- Spark 与mapReduce的区别: mapReduce和spark的内存结构: ------------------- ...
- Lucene.net(4.8.0) 学习问题记录五: JIEba分词和Lucene的结合,以及对分词器的思考
前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...
- Lucene.net(4.8.0) 学习问题记录六:Lucene 的索引系统和搜索过程分析
前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...
随机推荐
- LoadRunner11.00入门教程出现的问题
问题1.打不开浏览器 解决办法:打开浏览器工具--Internet 选项--高级--取消启用第三方浏览器扩展. 顺带解决了,有两个浏览器问题. 两个浏览器:一个是自带的IE,一个是其他软件插件. 解决 ...
- 1CSS与文档
层叠样式表(Cascading Style Sheet,CSS)的功能十分强大,可以影响一个或一组文档的表现. 为什么结构化对HTML来说很重要:1.非结构化页面使得建立内容索引极为困难.2.缺乏结构 ...
- Android中<meta-data>的使用
[转] 原文 在AndroidManifest.xml中,<meta-data>元素可以作为子元素,被包含在<activity>.<application> .& ...
- HTML其他基本格式说明
1.<!DOCTYPE>说明页面中使用的HTML版本,只是信息声明 2.元信息元素<meta>,通过属性定义文件信息的名称.内容.文档的关键字.作者及描述等..content内 ...
- 录制简单的自动化测试工具SlikMobile初体验
今天朋友推荐了款自动化测试工具SlikMobile,下载了个试用了下,感觉还是很容易入门和上手的,感觉和testin的工具差不多,跨平台,多语言支持,支持图片.文本和Native Class三种对象方 ...
- 前台 JSON对象转换成字符串 相互转换 的几种方式
在最近的工作中,使用到JSON进行数据的传递,特别是从前端传递到后台,前台可以直接采用ajax的data函数,按json格式传递,后台Request即可,但有的时候,需要传递多个参数,后台使用requ ...
- 加载UI
weak情况 1 2 3 4 @property (weak,nonatomic) UILabel *nameLabel; UILabel *nameLabel = [[UILabel alloc ...
- 修改easyui中datagrid表头和数据不能分开对齐的BUG。
easyui的datagrid中表头和列只能同时全部向左对齐,全部向右对齐或者居中对齐. 有时候有需求,数据向左或向右,表头居中对齐. 在不修改源码的情况下.下面的代码可以实现该功能. 把下面代码放在 ...
- MySQL导入.sql文件及常用命令
在MySQL Qurey Brower中直接导入*.sql脚本,是不能一次执行多条sql命令的,在mysql中执行sql文件的命令: mysql> source d:/myprogram/d ...
- 【转】linux下memcached安装以及启动
1.下载memcached服务器端安装文件 版本: memcached-1.4.25.tar.gz 下载地址:http://www.memcached.org/files/memcached-1.4. ...