在设置作为输入指针的变量时,我对ARC的行为有些困惑,并期望在函数范围之外保持有效。
考虑以下使用openDirectory框架的示例。
@interface bbb
-(bool)doSomethingWithADRecord:
-(void)obtainADRecord(NSString*)user
-(NSString*)getADrecord:(ODAttributeType)attr fromRecord:(ODRecord*)record;
@end
@interface bbb {
ODRecord *_myRecord;
}
@end
@implementation bbb
-(void)doSomethingWithADRecord:
{
// here we access _myRecord and expect it to be valid.
}
-(bool)obtainADRecord:(NSString*)user
{
...
// here I call the method that will set the member _myRecord from type ODRecord*
// whose scope related to the lifespan of the containing class (bbb)
[self getADrecord:attr toRecord:_myRecord];
}
// the following function should set the variable record to be used by the caller.
-(NSString*)getADrecord:(ODAttributeType)attr fromRecord:(ODRecord*)record {
...
// here a set an ODQuery object.
ODQuery *query = [[ODQuery alloc] initWithNode ...
// queryResults is an array of items from type ODQuery*
NSArray* queryResults = [query resultsAllowingPartial:NO error:&err];
for(ODRecord *item in queryResults) {
if (/*some logic*/)
{
//option 1: just regular set operator, expecting the ARC will do the retain itself
record = item;
//option 2: explicits take a reference on that item.
record = [[item retain] autorelease];
return @"found item";
}
}
}
@end
为澄清我的问题,我想知道我上面提到的两个选项中哪一个是正确的,就将引用传递给record
并最终传递给_myRecord
而言,它将即使将清除queryResults
的临时列表后,也要存储正确的值。
请注意,在这两个选项中,我都只是设置指针值,而无需从类型ODquery
初始化新对象并将数据复制到该新对象。
谢谢!
答案 0 :(得分:4)
我想知道简单地执行
record = item
是否足以使该对象指向的数据持续超出功能getADrecord
的范围
您误解了参数的工作方式;参数,例如record
,实际上是一个局部变量,该局部变量被初始化为调用中传递的 value 。
因此,对record
的对象引用的 any 分配对超出getADrecord
范围(如record
)的被引用对象的生存期的影响为零。在该函数中是本地的。
要通过参数返回类型T的值,该参数的类型必须为“指向类型T的变量的指针”。一个具有简单值类型的示例:
- (void) add:(int)value // an int value
to:(int *)ptrToVariable // a pointer to an int variable
{
// note the need to indirect (`*`) through pointer stored in
// `ptrToVariable` to access the pointed at variable
*ptrToVariable = *ptrToVariable + value;
}
int x = 31;
[self add:11 to:&x]; // &x creates a pointer to the variable x
// x = 42 after call
现在,您不想返回简单的值类型,而是返回一个对对象的引用的值,并且希望ARC正确管理生存期。这有点复杂。
在ARC下,保存对对象的引用的变量既具有类型又具有 ownership属性;此属性通知ARC如何处理在变量中存储引用。通用所有权属性为__strong
和__weak
,不带显式属性__strong
。因此,您的实例变量声明是以下内容的简写:
ODRecord __strong *_myRecord;
此声明意味着,对存储在ODRecord
ARC中的_myRecord
的任何引用都将使引用的ODRecord
至少在{em {1 }}存在,并且引用未被其他引用或_myRecord
覆盖。只要同一参考可以存储在其他地方,它“至少要长”,这也会影响生命周期。
快到了!要通过参数返回对nil
的引用,该参数的类型必须为“指向ODRecord
的强引用类型的变量的指针,即:
ODRecord
现在是一个作业,例如:
- (NSString *)getADrecord:(ODAttributeType)attr
fromRecord:(ODRecord * __strong *)record
将导致对指向变量的赋值,并且由于该变量的类型为*record = item;
,ARC将确保所引用的ODRecord __strong *
至少在其引用存储在其中的期间有效指向变量。
您对此方法的调用必须将指针传递给您的变量:
ODRecord
注释:
“ out”参数在错误显着的例外中很少在Objective-C中使用-它们的类型为[self getADrecord:attr toRecord:&_myRecord];
,Apple将这种用法称为“回写回叫”。 / p>
有关ARC和通过参数返回值的更详细说明,请参见Handling Pointer-to-Pointer Ownership issues in ARC和NSError and __autoreleasing
重要:
正如@matt在注释中指出的,您的代码包含ARC中禁止的
NSError * _autoreleasing *
和retain
调用,因此,如果您的代码正在编译,则您未启用ARC。对于新项目,将启用ARC,对于现有项目,您可能需要将其启用为项目的 Build Settings ,该设置称为“ Objective-C自动引用计数”。
答案 1 :(得分:0)
对“自动释放”的调用意味着对象具有额外的保留计数,当您离开当前的自动释放范围时(通常是在当前事件结束时),该保留计数将消失。
record = item显然不够用,因为当记录离开作用域时(即函数返回时),记录的保留计数消失了。
但是您要做的是-为每个项目调用自动释放功能,以确保 all 项保持分配一段时间,而不仅仅是“记录”。