Objective-C 中 ivar 与 property 的本质区别
关键词:ivar、property、内存布局、Runtime、KVC / KVO
一、什么是 ivar(Instance Variable)
1. 定义
ivar(实例变量) 是:
- 对象真实存在的成员变量
- 是对象内存结构的一部分
- 在 alloc 时就确定大小和偏移
@interface Person : NSObject {
@public
NSString *_name; // ivar
int _age;
}
@end
2. ivar 的核心特性
-
✅ 真正存储数据
-
✅ 每个对象实例各自一份
-
✅ 编译期确定内存布局
-
❌ Runtime 不能新增
⚠️ 这也是 Category 不能加 ivar 的根本原因
二、什么是 property(属性)
1. 定义
property 是一种语法糖,用于描述:
如何访问某个值(而不是值本身)
@property (nonatomic, strong) NSString *name;
编译器通常会自动生成:
- 一个 ivar(默认 _name)
- -name getter
- -setName: setter
2. property 的本质
property
├─ getter / setter 方法声明
├─ 内存管理语义(strong / weak / copy)
├─ 线程语义(atomic / nonatomic)
└─ KVO 支持
❗ property 本身不存数据
三、ivar vs property 的本质区别
1️⃣ 是否真实存在于内存中
| 对比项 | ivar | property |
|---|---|---|
| 是否占对象内存 | ✅ 是 | ❌ 否 |
| 是否真实存值 | ✅ 是 | ❌ 否 |
| 是否对象结构的一部分 | ✅ 是 | ❌ 否 |
👉 对象里真正存数据的只有 ivar
2️⃣ 访问方式不同
ivar 访问(直接内存访问)
_name = @"Hanqiu";
- 不走方法调用
- 不触发 KVO
- 不执行内存管理语义
property 访问(方法调用)
self.name = @"Hanqiu";
等价于:
[self setName:@"Hanqiu"];
会触发:
- strong / weak / copy
- KVO
- 自定义 setter 逻辑
3️⃣ 内存管理能力差异
@property (nonatomic, strong) NSObject *obj;
在 MRC 下,setter 逻辑类似:
- (void)setObj:(NSObject *)obj {
if (_obj != obj) {
[_obj release];
_obj = [obj retain];
}
}
👉 ivar 本身没有任何内存管理能力
4️⃣ KVC / KVO 行为差异
KVO
- KVO 是基于 setter 实现的
- 直接修改 ivar 不会触发
_name = @"A"; // ❌ 不触发 KVO
self.name = @"B"; // ✅ 触发 KVO
KVC 查找顺序(简化)
setName:
_name
name
isName
- KVC 可以直接访问 ivar
- property 只是优先入口
四、ivar 与 property 的关系总结
一句话总结
ivar 是数据本体,property 是访问规则
对象内存
└── ivar(_name)
└── property 提供访问方式
五、常见误区澄清
❌ 误区 1:property 就是 ivar
❌ 错
@property (nonatomic, readonly) NSString *name;
如果手写 getter:
- (NSString *)name {
return @"xxx";
}
👉 不会生成 ivar
❌ 误区 2:Category 里的 property 会生成 ivar
❌ 错(高频考点)
@interface UIView (Ext)
@property (nonatomic, strong) NSString *tagName;
@end
-
只生成 getter / setter 声明
-
❌ 不生成 ivar
✔ 必须使用 Associated Object
❌ 误区 3:不能直接使用 ivar
❌ 错
- 内部逻辑:可直接使用 ivar(效率高)
- 对外接口:应使用 property(安全、可维护)
六、在 Extension / Category 中的差异
| 场景 | ivar | property |
|---|---|---|
| 普通类 | ✅ | ✅ |
| Class Extension | ❌ 直接写 ivar✅ 通过 property | ✅ |
| Category | ❌ | ⚠️ 仅方法声明 |
七、推荐实践写法(工程级)
// Player.h
@interface Player : NSObject
@property (nonatomic, copy, readonly) NSString *name;
@end
// Player.m
@interface Player ()
@property (nonatomic, copy) NSString *name;
@end
优点
- 对外只读,API 干净
- 对内可写,逻辑清晰
- ivar 由 Extension 管理
八、终极一句话
ivar 是对象真实存在的内存成员,property 是对 ivar 的访问规则封装,通过 getter/setter 提供内存管理、KVO 等能力。