当前位置: 首页 > news >正文

iOS——【自动引用计数】ARC规则及实现

1.3.3所有权修饰符

所有权修饰符一共有四种:

  1. __strong 修饰符
  2. __weak 修饰符
  3. __undafe_unretained 修饰符
  4. __autoreleasing 修饰符
__strong修饰符

_strong修饰符表示对对象的强引用,持有强引用的变量在超出其作用域的时候会被废弃,随着强引用的失效,引用的对象会随之释放。 _strong是id和对象类型默认的所有权修饰符。比如id obj = …和id _ _strong obj作用相同。
有__strong修饰符修饰的变量在超出其作用域的时候,相当于会自动执行[obj release],即会释放其被赋予的对象。
附有__strong修饰符的变量之间可以相互赋值:

//obj0持有对象A的强引用
id __strong obj0 = [[NSObject alloc] init];
//obj1持有对象B的强引用
id __strong obj1 = [[NSObject alloc] init];
//obj2不持有对象
id __strong obj2 = nil;//obj0持有由obj1赋值的对象B的强引用,同时因为obj0被赋值,所以原先持有的对对象A的强引用失效。对象A的所有者不存在,因此废弃对象A。
//此时,持有对象B的强引用的变量为obj0和obj1
obj0 = obj1;
//obj2持有由obj0赋值的对象B的强引用,此时持有对象B的强引用的变量为obj0,obj1和obj2
obj2 = obj0;
//obj1被赋值为nil,所以对对象B的强引用失效。此时持有对象B的强引用的变量为obj0和obj2
obj1 = nil; 
//obj0被赋值为nil,所以对对象B的强引用失效。此时持有对象B的强引用的变量为obj2
obj0 = nil;
//obj2被赋值为nil,所以对对象B的强引用失效。此时持有对象B的强引用的所有者不存在,因此废弃对象B。
obj2 = nil;

由此可见__ strong 修饰符的变量,不仅只在变量作用域中,在赋值上也能够正确地管理其对象的所有者。
类成员变量,也可以在方法参数上,使用附有__strong修饰符的变量:

@interface Test : NSObject {id strong obj_;
}
- (void) setObject: (id __strong)obj;
@end
@implementation Test 
- (id)init {self = [super init]; return self;
}- (void)setObject: (id __strong) obj {obj_ = obj;
}
@end

使用该类:

{id __strong test = [[Test alloc] init];// test持有Test 对象的强引用[test setObject: [[NSObject alloc] init]];  //Test对象的obj_成员,持有NsObject 对象的强引用。
}//因为test 变量超出其作用域,强引1用失效,所以自动释放Test 对象。Test对象的所有者不存在,因此废弃该对象。废弃Test对象的同时,Test对象的obj_成员也被度弃,NSObject对象的强引用失效,自动释放NSObject 对象。NSObject对象的所有者不存在,因此废弃该对象

_ strong、 weak、 _sutoreleasing可以保证将附有这些修饰符的自动变量初始化为nil
如id _ _strong obj; 与 id _ _strong obj = nil;相同,其他几个同理。

使用_ _strong修饰符可以不必再次键入retain或者release,完美的满足了“引用计数式内存管理的思考方式”。

  • 自己生成的对象,自己所持有;
  • 非自己生成的对象,自己也能持有;。
  • 不再需要自己持有的对象时释放;
  • 非自己持有的对象无法释放;
__weak修饰符

__weak修饰符可以解决引用计数式内存管理中必然会发生的“循环引用” 的问题。循环引用可以简单理解为A引用了B,而B又引用了A,双方都同时保持对方的一个引用,导致任何时候引用计数都不为0,始终无法释放。

{id test0 = [[Test alloc] init];//test0持有Test对象A的强引用id test1 = [[Test alloc] init]; //test1持有rest对象B的强引用[test0 setObject:test1];//Test对象A的obj_成员变量持有Test对象B的强引用。此时,持有Test 对象B的强引用的变量为Test对象A的obj_和test1。[test1 setObject:test0];//Test对象B的obj_成员变量持有Test对象A的强引用。此时,持有Test 对象A的强引用的变量为Test对象B的obj_和test0。
}//因为test0变量超出其作用域,强引用失效,所以自动释放Test对象A//因为test1变量超出其作用域,强引用失效,所以自动释放Test对象B//此时,持有Test对象A的强引用的变量为Test对象B的obj_//此时,持有Test对象B的强引用的变量为Test对象A的obj_//发生内存泄漏

