Objective-C 中 ivar 与 property 的本质区别

5 阅读2分钟

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;

编译器通常会自动生成:

  1. 一个 ivar(默认 _name)
  2. -name getter
  3. -setName: setter

2. property 的本质

property
 ├─ getter / setter 方法声明
 ├─ 内存管理语义(strong / weak / copy)
 ├─ 线程语义(atomic / nonatomic)
 └─ KVO 支持

❗ property 本身不存数据


三、ivar vs property 的本质区别

1️⃣ 是否真实存在于内存中

对比项ivarproperty
是否占对象内存✅ 是❌ 否
是否真实存值✅ 是❌ 否
是否对象结构的一部分✅ 是❌ 否

👉 对象里真正存数据的只有 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 中的差异

场景ivarproperty
普通类
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 等能力。