在Objective-C中销毁一个对象

时间:2013-08-18 16:22:59

标签: ios objective-c

我正在尝试实现一个链表,所以我有一个带有头文件的Node类,如下所示:

@interface Node : NSObject

@property(nonatomic,assign)int data;
@property(nonatomic,strong) Node *right;
@property(nonatomic,strong) Node *left;

@end

然后在另一个类中,我正在分配它们然后调用一个方法来销毁给定值的所有出现:

Node *node0 = [[Node alloc]init];
Node *node1 = [[Node alloc]init];
Node *node2 = [[Node alloc]init];
Node *node3 = [[Node alloc]init];
Node *node4 = [[Node alloc]init];
node0.data = 1;
node1.data = 2;
node2.data = 5;
node3.data = 5;
node4.data = 3;
node0.right = node1;
node1.right = node2;
node2.right = node3;
node3.right = node4;
node4.right = NULL;
[self removeNodeWithValue:node0 value:5];
NSLog(@"node %d, %d, %d, %d, %d", node0.data, node1.data, node2.data, node3.data, node4.data);

这是方法本身:

-(void)removeNodeWithValue:(Node *)head value:(int)value
 {
  Node *toDelete;
  while (head != NULL) {
    if (head.data == value)
    {
        toDelete = head;
        head = head.right;
        toDelete = nil;
    }
    else
    {
       head = head.right;
    }
  }
 }
 ==> 1, 2, 5, 5, 3

我知道我可以更改实例,因为如果我将toDelete = nil更改为toDelete.data = 4,则输出为==> 1, 2, 4, 4, 3。我的问题是,我如何销毁这些实例?感谢。

3 个答案:

答案 0 :(得分:3)

好像你还没有理解ARC是如何工作的。只要有一个指向该对象的强指针,该对象就不会被释放。在您的示例中,您的代码失败有两个原因:首先,您始终强烈引用node0

Node *node0 = [[Node alloc]init];

只要此指针未设置为nil(请记住,按惯例NULL用于常规指针,nil用于对象指针),该节点将不会被释放。

其次,如果要释放的节点不是第一个节点,那么另一个节点会有一个指向它的强指针,这也是该节点不会被解除分配的另一个原因。保持指向node0(在您的情况下为toDelete)的另一个指针将增​​加节点的节点保留计数,当您将其设置为nil时,它将返回到它的原始状态值。

要正确地执行此操作,您还必须避免链删除(如果第一个节点被解除分配,它将丢失对第二个节点的强引用,如果没有强指针,则可能会释放该第二个节点,并且还会导致第三个节点要解除分配,等等)。

最后,我建议不要只持有一堆指向每个节点的指针,而是实现一个链表类,它将完成添加/删除节点的工作:

@interface List : NSObject

@property (nonatomic, strong) Node* first;
@property (nonatomic, weak) Node* last;

@end

// Inside the class implementation

- (void) addNodeWithValue: (int) value
{
    Node* node= [[Node alloc]init];
    node.data= value;
    if(!first)
    {
        last= first= node;
    }
    else
    {
        last.right= node;
        node.left= last;   // left should be a weak property
        last= node;
    }
}

- (void) removeNodeWithValue: (int) value  // O(n) method
{
    Node* ptr= first;
    while(ptr) 
    {
        if(ptr.data== value)
        {
            if(ptr== first)
            {
                first= last= nil;
            }
            else
            {
                ptr.left.right= ptr.right;
                ptr.right.left= ptr.left;
            }
            break;  // Remove the break if you want to remove all nodes with that value
        }
        ptr= ptr.right;
    }
}

我没有测试过这段代码,我不能保证它能正常工作。

答案 1 :(得分:0)

因此,您希望清除具有指定值的所有节点。首先,您的测试无效,因为您明确引用了所有节点,因此即使从节点结构中清除它们,您的测试日志仍会将其打印出来。其次,当删除方法未发现被测节点具有指定值时,需要以递归方式调用节点结构。第三,节点不应该自己测试,它应该测试leftright节点值(节点不能自行删除,因为它不知道它的父节点。)

所以,比如:

-(void)removeNodeWithValue:(Node *)head value:(int)value
{
    if (head.right.data == value)
    {
       head.right = nil;
    }
    else
    {
        [self removeNodeWithValue:head.right value:value];
    }

    if (head.left.data == value)
    {
       head.left = nil;
    }
    else
    {
        [self removeNodeWithValue:head.left value:value];
    }
}

这不会测试根节点本身,因为应该在启动之前检查它,然后从控制器本身中删除头项目。

答案 2 :(得分:0)

您的问题不是删除对象,而是指针。

指针就像箭头指向带有内容的盒子(记忆位置)。当你这样做

toDelete = head;
head = head.right;
toDelete = nil;

您只是删除了某个框中的一个“箭头”,但没有删除该框本身。

Wain的答案应该给出正确的方法。