使ObjectiveC对象在函数范围之外有效

时间:2019-12-14 14:40:53

标签: objective-c pointers automatic-ref-counting indirection

在设置作为输入指针的变量时,我对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初始化新对象并将数据复制到该新对象。

谢谢!

2 个答案:

答案 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

注释:

  

重要

     

正如@matt在注释中指出的,您的代码包含ARC中禁止的NSError * _autoreleasing *retain调用,因此,如果您的代码正在编译,则您未启用ARC。对于新项目,将启用ARC,对于现有项目,您可能需要将其启用为项目的 Build Settings ,该设置称为“ Objective-C自动引用计数”。

答案 1 :(得分:0)

对“自动释放”的调用意味着对象具有额外的保留计数,当您离开当前的自动释放范围时(通常是在当前事件结束时),该保留计数将消失。

record = item显然不够用,因为当记录离开作用域时(即函数返回时),记录的保留计数消失了。

但是您要做的是-为每个项目调用自动释放功能,以确保 all 项保持分配一段时间,而不仅仅是“记录”。