HTML5   发布时间:2022-04-27  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了ios – 为什么返回__strong和__autoreleasing变量只会在第一次产生不同的对象生命周期?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
虑一下这段代码

@implementation MyClass
-(void)dealloc {
    NSLog(@"MyClass dealloc: %@",self);
}
@end

@implementation AppDelegate

__weak static MyClass *weakShared = nil;

- (MyClass *)getMyClass {
    MyClass *tmpHolder = [[MyClass alloc] init]; // PREPEND "__autoreleasing"
    weakShared = tmpHolder;
    return weakShared; // ATTENTION TO THIS LINE
}
- (void)logMyClass:(NSUInteger)i {
    MyClass *mc = [self getMyClass];
    NSLog(@"(%@) this is MyClass: %@",@(i),mc);
}
- (void)applicationDidFinishLaunching:(Nsnotification *)aNotification {
    @autoreleasepool {
        for (int i = 0; i < 10; i++) {
            [self logMyClass:i];
        }
        NSLog(@"end");
    }
    NSLog(@"outside pool");
}

注意标有//注意此线路的线路.

我可以用3种口味替换那条线:

> return weakShared(__ weak)
> return tmpHolder(__strong)
>将带有__autoreleasing的tmpHolder返回到上面指示的tmpHolder变量.

上述每种情况的输出是:

1.

(0) this is MyClass: <MyClass: 0x600000020490>
MyClass dealloc: <MyClass: 0x600000020490>
(1) this is MyClass: <MyClass: 0x600000024270>
MyClass dealloc: <MyClass: 0x600000024270>
(2) this is MyClass: <MyClass: 0x600000024270>
MyClass dealloc: <MyClass: 0x600000024270>
end
outside pool

2.

(0) this is MyClass: <MyClass: 0x600000010570>
(1) this is MyClass: <MyClass: 0x600000010530>
MyClass dealloc: <MyClass: 0x600000010530>
(2) this is MyClass: <MyClass: 0x600000010530>
MyClass dealloc: <MyClass: 0x600000010530>
end
MyClass dealloc: <MyClass: 0x600000010570>
outside pool

3.

(0) this is MyClass: <MyClass: 0x600000020060>
(1) this is MyClass: <MyClass: 0x600000020040>
(2) this is MyClass: <MyClass: 0x600000020030>
end
MyClass dealloc: <MyClass: 0x600000020030>
MyClass dealloc: <MyClass: 0x600000020040>
MyClass dealloc: <MyClass: 0x600000020060>
outside pool

我的问题:为什么案例2的行为如此?我希望它能在返回之前自动释放我的变量,因此表现得像3;或者只是在没有自动释放的情况下返回它并且表现得像1.

注意:您将需要-Os标志来重现上述示例.

解决方法

TL; DR:

在迭代0中,由于ARC辅助函数的延迟绑定打破了返回值优化,因此将对象放入自动释放池中.其余的都会尽快释放,因为符号已被绑定.

案例2中的弱引用是红鲱鱼.删除weakShared变量后,您可以获得相同的行为.

@implementation AppDelegate
-(MyClass*)getMyClass {
    MyClass* tmpHolder = [[MyClass alloc] init];
    return tmpHolder;
}
...

应用ARC后的Objective-C代码如下所示:

@H_699_7@myClass* "-[AppDelegate getMyClass]"(AppDelegate* self,SEL _cmd) { MyClass* tmpHolder = [[MyClass alloc] init]; return objc_autoreleaseReturnValue(tmpHolder); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ }

与ARC -autorelease之前的方法不同,objc_autoreleaseReturnValue() function不会将对象直接移动到自动释放池中.它将检查调用者的汇编指令,如果调用者将立即“ – 保持”该值,我们将跳过自动释放池并直接返回1’ed对象.

void "-[AppDelegate logMyClass:]"(AppDelegate* self,SEL _cmd,NSUInteger i) {
    MyClass* mc = objc_retainAutoreleasedReturnValue([self getMyClass]);
//                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                 
    NSnumber* ii = objc_retainAutoreleasedReturnValue([NSnumber numberWithInt:i]);
    NSLog(@"(%@) this is MyClass: %@",ii,mc);
    objc_release(ii);
    objc_release(mc);
}

由于这种行为,在迭代1到9中,objc_autoreleaseReturnValue和objc_retainAutoreleasedReturnValue方法变为no-op,并且在-logMyClass:的末尾立即销毁那些MyClass实例.

(还有关于此返回优化如何在How does objc_retainAutoreleasedReturnValue work? by Matt Galloway上工作的详细说明.)

但是在迭代0发生了什么?

我们可以阅读implementation of callerAcceptsOptimizedReturn,它描述了objc_autoreleaseReturnValue如何确定调用者将“立即保留”.简而言之,它将确保呼叫者在通话后立即获得以下指示:

48 89 c7            movq %rax,%rdi
e8 __ __ __ __      callq <something>

解除引用< something>应该指出

ff 25 __ __ __ __   jmpq *<symbol>

其中< symbol>应该是objc_retainAutoreleasedReturnValue的函数指针.但是,如果您在调试器中运行该程序并跟踪objc_autoreleaseReturnValue,您将发现< symbol>在第一次通话时不是objc_retainAutoreleasedReturnValue!

原因是objc_retainAutoreleasedReturnValue是一个惰性符号(__DATA,__ la_symbol_ptr).链接到外部动态库时,这是the default behavior.在通过< symbol>进行调用之前,dynamic linker不会将其解析为正确的函数指针.

实际上,如果通过添加-bind_at_load linker flag来禁用延迟绑定行为,则代码将与“case 1”的行为相同

$clang -fobjc-arc -framework Foundation -bind_at_load -Og 1.m
$./a.out 
2018-05-30 19:25:58.838 a.out[4923:19498647] (0) this is MyClass: <MyClass: 0x7fa392400200>
2018-05-30 19:25:58.838 a.out[4923:19498647] MyClass dealloc: <MyClass: 0x7fa392400200>
2018-05-30 19:25:58.838 a.out[4923:19498647] (1) this is MyClass: <MyClass: 0x7fa392400200>
2018-05-30 19:25:58.838 a.out[4923:19498647] MyClass dealloc: <MyClass: 0x7fa392400200>
...
2018-05-30 19:25:58.839 a.out[4923:19498647] (9) this is MyClass: <MyClass: 0x7fa392600400>
2018-05-30 19:25:58.839 a.out[4923:19498647] MyClass dealloc: <MyClass: 0x7fa392600400>
2018-05-30 19:25:58.839 a.out[4923:19498647] end
2018-05-30 19:25:58.839 a.out[4923:19498647] outside pool
$

由于此问题仅在整个程序生命周期中发生一次,这可能是行为保持不变的原因.

LLDB脚本显示延迟加载行为:

@H_874_95@

大佬总结

以上是大佬教程为你收集整理的ios – 为什么返回__strong和__autoreleasing变量只会在第一次产生不同的对象生命周期?全部内容,希望文章能够帮你解决ios – 为什么返回__strong和__autoreleasing变量只会在第一次产生不同的对象生命周期?所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。