0

我有一个 Objective-C 方法,它创建一个指针,然后使用 performSelectorInBackground: 将它传递给一个新线程。问题是,我需要将指针的地址传递给线程,因为我想从线程中释放与其关联的内存。我遇到的问题是,当新线程启动时,调用方法结束,导致指针超出范围。如何在线程可以接收指针地址的地方保持足够长的时间?

如果我只是在主线程上调用“pointerTest”方法,这一切当然都有效。

这是我的代码:

-(void)pointerTest:(NSValue*)pointer
{   
    void **p = (void**)[pointer pointerValue];
    fprintf(stderr,"p was %s\n",(char*)(*p)); //prints "Hello There!"
    free(*p);
    *p = NULL;
}

现在,在主线程上:

-(IBAction)doTest:(id)sender
{
    char *str = "Hello There!";

    void *p = malloc(strlen(str)+1);
    strcpy(p, str);

    //this works
    //[self pointerTest:[NSValue valueWithPointer:&p]];

    //this fails
    [self performSelectorInBackground:@selector(pointerTest:) withObject:[NSValue valueWithPointer:&p]];

    if(!p){
        fprintf(stderr,"p was NULL!\n");
    }else{
        fprintf(stderr,"p was NOT NULL: %s\n",p);
    }
}

更新:

这段代码表明,如果我不将指针传递给 pointerTest:,我无法从 pointerTest 中释放 p:

-(void)pointerTest:(NSValue*)pointer
{   
    void *p = (void*)[pointer pointerValue];
    fprintf(stderr,"p was %s\n",(char*)p); //prints "Hello There!"
    free(p);
    fprintf(stderr,"p was %s\n",(char*)p); //STILL prints "Hello There!"
    *p = NULL;
    fprintf(stderr,"p was %s\n",(char*)p); //prints "(null)"
}

现在,在调用方法中:

//I pass p, NOT a pointer to p
[self pointerTest:[NSValue valueWithPointer:p]];

if(p){
    //p is not NULL, and in fact I can print its value
    fprintf(stderr,"p was NOT NULL: %s\n",p);
}

但是,如果我将指针传递给 p 而不是 p,我可以按预期从 pointerTest 中释放它的值:并且在从 pointerTest 返回时,调用方法中的 p 为 NULL。

4

1 回答 1

3

[我不会问你为什么将mallocC 字符串与 Objective-C 混合,我猜你是在试验。这样做本身并没有错,只是在这种情况下很不寻常。]

您根本不需要将指针传递给指针

指针名称。_ 一些框包含字符、一些员工记录等以及一些框名称(其他框的)。找到所需大小的盒子并返回其名称,您可以像传递整数值一样传递它 - 您不需要传递包含包含您的字符的盒子名称的盒子名称......malloc

此外,当malloc您需要在 C 字符串上允许尾随 NUL 字符时,请在字符串长度上加 1。

尝试:

- (void) pointerTest:(NSValue *)pointer
{   
   void *p = (void *)[pointer pointerValue];
   fprintf(stderr,"p (%p) was %s\n", p, (char *)p);

   free(p);
}

- (IBAction) doTest:(id)sender
{
   char *str = "Hello There!";

   void *p = malloc(strlen(str)+1); // allow for NUL
   fprintf(stderr,"p is %p\n", p);
   strcpy(p, str);

   // this works
   // [self pointerTest:[NSValue valueWithPointer:p]];

   // and so does this
   [self performSelectorInBackground:@selector(pointerTest:) withObject:[NSValue valueWithPointer:p]];

   if(!p)
   {
      fprintf(stderr,"p was NULL!\n");
   }
}

请注意,您不需要总结pNSValue将指针值传递给 Objective-C 方法没有错。

高温高压

评论后

您将指针的有效性与指针所指的内存中可能发生的事情混淆了。

指针指向的内存被释放。您的指针值在调用后不再有效free- 它是一个悬空指针

您现在悬空的指针值所引用的内存可以随时重新使用。碰巧的是,您fprintf的内存尚未被重新使用,因此您会看到旧内容-释放内存不会将其清除。

您存储NULL到变量中的目的是删除您的悬空指针,这样做通常可能是一种很好的做法,但是您发现获取短期变量的地址并将其传递给另一个方法是创建一个好方法悬空指针。因此,您最终尝试通过使用指向框 A 的悬空指针来清理从框 A 到框 B 的悬空指针,因为框 A 已经被释放了......让我们尝试用不同的方式来解释它;-)

在这种情况下,您创建了一个指向属于 的局部变量 (box) 的指针pdoTest一旦doTest完成,系统就会将正用于p空闲盒子堆(或本例中的堆栈)的盒子返回,并且您的指针变成了一个悬空; 当您的原始代码pointerTest尝试NULL通过那个现在悬空的指针将 a 存储到该框中时,您遇到了问题。

于 2012-09-28T21:26:37.160 回答