所谓内存泄露就是应当废弃的对象在超出其生存周期后继续存在。
还有一种情况是虽然只有一个对象,但是改对象持有自身的时候也会发生循环引用(自引用)。

id test = [[Test alloc] init];
[test setObject: test];

为什么说_ weak可以避免循环引用呢,因为 _weak修饰符可以提供弱引用。弱引用不能持有对象实例。
对象的持有状况:

{id __strong obj0 = [(NSObject alloc] init]; //自己生成并持有对象 //因为obj0变量为强引用,所以自己持有对象。id __weak obj1 = obi0;//obj1变量持有生成对象的弱引用 
}
//因为obj0变量超出其作用域,强引用失效,所以自动释放自己持有的对象。 因为对象的所有者不存在,所以度弃该对象。

因为带 __weak 修饰符的变量(即弱引用)不持有对象,所以在超出其变量作用域时,对象 即被释放。
__weak 修饰符还有另一优点。在持有某对象的弱引用时,若该对象被废弃,则此弱引用将自动失效且处于nil 被赋值的状态(空弱应用)。

id __weak obj1 = nil;
{id __strong obj0 = [[NSObject alloc] init];obj1 = obj0;NSLog(@%@, obj1);
}
NSLog(@%@, obj1);

得到的结果是第一个被打印出来的obj1存在,第二个为nil;
像这样,使用_ weak 修饰符可避免循环引用。通过检查附有 _weak 修饰符的变量是否为 nil ,可以判断被赋值的对象是否己废弃。

__unsafe_unretained 修饰符

_ unsafe_unretained 修饰符是不安全的所有权修饰符。尽管ARC式 的内存管理是编译器的工作,但附有 unsafe_unretained修饰符的变量不属于编译器的内存管理对象。
附有
unsafe_unretained 修饰符的变量同附有。 weak 修饰符的变量 一样,因为自己生成并持有的对象不能继续为自己所有,所以生成的对象会立即被释放。
但是它与
_weak不同的是:还是用上面那个例子:

id __weak obj1 = nil;
{id __strong obj0 = [[NSObject alloc] init];obj1 = obj0;NSLog(@%@, obj1);
}
NSLog(@%@, obj1);

这时打印出来的两个obj1都存在。
其实最后一个NSLog只是碰巧正常运行,但是它访问的是已经被废弃的对象。这是错误的访问。
因此在使用_ unsafe_unretained 修饰符时,赋值给附有 _strong 修饰符的变量时有必要确保被赋值的对象确实存在。

_ _autoreleasing 修饰符

虽然autorelease 无法直接使用,但实际上,ARC有效时autorelease 功能是起作用的。
ARC无效的时候,我们可以用[obj autorelease];
ARC有效的时候,可以这样用:id _ autoreleasing obj = [[NSObject alloc] init];
另外,ARC 有效时,要通过将对象赋值给附加了
autoreleasing 修饰符的变量来替代调用 autorelease 方法。对象赋值给附有 _autoreleasing修饰符的变量等价于在ARC无效时调用对象,即对象被注册到autoreleasepool。
可以理解为:在ARC 有效时,用@autoreleasepool块替代NSAutoreleasePool 类,autorcleasing修饰符的变量替代autorelease 方法。
在这里插入图片描述

NSAutoreleasePool:
官方释义:NSAutoreleasePool 是 Cocoa 用来支持引用计数内存管理机制的类, 当一个autorelease pool(自动释放池)被drain(销毁)的时候会对pool里的对象发送一条release的消息.
简单来说NSAutoreleasePool是一个对象池,它管理着在池内的对象的引用计数以及何时销毁问题。NSAutoreleasePool 是在 MRC时代使用的。

但是显式地附加_ autoreleasing修饰符很少用,非显式地附加 autoreleasing修饰符也是可以的,就像 _strong一样:


@autoreleasepool {
//取得非自己生成并持有的对象id __strong obj = [NSMutableArray array]:
}
//因为变量obj为强引用,所以自己持有对象。并且该对象由编译器判断其方法名后自动注册到autoreleasepoo1,因为变量obj超出其作用域,强引用失效,所以自动释放自己持有的对象。同时,随着@autoreleasepoo1块的结束,注册到autoreleasepoo1中的所有对象被自动释放。因为对象的所有者不存在,所以废奔对象。

