问题:
我有一个指向已释放对象的__unsafe_unretained id
指针。到目前为止一切都那么好,只要我根本不“使用”指针(特别是我不通过指针调用任何方法)。但是,当我尝试从方法返回其值时,即使我已明确指定返回值的类型为__unsafe_unretained id
,它也会崩溃。这是为什么?我想如果我使用__unsafe_unretained
,它根本不会调用像retain
/ release
/ autorelease
这样的方法吗?我以为我可以使用__unsafe_unretained id
,好像它是void*
(意味着它只做简单的原生作业)?
环境:
Xcode 4.4.1
iOS SDK 5.1
ARC
是enabled
iPhone 4.3 / 5.0 / 5.1 Simulator
或iPhone 4.3 Device
Debug
和Release
版本源代码:
// Declare my class with 1 member.
@interface MyClass : NSObject
{
__unsafe_unretained id m_MyMember;
}
@end
// **************************************************************************************************** //
// Implement my class.
@implementation MyClass
// Setter
-(void)SetMember:(__unsafe_unretained id)member
{
m_MyMember = member;
}
// Getter: by passing parameter by reference
-(void)GetMember1:(__unsafe_unretained id*)member
{
*member = m_MyMember; // No problem.
}
// Getter: by return value
-(__unsafe_unretained id)GetMember2
{
return m_MyMember; // Crashed in here!
}
@end
// **************************************************************************************************** //
//! Application entry point.
int main(int argc, char *argv[])
{
@autoreleasepool
{
{
// Create an object that dies immediately. deadObj is a dangling pointer.
__unsafe_unretained id deadObj = [[NSMutableString alloc] initWithFormat:@"%d", 12];
// Create my object.
MyClass* myObject = [[MyClass alloc] init];
// Assign my member.
[myObject SetMember:deadObj];
// Get back my member: by passing parameter by reference
__unsafe_unretained id unsafePointer1;
[myObject GetMember1:&unsafePointer1]; // No problem.
// Get back my member: by return value
__unsafe_unretained id unsafePointer2;
unsafePointer2 = [myObject GetMember2]; // Crashed in here!
int BreakpointHere = 0;
}
}
}
调用堆栈(iPhone 4.3模拟器/ iOS 4.3设备):
#0 0x011db09b in objc_msgSend ()
#1 0x00106712 in __arclite_objc_retainAutoreleaseReturnValue at /SourceCache/arclite_host/arclite-29.1/source/arclite.m:259
#2 0x00001fec in -[MyClass GetMember2] at /Users/user/SourceCode/main.m:28
#3 0x00002147 in main at /Users/user/SourceCode/main.m:56
调用堆栈(iPhone 5.0 / 5.1模拟器):
#0 0x014f6d25 in objc_retain ()
#1 0x014f7fe3 in objc_retainAutoreleaseReturnValue ()
#2 0x00001fec in -[MyClass GetMember2] at /Users/user/SourceCode/main.m:28
#3 0x00002147 in main at /Users/user/SourceCode/main.m:56
答案 0 :(得分:1)
我认为可以使用自动引用计数文档中的以下信息3.2.3. Unretained return values来解释此行为:
返回可保留对象类型的方法或函数 不返回保留值必须确保对象仍然有效 越过回程边界。
从这样的函数或方法返回时,ARC保留该值 在评估退货声明时,然后全部离开 本地范围,然后平衡保留,同时确保 价值贯穿于呼叫边界。在最坏的情况下,这可能 涉及自动释放,但调用者不得假设值为 实际上是在自动释放池中。
您的函数GetMember2
返回id
,这是一种可保留的对象类型。因此,ARC编译器添加retain
/ autorelease
调用以确保返回的对象在函数返回时仍然有效。由于m_MyMember
未指向有效对象,因此崩溃。
将返回类型声明为(__unsafe_unretained id)
不会改变此行为,实际上我假设此处忽略__unsafe_unretained
。