Effective Objective-C 2.0 初读小结
- 1.对于OC中的对象声明例如
NSObject *obj1 = [NSObject new];
, obj1这个指针变量是分配在栈上的, 他指向的是这一个分配在堆上面的实例对象, 如果进行下面的赋值操作NSObject *obj2 = obj1;
,那么并没有新生成一个实例对象, 只是在栈上分配了一个新的指针变量obj2, 而obj2和obj1指向的实例对象是同一个. - 2.关于文件头文件的引入问题, 一般情况下不建议在
A.h
文件中引入其他的B.h
文件, 因为在别人引入A.h
的时候, 同时也引入了B.h
文件, 增加不必要的文件耦合和编译时间, 一般在.h
文件中使用前向声明
即@class B
, 而在.m文件中才真的引入头文件, 当然对于protocol不能使用前向声明, 如果将protocol放在了另一个.h文件中, 那么就必须要引入这个头文件了. - 3.尽量使用字面量语法来初始化字符串, 数组, 字典等, 因为字面量语法其实是一种
语法糖
, 使用它可以让代码可读性更高, 当然对于一些必须要使用到初始化方法的时候字面量语法就不好用了.例如: NSString *str = @"string"; NSArray *arr = @[obj1, obj2]; arr[1]// 读取使用下标而尽量不使用对应的函数... [array setObject:(nonnull id) atIndexedSubscript:(NSUInteger)]
- 4.少用#define来定义常量, 因为宏定义只是简单的代码替换, 并没有类型判断, 不便于我们阅读判断, 同时宏定义可以被覆盖, 当别人引入了我们的头文件的时候, 可能会覆盖我们里面定义的宏, 带来很麻烦的调试, 我们应该使用C语言风格的
const
,static
,extern
相结合来定义常量/// 使用static 和const 定义文件内部的常量 一般使用k开头命名 static float const kAnimationTime = 2.0f; /// 使用const定义全局的常量, 在其他文件中可以通过 extern float const kAnimationTime引入使用, 一般不用k开头命名, 而使用class名字 float const CustomAnimationTime = 2.0f;
- 5.用好枚举, 使用枚举来表示选项, 状态码, 可以让代码更清晰, 这个在系统的API中也经常看到, 比如按钮的状态, autoresizing... , 例如如果你需要用一些状态码来表示网络请求的结果: 你可能会有两种方法
1. 定义一个整形变量, 然后说明, 不同的整数代表不同的状态, 那么这样对于开发就很不方便, 必须得很清楚并且很正确的输入对应的整数才能表示相应的状态, 那么就很容易出错, 和不便于维护int statusCode;if (statusCode == 200) { }/// 请求成功else if () ....2. 使用枚举, 对不同的状态定义不同的名字, 这样就很清晰方便了, 当然定义的时候使用NS_ENUM比使用enum要`好` typedef NS_ENUM(NSInteger, ErrorCode) {ErrorCodeNotFind,ErrorCodeLostConnection,ErrorCodeUnknow };
显然上面你应该选用枚举, 同时还有一种情况就是, 定义
多选项
, 这个你是会把他们都放进一个数组中么?? 当然不要这样做, 这个时候也应该使用枚举来定义, 不过会有一点的小技巧, Apple对这种进行了一个包装, 使用NS_OPTIONS
而不是enum
typedef NS_OPTIONS(NSInteger, ErrorOptions) {ErrorOptionsNone = 0,ErrorOptionsOne = 1 << 0, ///左移操作 --- 1 --- 0001ErrorOptionsTwo = 1 << 1, --- 2 --- 0010ErrorOptionsThree = 1 << 2 --- 4 --- 0100 };
因为上面定义的枚举值都为2的整数次幂值, 所以后面就可以使用位操作符 与(&)和或(|)来进行选项的筛选
ErrorOptions options = ErrorOptionsOne | ErrorOptionsTwo; //--- 0011if (options & ErrorOptionsOne) {// ErrorOptionsOne// 结束判断后面}else if (options & ErrorOptionsTwo) {// ErrorOptionsTwo// ...}else {// ...}
- 6.需要遍历操作的时候, 尽量不要用C语言风格的for遍历, 而是采用OC的 for-in方式的快速枚举, 当然使用block的方式来遍历未必不是更好的一种方式, 尤其是遍历字典的时候.
- 7.需要缓存的时候使用NSCache而不要使用NSArray或者NSDictionary, 因为使用NSCache来进行缓存当内存不足的时候系统会自动清理缓存, 并且会首先清理缓存时间较长的东西, 如果使用NSArray或者NSDictionary就没有这个福利了
- 8.不要在load方法里面执行耗时的操作, 因为这个时候会阻塞当前的线程, 如果是主线程被阻塞, 那么...就不能接受用户的响应, 同时不要在load方法里面使用其他的类和调用函数, 因为这个时候程序是
脆弱
的, 有可能使用的class还没有被加载到系统中来, 当然使用Foundation里面的NSString...这些是没有问题的 - 9.initialize这个方法在文档中写明了是在第一次使用这个类的时候才会调用一次(懒加载), 但是需要注意的是, 如果父类中实现了initialize这个方法, 而子类中没有实现这个方法, 当初始化子类的时候, 父类的这个initialize方法是会被调用多次的(消息转发机制), 比如
ZJChildClass类里面没有重写initialize方法, 但是他的父类重写了, 所以在初始化ZJChildClass的时候, 父类的initialize会被调用两次, 即会打印两条@interface ZJBaseClass : NSObject@end@implementation ZJBaseClass+ (void)initialize {NSLog(@"加载一次-----");}@end@interface ZJChildClass : ZJBaseClass@end
所以一般都是这样来重写initialize方法的, 保证只会像我们期望的那样
调用
一次+ (void)initialize {if (self == [ZJBaseClass class]) { /// 不能用 [self class]NSLog(@"加载一次-----");}}
- 10.对只需要执行一次的代码使用
dispatch_once
, 这样可以保证线程安全
, 并且只执行一次, 最常见的是用来实现单例+ (instancetype)sharedInstance {static Object *sharedInstance = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{sharedInstance = [self new];});return sharedInstance; }
- 11.多用GCD少用NSObject的一些performSelector等方法, 因为使用performSelector这种方式可能会造成内存泄漏, 一般情况下使用GCD都可以完成, 比如dispatch_after来实现延时后执行
- 12.使用NSTimer的时候要特别注意内存泄漏的问题, 因为NSTimer会持有目标对象, 很容易造成循环引用的问题, 也许你会想到在这个目标对象的dealloc里面让NSTimer失效(调用 invalidation 并且置为nil), 但是这根本就没有用, 因为循环引用的原因, 根本就不会调用dealloc方法, 所以在里面销毁是没有用的, 需要在对象被销毁之前手动销毁计时器
Effective Objective-C 2.0 初读小结相关推荐
- nginx源码初读(8)--让烦恼从数据结构开始(ngx_event)
nginx中的事件模块是一个很重要的模块,但这里作为初读,我们只简单看一下ngx_event的数据结构,至于模块和机制,留作之后再分析. 下面是结构体ngx_event_t的代码: typedef s ...
- 初读《设计模式之禅》
读这本书的起因源于csdn学生大本营的一次活动<设计模式之禅>试读员招募,身为程序员兼之学生大本营的老师没有道理不踊跃参加了(参加时可没走任何后门),佛祖显灵,真的能有幸成为了试读员.从得 ...
- 敬天爱人 大道至简——初读《经营十二条》
老板送了一本稻盛和夫的<经营十二条>让我看看,前段时间一直忙于应付考试与工作,直到今天才抽出时间好好研读了一番.从这本书里读到的第一印象就是日本人性格里特有的精神至上.团队意识.日本人强调 ...
- php的swoole教程,PHP + Swoole2.0 初体验(swoole入门教程)
PHP + Swoole2.0 初体验(swoole入门教程) 环境:centos7 + PHP7.1 + swoole2.0 准备工作: 一. swoole 扩展安装 1 .下载swoole cd/ ...
- 来一起学习一下vue3.0 初体验---comeon
vue3.0 初体验 第一步创建项目 第二步对vue项目进行升级 接下来你就可以尽情的开发啊 第一步创建项目 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页.如果你想学习如何使用Ma ...
- 初读《偷影子的人》观后感
初读<偷影子的人>观后感 "为每一个你所偷来的影子找到点亮生命的小小光芒,为它们找回隐匿的记忆拼图,这便是我们对你的全部请托." < 偷影子的人>是法国作家 ...
- 极光推送 角标清0 未读消息不清空
不要调用 [UIApplication sharedApplication].applicationIconBadgeNumber = 0; 角标和通知栏未读推送都会清空 使用下面的方法... - ( ...
- vue3.0响应式源码实践,vue3.0初体验
vue3.0响应式源码实践,vue3.0初体验 镇楼图--杀生丸.jpg vue-next(vue3.0预体验) 1. 使用: 2.vue-next的目录结构 3. reactive内部实现 作者上篇 ...
- 魅族 android6.0,大屏又好用的 MEIZU 魅蓝MAX及Flyme6.0初体验
大屏又好用的 MEIZU 魅蓝MAX及Flyme6.0初体验 2017-01-03 15:49:10 9点赞 11收藏 28评论 其实这个手机已经买了快2个月了,奈何拖延症犯了.....一直不想写,拖 ...
最新文章
- 在嵌入式学习过程中,很多人都有这样的困惑!——为什么要学习嵌入式技术?...
- 双主数据库配置与应用
- 用c语言实现单链表的初始化,建表,查找,求长度,插入,删除等操作,【YTU+2430+C语言习题+链表建立+插入+删除+输(5)...
- java jnlp被阻止_JNLP应用程序Web服务访问被拒绝 - java.io.FilePermission
- R语言比较运算符和逻辑运算符
- 实用 JavaScript 调试技巧
- react学习(6)----react样式多用内联
- Downloader Middlewares反反爬虫【学习笔记04】
- Stack Usage on Transfers to Interrupt and Exception Handling Routines
- mysql nb3 备份_Navicat mysql 数据库备份和使用,备份以后是nb3文件-Go语言中文社区...
- Linux RPM软件包管理
- 部署中遇到的问题(四)
- 阿里云ECS服务器Linux环境下配置php服务器(二)--phpMyAdmin篇
- 人工客服行业遭重创,背后支撑的力量
- 我的世界python——方块朋友(方块设置移动路径getline)
- 简单好用、且永久免费的内网穿透工具
- 人工智能入门学习-人工智能岗位超吃香
- 网易云发送验证码短信,发送通知短信,java版
- 【服务器】vim使用
- 新媒体短视频运营哪些内容
热门文章
- 关于SPFA Bellman-Ford Dijkstra Floyd BFS最短路的共同点与区别
- springboot2.x 与 elasticsearch2.4.x整合出错:None of the configured nodes are available
- OC(Open collector) 集电极开路
- MSP430F5XXX中的ADC12使用
- 极限学习机和支持向量机_极限学习机I
- Linux TCP/IP中L4L3的实现框架:udp send部分
- 去杠杆高歌猛进,借呗会倒闭吗?
- vb excel 整行删除_Excel中常用的批量处理都不掌握,那就真的Out了
- linux gcc中sin30度,学习gcc.pdf
- C#委托(delegate、Action、Func、predicate)和事件