取得非自己生成并持有对象时被调用方法的源代码:

+ (id) array {return [[NSMutableArray alloc] init];
}

没有使用_ _autoreleasing修饰符,可写成以下形式:

{id obj = [[NSMutableArray alloc] init];return obj;
}

由于return使得对象变量超出其作用域,所以该强引用对应的自己持有的对象会被自
动释放,但该对象作为函数的返回值,编译器会自动将其注册到autoreleasepool。

在访问附有 weak修饰符的变量时,实际上必定要访问注册到autoreleasepool 的对象。

id __weak obj1 = obj0;
NSLog (@"class=8@", [obj1 class]);

以下源代码与此相同。

id __weak obj1 = obj0;
id __autoreleasing tmp = obj1; 
NSLog(@"class=%@", [tmp class]);

为什么在访问附有_ weak 修饰符的变量时必须访问注册到autoreleasepool 的对象呢?这是因为 weak 修饰符只持有对象的弱引用,而在访问引用对象的过程中,该对象有可能被废弃。 如果把要访问的对象注册到autoreleasepool 中,那么在@autoreleasepool 块结束之前都能确保该对象存在。因此,在使用附有 _weak 修饰符的变量时就必定要使用注册到autoreleasepool 中的对象。
可以由id _ _strong obj 的例子类推出id _ _strong *obj 吗?其实,推出来的是id _ autoreleasing *obj。同样地,对象的指针NSObject **obj 便成为 了NSObject * autoreleasing *obj.
像这样,id 的指针或对象的指针在没有显式指定时会被附加上
_autoreleasing 修饰符。 如NSString 的stringWithContentsorFile:encoding:error 类方法:

- (BOOL) performOperationWithError: (NSError **)error;

id的指针或对象的指针会默认附加上,autoreleasing修饰符 ,所以等同于以下源代 码 :

- (BOOL) performoperationWithError:(NSError *__autoreleasing *)error;

使用附有_ _autoreleasing 修饰符的变量作为对象取得参数,与除alloc/new/copy/mutableCopy 外其他方法的返回值取得对象完全一样,都会注册到 autoreleasepool, 并取得非自己生成并持有的对象。

赋值给对象指针时,所有权修饰符必须一致:

NSError *error = nil;
NSError __strong *pError = &error;

但是前面的方法参数中使用 了附有_ _autoreleasing 修饰符的对象指针类型。然而调用方却使用了附有strong修饰符的对象指针类 型。但为什么该源代码没有警告就顺利通过编译了呢?

- (BOOL) performoperationWithError:(NSError *__autoreleasing *)error;
{NSError strong *error = nil;BOOL result = [obj performoperationWithError:&error]:
}

实际上,编译器自动地将该源代码转化成 了下面形式:

NSError __strong *error = nil; 
NSError __autoreleasing *tmp = error;
BOOL result = [obj performOperationWithError:&tmp]; 
error = tmp;

只有 作为alloc/new/copy/mutableCopy 方法的返回值而取得对象时,能够自己生成并持有对象。其他 情况即为“取得非自己生成并持有的对象”

** 另外,虽然可以非显式地指定_ autoreleasing修饰符,但在显式地指定 _autoreleasing修饰符时,必须注意对象变量要为自动变量 (包括局部变量、函数以及方法参数)。**

详细了解@autoreleasepool

如以下源代码所示,ARC无效时,可 将NSAutoreleasePool 对象嵌套使用。

//ARC无效
NSAutoreleasePool *pool0 = [[NSAutoreleasePool alloc] init];NSAutoreleasePool *pool1 = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];id obj = [[NSObject alloc] init]; [obj autorelease];[pool2 drain]; [pooll drain];
[pool0 drain];

同样地,@autoreleasepool 块也能够嵌套使用。

@autoreleasepool {@autoreleasepool {@autoreleasepool {id __autoreleasing obj = [[NSObject alloc] init];}}
}

比如在iOS应用程序模版中,main函数中一开始总是有一个@autoreleasepool块,它包含了全部程序。
NSRunLoop 等实现不论ARC 有效还是无效,均能够随时释放注册到autoreleasepool 中的对象。

