Effective Objective-C 第一章阅读笔记

金歌  金牌会员 | 2025-1-13 16:12:02 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 923|帖子 923|积分 2769

Effective Objective-C 第一章阅读笔记


  
OC的语言起源

OC接纳的利用消息布局,而不是函数调用。OC由Smalltalk演化而来,后者是消息型语言的鼻祖。
消息与函数调用之间的区别看上去就像如许:
  1. // Messaging(Objective-C)
  2. Object* obj = [Object new];
  3. [obj performWith: parameter1 and: parameter2];
  4. // Function calling(C++)
  5. Object* obj = new Object;
  6. obj->perform(parameter1, parameter2);
复制代码
这里的关键区别在于,消息布局的语言,其运行时所应执行的代码由运行环境来决定;利用函数调用的语言,则由编译器来决定
假如这里面调用的函数时多态的,那么对于函数型语言则是通过一个虚方法表来查出应该执行哪一个函数,至于接纳消息布局的语言,无论是否多态,总是在运行时才会去查找所要执行的一个方法。
OC的告急工作都由运行期组件完成,运行期组件本质上是一种与开发者所毗连的动态库,这里会在后面的内容中介绍。
内存管理

OC的有些语法是照搬C语言的,OC中的指针式用来指示对象的。
  1. NSString *someString = @"The String"
复制代码
上面代码中的someString变量是用来指代一个NSString的类型的,这里所有的对象都是存储到我们的堆空间中的,而不是栈区。也就是说这种代码是不可以存在的:
  1. NSString someString;
复制代码
下面的代码体现出了一个浅拷贝的内容。
  1. NSString* someString = @"The string";
  2. NSString* anotherString = someString;
复制代码
下图描述了他的一个内存分布

分配在堆中的内存必须直接管理,分配在栈上的用于保存变量的内存会在其栈帧弹出时自动清理
OC接纳引用计数来管理堆区的内存,当然OC中也存在定义中不含有*的变量

创建布局体相比,创建对象还必要额外开销,这里接纳布局体可以节省很多内存。
小结



  • Objective-C为C语言添加了面向对象特性,是其超集。Objective-C利用动态绑定的消息布局,也就是说,在运行时才会检查对象类型。接收一条消息之后,究竟应执行何种代码,由运行期环境而非编译器来决定。
在类的头文件中尽量少引入其他头文件

在开发中我们经常会创建很多类,在OC中类的头文件是如下的布局:
  1. // EOCPerson.h
  2. #import <Foundation/Foundation.h>
  3. @interface EOCPerson : NSObject
  4. @property (nonatomic, copy) NSString *firstName;
  5. @property (nonatomic, copy) NSString *lastName;
  6. @end
  7. // EOCPerson.m
  8. #import "EOCPerson.h"
  9. @implementation EOCPerson
  10. // Implementation of methods
  11. @end
复制代码
但一样平常我们可能会创建另一个种别EOCEmployer,后面发现每一个EOCEmployer都应该被EOCPerson持有,于是我们会在EOCPerson的头文件的前面添加一天#improt "EOCEmployer.h",尽管这个可以实现,但是浪费很多时间,在头文件部分我们实在只必要让EOCPerson知道这个类的存在就可以了,以是我们只用接纳@class EOCEmployer就可以实现了
假如在EOCPerson的代码中我们必要用到EOCEmployer的接口细节的时候,我们在类的实现部分在导入对应的头文件#improt "EOCEmployer.h
  1. // EOCPerson.m
  2. #import "EOCPerson.h"
  3. #import "EOCEmployer.h"
  4. @implementation EOCPerson
  5. // Implementation of methods
  6. @end
复制代码
同时向前声明还可以办理我们这里的两个类相互引用的一个标题


这里可以看到我们在两个头文件中相互引用的时候,会出现编译错误的标题,但是假如我们换成@class就不会出现对应的一个标题
这里引用原文来介绍一下:

但是我们在引入协议的时候,就不可以利用向前声明。向前声明只能告诉编译器有某个协议,而编译器却要知道他定义的方法。
但是在某些委托协议中,就不消单独写一个头文件了。在那种环境下,协议只有与继承协议委托的类在一起定义才有意义,可以把那段实当代码放在对应分类中。
小结



  • 除非确有须要,否则不要引入头文件,尽量接纳向前声明来提及别的类
  • 无法利用向前声明的时候,尽量把’这个类遵照某协议’这一条声明放在分类中,
