effective-Objective-C 第一章阅读笔记

文章目录

OC起源

OC采用的是消息结构,不是函数调用,由Smalltalk演化而来。

消息结构的语言运行时所应执行的代码由运行环境来决定。

使用函数调用的语言则由编译器来决定

函数型语言和消息结构型语言在处理多态时,查找要执行的具体方法的时机和方式不同

  • 基于虚方法表的语言,如C++、Java在编译期,编译器知道类的继承关系和虚函数的签名,每一个类有一个虚方法表,表中存放该类的所有虚函数的实际内存地址,对象内部由一个隐藏指针vptr指向该类的虚表,当调用多态方法时,代码需要先通过对象的cptr指针找到虚表,在表中按照固定偏移找到函数地址,跳转执行。(运行时只查表)
  • 基于消息分发类的语言,如smalltalk、Ruby、早期OC,对象之间通过发送消息来调用方法,编译器通常不绑定方法地址,甚至都不检查方法存不存在,运行时,系统查找对象所属类的方法字典,按照消息名查找对应方法的实现,会沿着继承链向上查找,找不到触发消息无法处理的机制,如调用method_missing或抛出异常,开销比较大

内存管理

OC的部分语法与C语言相同,在OC中使用指针式来指示对象。

objc 复制代码
NSString* str - @"real.";

OC中所有对象都是一个objc_object结构体,我们操作的NSString* 等都是指向这些结构体的指针。这OC中的对象存储在堆/常量区。

objc 复制代码
NSString* str = @"real.";
NSString* antStr = str;

我们看一下这段代码的内存分布:

分配在堆中的内存必须直接管理,分配在1栈上的用于保存变量的内存会在其栈帧弹出时自动清理

OC采用引用计数管理堆区内存

比起创建结构体,创建对象需要额外的开销,所以有时候采用结构体可以节约内存。

在类的头文件中尽量少引用其他头文件

在类的头文件中,如果我们需要引入其他文件,使用@class就可以了,实现向前声明,还能避免循环引用

我们在引入协议时,不可以使用向前声明,因为向前声明只能告诉编译器某个协议的存在,而编译器需要知道协议中定义的方法。

多用字面量语法

OC为我们提供了许多语法糖,实现便携书写

objc 复制代码
NSNumber* number = @1
NSNumber* number = @1.6f
NSNumber* number = @YES
NSNumber* number = @'a'
NSNumber* bumber = @(80);
objc 复制代码
NSArray* ary = @[@"ll", @"gg", @"ff"];
ary[1]//字面量取法
objc 复制代码
NSDictionary* data = [@"123":@"213"];
data[@"123"];

在使用字面量语法时,我们需要尽量避免值出现nil,避免抛出异常

多用类型变量,少用#define预处理

objc 复制代码
#define ANIMATION_DURATION 0.8;

如果该宏定义在某个头文件中,那么所有引用这个头文件的代码都会被替换

objc 复制代码
static const int number = 20;

限制该变量只在当前编译单元中可见,避免其他文件被污染
同时可以遵守下面几个规则:

只在当前文件用的常量 → k 前缀

在其他类中可见的话,可以使用类名来做前缀

只要不打算公开这个常量,就在.m文件中定义,并使用static const修饰(保证当前文件可见以及不可修改)

如果不采用static的话,如果在另一个实现文件中定义一个同名变量会报错
其实采用static和const一起来修饰的话,编译器其实还是和#define一样的实现,但是他会有类型信息。

在某些情况下,我们需要给外部一个可见的常量,可以像下面这样定义:

objc 复制代码
extern NSString* *const tom;
extern const int duration;
//.h
NSString *const tom = @"mot";
const int duration = 30;
//.m

注意const修饰的位置,与*结合就是说修饰一个常量指针,与NSString结合就是说修饰一个常量字符串

编译器看到头文件的extern之后就会将其添加到全局符号表中,需要注意避免名称冲突

枚举

objc 复制代码
enum CellType {
    CellTypeSongs
};
typedef enum CellType CellType;
CellType state = CellTypeSongs;

在C++11之后我们可以指定使用何种底层数据类型

objc 复制代码
typedef enum : NSUInteger { //这里保证我们的一个底层数据类型是NSInteger
    <MyEnumValueA>,
    <MyEnumValueB>,
    <MyEnumValueC>,
} <MyEnum>;

我们也可以从某一个值开始手工枚举成员所对应的值。

objc 复制代码
enum CellType {
    CellTypeSongs = 1,
    CellTypeAlbum
};

通过组合枚举实现多选功能

相关推荐
ShineWinsu19 小时前
对于C++:继承的解析—上
开发语言·数据结构·c++·算法·面试·笔试·继承
小付同学呀20 小时前
C语言学习(五)——输入/输出
c语言·开发语言·学习
梦幻精灵_cq20 小时前
学C之路:不可或缺的main()主函数框架(Learn-C 1st)
c语言·开发语言
消失的旧时光-194320 小时前
C++ 多线程与并发系统取向(二)—— 资源保护:std::mutex 与 RAII(类比 Java synchronized)
java·开发语言·c++·并发
编程之路从0到121 小时前
ReactNative新架构之iOS端TurboModule源码剖析
react native·ios·源码阅读
雾山大叔21 小时前
多会话浏览器串口调试助手
经验分享·笔记·学习
福大大架构师每日一题21 小时前
go-zero v1.10.0发布!全面支持Go 1.23、MCP SDK迁移、性能与稳定性双提升
开发语言·后端·golang
五阿哥永琪1 天前
1. 为什么java不能用is开头来做布尔值的参数名,会出现反序列化异常。
java·开发语言
逻极1 天前
pytest 入门指南:Python 测试框架从零到一(2025 实战版)
开发语言·python·pytest
桂花很香,旭很美1 天前
Anthropic Agent 工程实战笔记 · 延伸阅读
笔记·架构·agent