因为autoreleasepool 范围以块级源代码表示,提高了程序的可读性,所以今后在ARC 无效时也推荐使用@autoreleasepool 块。 另外,无论ARC是否有效,调试用的非公开函数_objc_autoreleasePoolPrint() 都可使用。这 一函数可有效地帮助我们调试注册到autoreleascpool 上的对象。

1.3.4规则

在ARC 有效的情况下编译源代码,必须遵守一定的规则:

  • 不能使用retain/release/retainCount/autorelease
  • 不能使用NSAllocateObject/NSDeallocateObject
  • 须遵守内存管理的方法命名规则
  • 不要显式调用dealloc
  • 使用@autoreleasepool 块替代NSAutoreleasePool
  • 不能使用区域(NSZone)
  • 对象型变量不能作为C 语言结构体 (struct/union)的成员
  • 显式转换 “id” 和 “void *”
不能使用retain/release/retainCount/autorelease

内存管理是编译器的工作,因此没有必要使用内存管理的方法 (retain/release/retainCount/autorelease )。苹果官方说明:
〝设置ARC 有效时,无需再次键入retain 或release 代码。”
一旦使用就会报错。

不能使用NSAllocateObject/NSDeallocateObject

在ARC 有效时,禁止使用NSAllocat eObject 函数。同retain 等方法 一样,如果使用便会引 起编译错误。同样地,也禁止使用用于释放对象的NSDeallocateObject 函数。

须遵守内存管理的方法命名规则

alloc/new/copy/mutableCopy 名称开始的方法在返回对象时,必须返回给调用方所应当持有的对象。以init 开始的方法的规则要比alloc/new/copy/mutableCopy更严格。该方法必须是实例方法, 并且必须要返回对象。返回的对象应为id 类型或该方法声明类的对象类型,抑或是该类的超类型或子类型。该返回对象并不注册到autoreleasepool 上。基本上只是对alloc 方法返回值的对象 进行初始化处理并返回该对象。

不要显式调用dealloc

ARC 有效时会遊循无法显式调用dealloc 这 一规则,如果使用就会同release 等方法 一样,引 起编译错误。

使用@autoreleasepool 块替代NSAutoreleasePool

NSAutoreleasePool 类不可使用时便会引起编译器报错。

不能使用区域(NSZone)

不管ARC 是否有效,区域在现在的运行时系统中己单纯地被忽略。

对象型变量不能作为C 语言结构体 (struct/union)的成员

C语言的结构体(struct或union )成员中 ,如果存在OC 对象型变量,便会引起编译错误 。
要把对象型变量加入到结构体成员中时,可强制转换为void *或是附加前 面所述的unsafe_unretained修饰符。

显式转换 “id” 和 “void *”

在ARC 无效时,像以下代码这样将id 变量强制转换void * 变量并不会出问题:

id obj = [[NSObject alloc] init];
void *p = obj;
id o = p;
[o release];

但是在ARC有效时这便会引起编译器错误。
id 型或对象型变量赋值给void * 或者逆向赋值时都需要进行特定的转换。如果只想单纯地赋值,则可以使用 “_ _bridge 转换”。

id obj = [[NSObject alloc] init]; 
void *p = (__bridge void *)obj;
id o = (__bridge id)p;

但是转换为void *的_ _bridge转换,其安全性与赋值给,unsafe_unretained修饰符相近,甚至会更低。如果管理时不注意赋值对象的所有者,就会因悬垂指针而导致程序崩溃。
_ _bridge_retained 转换可使要转换赋值的变量也持有所赋值的对象。
_ bridge_transfer 转换提供与此相反的动作,被转换的变量所持有的对象在该变量被赋值给转换目标变量后随之释放。
bridge retained转换与retain类似, bridge_transfer 转换与release相似。在给id obj 赋值时retain 即相当于 _strong 修饰符的变量。
如果使用以上两种转换,那么不使用id 型或对象型变量也可以生成、持有以及释放对象。 虽然可以这样做,但在ARC 中并不推荐这种方法。

以下函数可用于Objective-C对象与CoreFoundation 对象之间的相互变换,即Toll-Free Bridge 转換。

CFTypeRef CFBridgingRetain(id X) {return (__bridgeretained CFTypeRef)X;
}
id CFBridgingRelease(CFTypeRef X) {return (__bridgetransfer id)X;
} 

1.3.5属性

当ARC有效时,以下可作为这种属性声明中使用的属性来用。
在这里插入图片描述