多用字面量语法

这部分内容主要还是一些更加便捷的语法:
比方说NSNumber可以接纳
  1. NSNumber* number = @1
  2. NSNumber* number = @1.5f
  3. NSNumber* number = @YES
  4. NSNumber* number = @'a'
  5. int x = 3
  6. float y = 6.32f
  7. NSNumber* = @(x * y)
复制代码
NSArray可以接纳
  1. NSArray* ary = @[@"123", @"223", @"3214"];
  2. //取对应的一个下标
  3. ary[1]//字面量取法
复制代码
NSDictionary可以接纳
  1. NSDictionary* data = [@"123":@"213"];
  2. //取某一个值
  3. data[@"123"];
复制代码
可变数组与字典
  1. mutableAry[1] = @"dog"
  2. mutableDryp[@"213"] = @"23144"
复制代码


  • 注意利用字面量语法的时候,我们要保证我们的值不会出现nil,假如出现nil会抛出非常。
多用类型变量,少用#define预处理指令

熟悉C语言的我们,对于下面这一行代码也是比较熟悉,但是这段代码实在会造成某些隐患

假设这个指令声明在某个头文件中,那么所有引入了头文件的代码,他都会被替换。
当我们在完成一个很大的项目中,很可能会出现重复的常量名,如许可能会出现一个替换,从而导致代码出现一些标题。
我们应该把预处理指令换成我们的一个类型常量:
  1. static const int kDuration = 30;
复制代码
我们可以发现他有类型信息,可以更好的描述来常量的含义,这里我们命名常量的时候,假如局限在某一个编译单位中就加字母k,假如常量在类之外可见,则通常以类名为前缀。
然后我们尽量不要在头文件中定义,由于我们假如在头文件中声明的话,就相当于声明了一个名字为kDuration的全局变量,以是我们不应该在头文件中定义。
只要不打算公开这个常量,我们应该将其定义在该常量的实现文件中。变量一定要同时用static和const来声明


  • 接纳static可以保证这个变量只能在定义此变量的编译单位中可见(也就是定义他的一个实现的.m文件)
  • 接纳const可以保证他不被修改。
假如不接纳static,如许假如在另一个实现文件中定义一个同名的变量会抛出一个错误。
这里实在接纳static和const一起来修饰的话,编译器实在还是和#define一样的实现,但是他会有类型信息。
在某些环境下,我们可能必要给外部一个可见的常量,这类常量我们应该如许定义:
  1. extern NSString* *const EOCString;
  2. extern const int duration;
  3. //头文件
  4. NSString *const EOCString = @"Value";
  5. const int duration = 30;
  6. //实现部分
复制代码
这里我们要注意const修饰的位置,const是为了保证我们的这个指向EOCString的指针稳定。
编译器看到我们在头文件中的extern就会把他添加到全局符号表中,由于符号会被添加到全局符号表中,以是命名常量需谨慎,千万不能出现名称冲突。
总之,我们呢不要利用预处理定义常量,应该借助编译器来保证我们呢的常量精确,在实现部分可以接纳static和const。(这里笔者之后会写一篇有关这几个关键字的博客)
小结



  • 不要用预处理下令
  • 在实现文件中用static和const来定义在编译单位内可见的常量
  • 在头文件中用extern来声明全局变量,并在相关实现文件中定义他的值
枚举表现状态,选项,状态码

这里简单介绍一下他的语法。
  1. enum EOCConnectionState {
  2.     EOCConnectionStateDisconnected
  3. };
  4. typedef enum EOCConnectionState EOCConnectionState;
  5. EOCConnectionState state = EOCConnectionStateDisconnected;
复制代码
在C++11之后我们可以指定利用何种底层数据类型。
  1. typedef enum : NSUInteger { //这里保证我们的一个底层数据类型是NSInteger
  2.     <MyEnumValueA>,
  3.     <MyEnumValueB>,
  4.     <MyEnumValueC>,
  5. } <MyEnum>;
复制代码
我们也可以在某一个值开始,通过手工来指定某个枚举成员所对应的一个值。
  1. enum EOCConnectionState {
  2.     EOCConnectionStateDisconnected = 1,
  3.     EOCConnectionStateConnected
  4. };
复制代码

这里就可以通过按位与来组合差别的选项。
末了我们在switch语句中可以用枚举值来取代对应的一个选择。

然后我们的switch中尽量不要利用default的分支。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表