基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

assign 和 weak 的区别?

知识点图片

在 iOS 开发(Objective-C)中,assignweak 都是用于修饰属性(Property)的关键字,它们的主要区别在于对象释放后的行为以及适用的数据类型

以下是核心区别的详细总结:

1. 核心区别总结

特性 weak assign
对象释放后 自动置为 nil (安全) 保持原地址不变,变成悬垂指针 (不安全)
适用类型 仅限 Objective-C 对象 (id, UIView, etc.) 基本数据类型 (int, float, BOOL) + C数据结构
引用计数 不增加引用计数 不增加引用计数
底层实现 依赖 Runtime 的哈希表维护 简单的指针地址赋值

2. 详细原理解析

assign

  • 定义assign 是简单的赋值操作。
  • 内存管理:它不会改变对象的引用计数。
  • 适用场景:主要用于修饰基本数据类型(如 NSInteger, CGFloat, BOOL)和 C 数据结构(如 struct, enum)。
  • 用于对象的危险性(悬垂指针/野指针)
    • 如果在 ARC 下用 assign 修饰一个对象,当该对象被释放(dealloc)后,指针变量依然指向那块内存地址。
    • 如果你再次访问这个属性,就会访问一块已经回收的内存,导致 Crash (EXC_BAD_ACCESS)
    • 比喻:你记住了某人的家庭住址。房子拆迁了,你手里还拿着地址。如果你按地址找过去,可能会掉进废墟坑里(崩溃)。

weak

  • 定义weak 表示一种“非拥有”关系。
  • 内存管理:它不会改变对象的引用计数。
  • 适用场景:仅用于 Objective-C 对象。常用于解决循环引用(Retain Cycle)问题,例如 delegate 代理属性或 Block 中的 self
  • 安全性(自动置 nil)
    • weak 指向的对象被销毁时,Runtime 会自动将这个指针变量赋值为 nil
    • 在 OC 中,向 nil 发送消息是安全的(什么都不会发生),所以不会导致 Crash。
    • 比喻:你记住了某人的家庭住址,但这个地址写在一张魔法纸上。如果房子拆迁了,魔法纸上的字会自动消失(变成空白/nil)。你再看纸,上面什么都没有,你就知道不用去了。

3. 底层实现原理(面试加分项)

  • assign 的实现
    非常简单,就是内存地址的拷贝。

  • weak 的实现
    Runtime 维护了一张全局的 Weak 表(Hash Table)

    1. Key:被引用对象的内存地址。
    2. Value:一个数组,存储了所有指向该对象的 weak 指针的地址。
    3. 当对象调用 dealloc 释放时,Runtime 会去查这张表,找到所有指向它的 weak 指针,将它们统一置为 nil,然后从表中删除该记录。

4. 常见代码示例

正确用法:

plaintext
// 基本数据类型用 assign
@property (nonatomic, assign) NSInteger age;

// 代理通常用 weak 避免循环引用
@property (nonatomic, weak) id<MyDelegate> delegate;

// UI控件(如果是 XIB/Storyboard 拖拽的)通常用 weak,因为 view hierarchy 已经强引用了它
@property (nonatomic, weak) IBOutlet UILabel *titleLabel;

错误用法(会导致 Crash):

plaintext
// 错误:用 assign 修饰对象
@property (nonatomic, assign) NSString *name; 

// 场景:
self.name = [NSString stringWithFormat:@"Hello"]; // name 指向一个对象
// ... 稍后该字符串对象引用计数归零被释放 ...
NSLog(@"%@", self.name); // 崩溃!因为 self.name 还是指向原来的地址,但内存已回收

一句话总结

assign 适用于基本数据类型,对象释放后变野指针;weak 适用于对象,对象释放后自动变 nil

00:00
00:00