以上各种属性赋值给指定的属性中就相当于赋值给附加各属性对应的所有权修饰符的 变量中。只有copy 属性不是简单的赋值,它赋值的是通过NSCopying 接口的copyWithZone: 方法复制赋值源所生成的对象。
在声明类成员变量时,如果同属性声明中的属性不一致则会引起编译错误。如:

id obj;

在声明id 型obj 成员变量时,像下面这样,定义其属性声明为weak。

@property (nonatomic, weak) id obj;

编译器会报错。此时,成员变量的声明中需要附加 _weak 修饰符。(或者使用strong属性)

id __weak obj;

1.3.6数组

静态数组也可以使用_ _strong, _ weak 修饰符, autoreleasing 修饰符以及 _unsafe unretained 修饰符。
例:id _ weak objs [10];
附有
strong/ weak/ autoreleasing 修饰符变量的数组保证其初始化为nil。
数组超出其变量作用域时,数组中各个附有
strong 修饰符的变量也随之失效,其强引用消失,所赋值的对象也随之释放。这与不使用数组的情形完全一样。
将附有
_strong 修饰符的变量作为动态数组来使用时 又如何呢?在这种情况 下,根据不同的 目的选择使用NSMutableArray、NSMutableDictionary、NSMutableSet 等Foundation 框架的容器。 这些容器会恰当地持有追加的对象并为我们管理这些对象。
声明动态数组用指针:

id __strong *array = nil;

由于“ id *类型” 默认为“id _ _autoreleasing * 类型”,所以有必要显式指定为 _ _strong 修饰符.

动态数组在分配内存时推荐使用calloc 函数。
像这样,通过calloc函数分配的动态数组就能完全像静态数组 一样使用。

array[0] = [[NSObject alloc] init]:

但是,在动态数组中操作附有_ _strong修饰符的变量与静态数组有很大差异,需要自己释放所有的元素。 如以下源代码所示 ,一定要将 nil 赋值给所有元素中,使得元素所赋值对象的强引用失效,从而释放那些对象。在此之后,使 用free 函数废弃内存块。

for (NSUInteger i = 0; i < entries; ++i) array[i] = nil;
free (array);

使用memset 等函数将内存填充为0也不会释放所赋值的对象。这非常危险,只会引起内存泄漏。另外,使用memcpy 两数拷贝数组元素以及realloc 两数重新分配内存块也会有危险。由于 数组元素所赋值的对象有可能被保留在内存中或是重复被废弃,所以这两个函数也禁止使用。

ARC的实现

ARC 是“由编译器进行内存管理〞的,但实际上只有编译器是无法完全胜任的,在此基础上还需要Objective-C 运行时库的协助:

  • clang(LLVM编译器)3.0以上
  • Objecttive-C运行时库493.9以上

_ _strong修饰符

附有_ _strong 修饰符的变量在实际的程序如何运行:

id __strong obj = [[NSObject alloc] init];

其模拟源代码:

//编译器的模拟代码 
id obj = objc_msgSend(NSObject, @selector(alloc)); objc_msgSend(obj, @selector(init));
objc_release(obj);

2次调用objc_msgSend 方法(alloc 方法和init 方法),变量作用域结束时通过objc_release释放对象。虽然ARC 有效时不能使用release 方法,但由此可知编译器自动插 入了release。
使用alloc/new/copy/mutableCopy 以外的方法:

id __strong obj = [NSMutableArray array];
//编译器的模拟代码
id obj = objc_msgSend(NSMutableArray, @selector(array)); 
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);

objc_retainAutoreleasedReturValue函数主要用于最优化程序运行。顾名思义,它是用于自己持有(retain)对象的函数,但它持有的对象应为返回注册在autoreleasepool 中对象的方法,或是函数的返回值。
objc_autoreleaseReturnValue。它用于alloc/new/copy/mutableCopy方法以外的NSMutableArray 类的 array 类方法等返回对象的实现上。
它这样转换:

+ (id) array {return [[NSMutableArray alloc] init];
}
//模拟代码
+ (id) array {id obj = objc_msgSend(NSMutableArray, @selector(alloc));objc_msgSend(obj, @selector(init)); return objc_autoreleaseReturnValue(obj);
}

