tableView:moveRowAtIndexPath:toIndexPath:看内存管理

来源:互联网 发布:centos 7 minimal ssh 编辑:程序博客网 时间:2024/05/20 11:33

/*今天本来在研究tableView:moveRowAtIndexPath:toIndexPath:这个方法,但是一个crash,让我有了一些有意思的发现,从而让我对内存管理有了更深的认识,不过这些只是我的个人理解,或许不正确,希望大家看过以后也可以发表一下意见*/

首先我就直接上一段代码

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath

{

   NSInteger fromRow = [sourceIndexPath row];

   NSInteger toRow = [destinationIndexPath row];

    

   id obj = [self.mArrobjectAtIndex:fromRow];

    //NSLog(@"%d,%p",[obj retainCount],obj);--------------1

    //NSLog(@"%p",[self.mArr objectAtIndex:fromRow]);-----2

    

    //[obj retain];---------------------------------------3

    //NSLog(@"%d",[obj retainCount]);---------------------4

    

    [self.mArrremoveObjectAtIndex:fromRow];

    //NSLog(@"%d",[obj retainCount]);---------------------5

    //NSLog(@"%d",[obj retainCount]);---------------------6

    //NSLog(@"%p",obj);-----------------------------------7

   if (destinationIndexPath.row > [self.mArrcount])

    {

        [self.mArraddObject:obj];

        //NSLog(@"%d",[obj retainCount]);-----------------8

    }

   else

    {

        //NSLog(@"%d",[obj retainCount]);-----------------9

        [self.mArrinsertObject:obj atIndex:toRow];

        //NSLog(@"%d,%p",[obj retainCount],obj);---------10

    }

    //[self.mArr insertObject:obj atIndex:toRow];--------11

    //[obj release];-------------------------------------12

    //NSLog(@"%d",[obj retainCount]);--------------------13


}


上面代码的打开部分是原来的代码,虽然不会报错,但是运行后,移动行就会发生crash的现象,比如,连续移动同一行。

将上面代码的3与12打开则不会发生崩溃。

其他是暴力调试用的,可以尝试打开它们,自己调试,会发现有意思的现象。在这里我简单说一下我的发现。

首先,将第1句与第2句打开,从打印结果你会发现,obj[self.mArr objectAtIndex:fromRow]是同一个对象。

然后只打开1,5,10并且保持两个retain,release语句关闭时,你会发现打印的引用计数的结果为1,1,2。

但是,如果打开两个retain,release语句,并且打开它们相应的引用计数语句,也就是打开1,3,4,5,10,12,13;这时打印的引用计数的结果为1,2,1,2,1。

好玩的事情发生了,就是在经过[self.mArr removeObjectAtIndex:fromRow]语句后,第一种情况的引用计数并没有减少,仍是1,而第二种情况的引用计数却由2降为1,我就很纳闷,这是什么情况,所以添加了语句9,因为我怀疑可能只是当时引用计数并未减少,而是在之后又进行了减少,这时出现了预料中的结果,在打断点的情况下,清楚地看到程序是在执行第9句的时候崩溃了,也就是说在这里obj的引用计数已经变为0,被清除了,所以才会引发crash,但是为什么不在第5句的时候就崩溃呢?为了排除其他想不到的因素,我在语句5后紧跟着添加了语句6,运行,哎?这次崩在了第6句,于是我大胆猜测,苹果可能由于某种原因设计了一种机制,就是在对象被某种方式使引用计数降为0以后,仍暂时保留它,直到下次调用以后,再清除。不过,这些只是我在自己现有的水平下的臆测,也希望知道其中原委的人解决我的疑惑。(补充:当我将第1句引去,则不会在第6句发生崩溃,第9句也不会崩溃,只在第二次移动同一句时,产生崩溃,这推翻了我的猜测,也加深了我的疑惑)。

没移动前移动一次再次移动同一标号行产生了崩溃。



这个事情让我重新审视了内存管理的法则。附在最后

1,当你使用new、alloc、或copy方法创建一个对象时,该对象的保留计数器值为1.当不再使用该对象时,你要负责向该对象发送一条release或autorelease消息。这样,该对象将在其使用寿命结束时被销毁。

2当你通过任何其他方法获得一个对象时,则假设该对象的保留计数器值为1,而且已经被设置为自动释放,你不需要执行任何操作来确保该对象被清理。如果你打算在一段时间内拥有该对象,则需要保留它并确保在操作完成时释放它。

3如果你保留了某个对象,你需要(最终)释放或自动释放该对象。必须保持retain方法和release方法的使用次数相等(法则引自小橘子书)

0 0
原创粉丝点击