深化了解 Objective-C 特点内存办理语义
一文彻底搞懂 assign、weak、copy、strong 这些内存办理语义的用法与原理
举个例子:
//
// Dog.h
// oc-demo
//
// Created by 姚明振 on 2022/8/17.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interfaceDog:NSObject
@property(nonatomic,assign,nullable)NSObject*assignProperty;
@property(nonatomic,weak,nullable)NSObject*weakProperty;
@property(nonatomic,copy,nullable)NSString*propertyCopy;
@property(nonatomic,strong,nullable)NSObject*strongProperty;
@end
NS_ASSUME_NONNULL_END
assign:
原因是 alloc、init 办法返回的是一个 autorelease 的 NSObject 实例,当走完 init 后如果没有人对他进行 retain 操作,则立马会被毁掉。
总结:
- 只进行简略的赋值操作(把一个指针赋值给该特点,如果是目标则是目标地址,如果是根本数据类型则是该值的地址)
- 只适用于根本数据类型(非 Objective-C 目标「语法上是支撑润饰 Objective-C 目标的」,如:int,float,NSInterge,CGFloat,及结构体类型)
- 不影响该特点所指向目标的生命周期(不改动retaincount)
- 在所指向目标毁掉时不会主动为该特点赋 nil 值
weak:
参考 assign,做个对比
总结:
- 只适用于 Objective-C 目标(语法上就不支撑润饰根本数据类型)
- 不影响该特点所指向目标的生命周期(不改动retaincount)
- 在所指向目标毁掉时会主动为该特点赋 nil 值(避免野指针拜访导致 crash)
strong:
总结:
-
只适用于 Objective-C 目标(语法上就不支撑润饰根本数据类型)
-
会强引证指向的目标(retaincount + 1)
-
会开释之前指向的目标(retaincount – 1)
-
当润饰 block 类型特点时(ARC 下表现与 copy 共同)
- 当指向的目标为 StackBlock 时会把 block 目标复制到堆区成为 MallocBlock
- 当指向的目标为 MallocBlock 时会增加引证计数(retaincount + 1)
- 当指向的目标为 GlobalBlock 时什么都不会产生
copy:
当用 copy 润饰一个 NSObject 类型的特点,运行时产生了 crash,并抛出 NSObject 未完成 copyWithZone: 办法的反常。这是由于 copy 润饰的特点会在 setter 办法内对老值进行 release,对新值进行 copy 操作,也就是它真正指向的是传入目标 copy 后的返回值(可能是深 copy 也可能是浅 copy )。这一操作避免了给不可变类型(如:NSString)特点赋值对应可变子类(如:NSMutableString)导致的逻辑反常。
另一方面当为该特点赋值后,持续修改原值时该特点的值不受影响,由于此刻现已把 NSMutableString copy 为了 NSString。
总结:
-
只适用于 Objective-C 目标(语法上就不支撑润饰根本数据类型)
-
会强引证指向的目标(retaincount + 1)
-
会开释之前指向的目标(retaincount – 1)
-
当润饰 NSString,NSArray 等存在可变类型的子类时(这是 copy 与 strong 的最大差异)
- 运用 copy 润饰,把可变类型深 copy 为不可变类型,避免不安全修改
- 不安全的原因是:可变类型的目标能够在不改动目标地址的情况下修改值,由于你的特点是 NSString 类型,此刻值被意外修改是不符合预期的。
-
当润饰 block 类型特点时
- 当指向的目标为 StackBlock 时会把block目标复制到堆区成为 MallocBlock
- 当指向的目标为 MallocBlock 时会增加引证计数(retaincount + 1)
- 当指向的目标为 GlobalBlock 时什么都不会产生
总结
今日开始复习,决议把自己的了解以文章的形式输出,一方面能加深了解做个笔记,另一方面也期望能给咱们带来点帮助。笔者水平有限,不免有了解偏差与遗失,期望咱们批评指正。