objc_autoreleaseReturnValue 函数同objc_autorelease函数不同,一般不仅限于注册对象到autorelcasepool 中。
objc_autoreleaseReturnValue 函数会检查使用该函数的方法或函数调用方的执行命令列表,如果方法或函数的调用方在调用了方法或函数后紧接着调用objc_retainAutoreleasedReturnValue( ) 函数,那么就不将返回的对象注册到autoreleasepool 中,而是直接传递到方法或函数的调用方。 objc_retainAutoreleasedReturnValue 两数与objc_retain 两数不同,它即便不注册到autoreleasepool 中而返回对象,也能够正确地获取对象。通过objc_autoreleaseReturnValue 函数和obijc_retainAutoreleasedReturnValue 函数的协作,可以不将对象注册到autoreleasepool 中而直接传递。
在这里插入图片描述

1.4.2 __weak修饰符

功能:

  1. 若附有_ _weak 修饰符的变量所引用的对象被皮弃,则将nil 赋值给该变量。
  2. 使用附有_ _weak 修饰符的变量,即是使用注册到autoreleasepool 中的对象。
    _ _weak的实现:
id __weak obj1 = obj;

假设obj是_ _strong修饰的。

//编译器的模拟代码
id obj1;
objc_initWeak(&obj1, obj); 
objc_destroyWeak(&obj1) ;

通过objc_initWeak两数初始化附有_ _weak修饰符的变量,在变量作用域结束时通过objc_destroyWeak 函数释放该变量。

weak表与引用计数表相同,作为散列表被实现。如果使用weak 表,将废弃对象的地址作为键值进行检索,就能高速地获取对应的附有_ weak 修饰符的变量的地址。另 外,由于一个对象可同时赋值给多个附有 _weak 修饰符的变量中,所以对于一个键值,可注册多个变量的地址。
释放对象时,废弃谁都不持有的对象的同时,程序的动作:
(1) objc_release
(2)因为引用计数为0 所以执行dealloc
(3) _objc_rootDealloc
(4) object_dispose
(5) objc_destructInstance
(6) objc_clear_deallocating

对象被废弃时最后调用的obje_clear_deallocating 两数的动作如下:
(1 ) 从weak表中获取废弃对象的地址为键值的记录。
(2)将包含在记录中的所有附有_ _weak修饰符变量的地址,赋值为nil。
(3 ) 从 w e a k 表 中 删 除 该 记 录 。
(4 )从引用计数表中州除废弃对象的地址为键值的记录。

使用 _ _weak修饰符时 ,以下源代码会引起编译器警告

id __weak obj = [[NSObject alloc] init];

编译器如何处理该源代码呢?

//编译器的模拟代码
id obj;
id tmp = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(tmp, @selector(init));
objc_initWeak(&obj, tmp);
objc_release(tmp);
objc_destroyWeak(&object);

虽然自己生成并持有的对象通过objc_initWcak 函数被赋值给附有。_ _weak 修饰符的变量中, 但编译器判断其没有持有者,故该对象立即通过objc_release 函数被释放和废弃。

使用附有_ _weak 修饰符的变量, 即是使用注册到autoreleasepool 中的对象。

{id __weak obj1 = obj; NSLog(@"%@", obj1);
}

该 源 代 码 可 转 换 为如 下形 式:

// 编译器的模拟代码
id obi1;
objc_initWeak(&obj1, obj);
id tmp = objc_loadWeakRetained(&obj1);
objc_autorelease(tmp);
NSLog(@%@, tmp);
objc_destroyWeak(&obj1);

与被赋值时相比,在使用附有_ _weak 修饰符变量的情形下,增加了对obje loadWeakRetained 函 数 和 objc_autorelease函 数 的 调 用。这些函数的动作如下:
(1) objc_loadWeakRetained函数取出附有_weak 修饰符变量所引用的对象并retain。 (2) objc_autorelease 函数将对象注册到autoreleasepool 中。

在使用附有_ weak 修饰符的变量时,最好先暂时赋值给附有 _strong修饰符的变量后再使用。

1.4.3 __autoreleasing 修饰符

将对象赋值给附有 autoreleasing 修饰符的变量等同于ARC 无效时调用对象的autorelease 方法。

@autoreleasepool {id __autoreleasing obj = [[NSObject alloc] init];
}
//编译器的模拟代码 
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init)); 
objc_autorelease(obj); 
objc_autoreleasePoolPop(pool);

NSMutableArray 类的array 类方法:

