tableView:moveRowAtIndexPath:toIndexPath:看內存管理

/*今天本來在研究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.mArr objectAtIndex:fromRow];

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

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

    

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

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

    

    [self.mArr removeObjectAtIndex:fromRow];

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

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

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

    if (destinationIndexPath.row > [self.mArr count])

    {

        [self.mArr addObject:obj];

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

    }

    else

    {

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

        [self.mArr insertObject: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方法的使用次數相等(法則引自小橘子書)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章