@autoreleasepool {
id __autoreleasing obj = [NSMutableArray array];
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj); 
obic_autorelease(obj);
objc_autoreleasePoolPop(pool);

虽然持有对象的方法从alloe 方法变为objc_retainAutoreleasedRcturnValue 函数,但注册 autoreleasepool 的方法没有改变,仍是obje_autorelease 函数。

相关文章:

iOS——【自动引用计数】ARC规则及实现

1.3.3所有权修饰符 所有权修饰符一共有四种&#xff1a; __strong 修饰符__weak 修饰符__undafe_unretained 修饰符__autoreleasing 修饰符 __strong修饰符 _strong修饰符表示对对象的强引用&#xff0c;持有强引用的变量在超出其作用域的时候会被废弃&#xff0c;随着强引…...

智慧城市的前景:数字孪生技术在智慧城市中的应用前景

目录 一、引言 二、数字孪生技术及其在智慧城市中的应用概述 三、数字孪生技术在智慧城市中的应用前景 1、城市规划与仿真模拟 2、智能交通与出行服务 3、智慧环保与可持续发展 4、智慧公共服务与社会治理 5、智慧能源与绿色建筑 四、数字孪生技术在智慧城市中的挑战与…...

Everything:文件查找工具,一搜即得

名人说&#xff1a;东边日出西边雨&#xff0c;道是无晴却有晴。——刘禹锡 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、软件介绍①Everything②核心功能③原理 二、下载安装①下载②安装 三、使用方法①文…...

【数据结构:树与堆】向上/下调整算法和复杂度的分析、堆排序以及topk问题

文章目录 1.树的概念1.1树的相关概念1.2树的表示 2.二叉树2.1概念2.2特殊二叉树2.3二叉树的存储 3.堆3.1堆的插入&#xff08;向上调整&#xff09;3.2堆的删除&#xff08;向下调整&#xff09;3.3堆的创建3.3.1使用向上调整3.3.2使用向下调整3.3.3两种建堆方式的比较 3.4堆排…...

vue3+element-plus el-input 自动获取焦点

虽然element有提供input的autofocus属性&#xff0c;但是当我们第二次进入页面就会发现autofocus已经不再生效&#xff0c;需要通过onMounted去触发input的focus解决这个问题。 1.先给el-input绑定一个ref&#xff1a;<el-input ref"inputRef" v-model"inp…...

简单了解TCP/IP四层模型

什么是计算机网络&#xff1f; 计算机网络我们可以理解为一个巨大的城市地图&#xff0c;我们想从A地前往B地&#xff0c;其中要走的路、要避开的问题都交给计算机网络解决&#xff0c;直到我们可以正常的到达目的地&#xff0c;那么我们会把其中的过程抽象成一个网络模型&…...

大模型时代下的自动驾驶研发测试工具链-SimCycle

前言&#xff1a; 最近OpenAI公司的新产品Sora的发布&#xff0c;正式掀起了AI在视频创作相关行业的革新浪潮&#xff0c;AI不再仅限于文本、语音和图像&#xff0c;而直接可以完成视频的生成&#xff0c;这是AI发展历程中的又一座重要的里程碑。AI正在不断席卷着过去与我们息…...

人工智能迷惑行为大赏

近年来&#xff0c;随着人工智能技术的不断发展和应用&#xff0c;我们在日常生活中越来越多地接触到各种智能设备和程序。然而&#xff0c;随之而来的是一些令人瞠目结舌的人工智能迷惑行为&#xff0c;让人们对这一新兴技术产生了更多的好奇和思考。 在人工智能迷惑行为大赏…...

ZJUBCA研报分享 | 《BTC/USDT周内效应研究》

ZJUBCA研报分享 引言 2023 年 11 月 — 2024 年初&#xff0c;浙大链协顺利举办为期 6 周的浙大链协加密创投训练营 &#xff08;ZJUBCA Community Crypto VC Course&#xff09;。在本次训练营中&#xff0c;我们组织了投研比赛&#xff0c;鼓励学员分析感兴趣的 Web3 前沿话题…...

SSM整合项目(使用Vue3 + Element-Plus创建项目基础页面)

1.配置Vue启动端口 1.修改vue.config.js const {defineConfig} require(vue/cli-service) module.exports defineConfig({transpileDependencies: true }) module.exports {devServer: {port: 9999 //启动端口} }2.启动 2.安装Element Plus 命令行输入 npm install eleme…...

css相邻元素边框重合问题,解决方案

1、如下图所示&#xff0c;在给元素设置边框后&#xff0c;相邻元素会出现重合的问题 2、解决方案 给每个元素设置margin-top以及margin-left为负的边框 <div style"width: 300px;display: flex;flex-wrap: wrap;margin-top: 50px;"><div style"border…...

CentOS7 利用remi yum源安装php8.1

目录 前言remi yum源remi yum源 支持的操作系统remi yum源 支持的php版本 安装epel源安装remi源安装 php8.1查看php版本查看php-fpm服务启动php-fpm服务查看php-fpm服务运行状态查看php-fpm服务占用的端口查看 php8.1 相关的应用 前言 CentOS Linux release 7.9.2009 (Core) …...

深入探索Java设计模式:责任链模式解析与实践

目录 一、责任链模式的基础知识1. 模式结构2. 模式示例 二、责任链模式的实际应用1. 请求处理链2. 日志记录器 三、责任链模式的重要性和使用场景结语 欢迎阅读本篇博客&#xff0c;我们将深入探讨Java设计模式中的责任链模式&#xff0c;帮助初学者、初中级程序员和在校大学生…...

如何在项目中应用“API签名认证”

❤ 作者主页&#xff1a;李奕赫揍小邰的博客 ❀ 个人介绍&#xff1a;大家好&#xff0c;我是李奕赫&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 记得点赞、收藏、评论⭐️⭐️⭐️ &#x1f4e3; 认真学习!!!&#x1f389;&#x1f389; 文章目录 为什么需要AP…...

【AIGC+VisionPro】空间视频生意的创业者

1. 产品概述 -一款基于人工智能的2D到3D视频/图像转换工具,可将普通的2D视频/图像转换为令人惊艳的3D视觉体验。 - 它支持在PC上进行转换,并输出适用于Meta Quest、Apple Vision Pro等XR设备的3D格式。 2. 产品功能 - 利用尖端的3D AI系统,可将任何视频(Youtube、电影、游戏、…...

word转PDF的方法 简介快速

在现代办公环境中&#xff0c;文档格式转换已成为一项常见且重要的任务。其中&#xff0c;将Word文档转换为PDF格式的需求尤为突出&#xff0c;将Word文档转换为PDF格式具有多方面的优势和应用场景。无论是为了提高文档的可读性和稳定性、保障文档的安全性和保护机制、还是为了…...

【开源】SpringBoot框架开发图书管理系统

目录 一、 系统介绍二、 功能模块2.1 登录注册模块2.1 图书馆模块2.2 图书类型模块2.3 图书模块2.4 图书借阅模块2.5 公告模块 三、 源码解析3.1 图书馆模块设计3.2 图书类型模块设计3.3 图书模块设计3.4 图书借阅模块设计3.5 公告模块设计 四、 免责说明 一、 系统介绍 图书管…...

Java 继承与多态

一、继承 在Java中&#xff0c;继承是一种重要的面向对象编程概念&#xff0c;它允许一个类&#xff08;称为子类或派生类&#xff09;继承另一个类&#xff08;称为父类或基类&#xff09;的属性和方法。这意味着子类可以使用父类的成员变量和方法&#xff0c;并且可以添加自…...

C语言——递归题

对于递归问题&#xff0c;我们一定要想清楚递归的结束条件&#xff0c;每个递归的结束条件&#xff0c;就是思考这个问题的起始点。 题目1&#xff1a; 思路&#xff1a;当k1时&#xff0c;任何数的1次方都是原数&#xff0c;此时返回n&#xff0c;这就是递归的结束条件&#…...

构建空间场景轻应用,Mapmost Alpha来啦【文末赠书(10本)--第一期】

文章目录&#xff1a; 一、Mapmost Alpha 介绍二、Mapmost Alpha应对数字孪生业务痛点解决之道2.1 Mapmost Alpha 提供海量城市底板2.2 Mapmost Alpha 提供便捷的配置管理工具2.3 Mapmost Alpha 提供一键式部署发布和分享 三、沉浸式体验Mapmost Alpha3.1 创建应用3.2 新手指导…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解&#xff0c;现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&&#xff1a;逻辑与 ||&#xff1a;逻辑或 &#xff01;&#xff1a;逻辑非 短路求值 位运算符 按位与&&#xff1a; 按位或 | 按位取反~ …...