Objective-C 記憶體管理之dealloc方法中變數釋放處理

來源:互聯網
上載者:User

標籤:des   style   blog   http   io   ar   os   使用   sp   

本文轉載至 http://blog.sina.com.cn/s/blog_a843a8850101ds8j.html 

(一).關於nil

http://cocoadevcentral.com/d/learn_objectivec/

Calling Methods on Nil

In Objective-C, the nil object is the functional equivalent to the NULLpointer in many other languages. 

The difference is that you can call methods on nil without crashing or throwing an exception.   

在Objective-C中,nil對象與許多其他語言中的NULL指標有同樣的功能。

區別在於,你可以向一個nil對象發送任何資訊,即讓一個nil的對象調用任何方法,而不會導致程式的崩潰或者拋出異常。

這是一個有用的基礎知識

另外在cocoachina (http://www.cocoachina.com/bbs/read.php?tid-70288.html )論壇有人指出

對象被release後 系統會將該塊記憶體標記為可用(可重新分配)  nil就是起到個重設指標的作用 對記憶體的釋放無意義 

防止出現調用錯誤。

 

(二).結論:

不同的環境下使用不同的代碼處理是中庸之道,也就是

如果你在開發和調試,測試階段

使用可以直接暴露問題代碼的dealloc處理方式:

在dealloc中即僅僅release你的變數。

如果你把程式發布給使用者使用,使用先release,後賦值nil的方式

這樣,不會暴露crash給使用者

 

(三)..以下是參考:

 

首先,這是一篇非常好的部落格,詳細說明了關於dealloc中的幾種處理方式的論證

http://iphonedevelopment.blogspot.com/2010/09/dealloc.html

英文好的看原文,不要被我的翻譯誤解。

另外:

stackoverflow上幾個有價值的參考,上面討論了開發人員的在這方面的經驗:

http://stackoverflow.com/questions/4124049/dealloc-use-release-or-set-to-nil-for-properties

http://stackoverflow.com/questions/192721/why-shouldnt-i-use-objective-c-2-0-accessors-in-init-dealloc

 

(四)..現在,正式對這篇部落格翻譯:http://iphonedevelopment.blogspot.com/2010/09/dealloc.html

聲明:如果有錯誤翻譯或者錯字等請指出,但是本人僅是翻譯供學習探討所用,任何問題與糾紛居於本人無關,謝謝合作!

Dealloc

Last week there was a bit of a Twitter in-fight in the iOS community over the "right" way to release your instance variables in dealloc. I think Rob actually started it, to be honest, but I probably shouldn‘t be bringing that up.

上一周,在Twitter iOS 社區上有一場關於任何正確在dealloc方法中正確釋放你的變數的激烈討論(辯論大戰!),我認為是由Rob引發的,但說實話,我其實不應該透露這一點(好笑,作者不想八卦,卻仍然給了Rob的串連~).

Basically, several developers were claiming that there‘s never a reason to set an instance variable to nil in dealloc, while others were arguing that you should always do so.

基本上,幾個開發人員都聲明到,沒有任何理由允許在dealloc方法中把一個執行個體變數設值為nil,同時其他極為爭辯到你應該這麼做,即在dealloc中,對執行個體變數賦值為nil.

To me, there didn‘t seem to be a clear and compelling winner between the two approaches. I‘ve used both in my career. However, since we‘re in the process of trying to decide which approach to use in the next edition of Beginning iPhone Development, I reached out to Apple‘s Developer Tools Evangelist, Michael Jurewitz, to see if there was an official or recommended approach to handling instance variables in dealloc.

對我來說,似乎在這兩種方式中,沒有出現一個清晰地完全的勝利者。在我的開發過程中,這兩種方式我都用過。但是,既然我們在嘗試將這兩個方法取其一而用到下一版本的 Beginning iPhone Development中,我向蘋果的開發人員 Michael Jurewitz 求助,來探索在dealloc中如何處理執行個體變數這件事情上,是否存在一個官方的或者推薦的方法。

Other than the fact that you should never, ever use mutators in dealloc (or init, for that matter), Apple does not have an official recommendation on the subject.

除了在dealloc或者init方法中,你最好不要使用設值方法(eg:[self.xxxx message];),蘋果沒有提供過關於dealloc中釋放執行個體變數的官方推薦方法。

However, Michael and Matt Drance of Bookhouse Software and a former Evangelist himself, had discussed this issue extensively last week. They kindly shared their conclusions with me and said it was okay for me to turn it into a blog post. So, here it is. Hopefully, I‘ve captured everything correctly.

然而,Michael and Matt Drance of Bookhouse Software 和一個前 Evangelist 他自己(Evangelist本意是傳播福音的人,我猜是那些宣講蘋果官方技術的人員,就是普及蘋果開發技術的一些專家吧)關於此問題在上周進行了一場較廣泛的討論。他們非常有好的與我分享了他們的結論結果並且同意我在部落格上登載出來,所以,結果是這樣的,希望我已經正確地搜集到每個方面了。

 

The Two Major Approachs

Just to make sure we‘re all on the same page, let‘s look at the two approaches that made up the two different sides of the argument last week. 

兩種主要的方法

首先來確認我們達成共識,讓我們先看看上周兩個不同支援者的兩種方法。

Just Release

僅僅release

The more traditional approach is to simply release your instance variables and leave them pointing to the released (and potentially deallocated) object, like so:

最傳統的方法是僅僅release掉你的執行個體變數並且任其只想一個已經release的對象上,就像這樣:

 

  1. - (void)dealloc  
  2. {  
  3.     [Sneezy release];  
  4.     [Sleepy release];  
  5.     [Dopey release];  
  6.     [Doc release];  
  7.     [Happy release];  
  8.     [Bashful release];  
  9.     [Grumpy release];  
  10.     [super dealloc];  
  11. }  

 

In this approach, each of the pointers will be pointing to a potentialy invalid object for a very short period of time — until the method returns — at which point the instance variable will disappear along with its owning object. In a single-threaded application (the pointer would have to be accessed by something triggered by code in either this object‘s implementation of dealloc or in the dealloc of one of its superclasses, there‘s very little chance that the instance variables will be used before they go away , which is probably what has led to the proclamations made by several that there‘s "no value in setting instance variables to nil" in dealloc. 

在這個方法上,每一個指標都會在非常短的時間上的指向一塊可能非法的對象上,知道方法執行完畢,在那時,執行個體變數會隨著它的擁有者一同消失。在一個單線程的應用中(指標會不得不被或者是對象的自己實現dealloc又或者在它父類的dealloc中一些啟動的東西訪問到,一個執行個體變數在它小事之前會被使用到是一個小機率事件。但如果發生了,就正中下懷了,也就是那些宣告說需要在dealloc方法中賦值給執行個體變數nil值觀點的人所顧慮的那樣。

In a multi-threaded environment, however, there is a very real possibility that the pointer will be accessed between the time that it is deallocated and the time that its object is done being deallocated. Generally speaking, this is only going to happen if you‘ve got a bug elsewhere in your code, but let‘s face it, you may very well. Anyone who codes on the assumption that all of their code is perfect is begging for a smackdown, and Xcode‘s just biding its time waiting for the opportunity.

然而,在一個多線程的環境裡,一個指標在本身被dealloc以後與它的擁有者對象被dealloc之前被訪問到,卻是一個很有可能發生的事情的。一般而言,如果你在別處代碼中遇到bug,這裡成為了問題的源頭,但是讓我們面對它,你會變得更好。任何建立在自己的代碼是完美的這個假設上寫代碼的人都是在掩耳盜鈴,Xcode僅僅是在伺機而動,等待機會報錯給你。

 

Release and nil 

In the last few years, another approach to dealloc has become more common. In this approach, you release your instance variable and then immediately set them to nil before releasing the next instance variable. It‘s common to actually put the release and the assignment to nil on the same line separated by a comma rather than on consecutive lines separated by semicolons, though that‘s purely stylistic and has no affect on the way the code is compiled. Here‘s what our previous dealloc method might look like using this approach:

在過去的幾年,另一個在dealloc中處理的方法變得越來越普及,在這個方法中,你release你的執行個體變數並且在releasing下一個執行個體變數前立即把它賦值為nil.比較普遍的做法是,將release語句與賦值nil語句用一個都好隔開放到同一行而不是用分號隔開為多行,儘管這樣做僅僅是表層代碼的長相上,在編譯時間是無任何差別的。下面是我們之前的dealloc用這種方法後的樣子:


  1. - (void)dealloc  
  2. {  
  3.     [sneezy release], sneezy = nil;  
  4.     [sleepy release], sleepy = nil;  
  5.     [dopey release], dopey = nil;  
  6.     [doc release], doc = nil;  
  7.     [happy release], happy = nil;  
  8.     [bashful release], bashful = nil;  
  9.     [grumpy release], grumpy = nil;  
  10.     [super dealloc];  
  11. }  
In this case, if some piece of code accesses a pointer between the time that dealloc begins and the object is actually deallocated, it will almost certainly fail gracefully because sending messages to nil is perfectly okay in Objective-C. However, you‘re doing a tiny bit of extra work by assigning nil to a bunch of pointers that are going to go away momentarily, and you‘re creating a little bit of extra typing for yourself in every class.

 

在這種情況下如果有代碼訪問一個開始被dealloc但是還沒被完全dealloc間的指標時,這樣的操作是無效失敗的,因為在Objective-C中,想一個nil值的對象發送訊息是沒有問題,不會引發錯誤的。但是,如果你賦值給一些會立即消失的對象nil值,你卻做了一些額外的工作,在每一個你的類中都會製造這些額外的輸入開支。

 

 

The Showdown 最後一戰So, here‘s the real truth of the matter: The vast majority of the time, it‘s not going to make any noticeable difference whatsoever. If you‘re not accessing instance variables that have been released, there‘s simply not going to be any difference in the behavior between the two approaches. If you are, however, then the question is: what do you want to happen when your code does that bad thing?

 

那麼,接下來是最重要的地方。絕大多數的時候,沒有什麼明顯的區別。如果你不去訪問那些被釋放掉的執行個體變數,在這兩種方法間沒有任何的功能方面結果的區別。但如果你訪問了,那麼問題是,你想你的代碼如何針對這種情況做出反應?

In the first approach, your application will usually crash with an EXC_BAD_ACCESS, though you could also end up with any manner of odd behavior (which we call a "heisenbug") if the released object is deallocated and its memory is then reused for another object owned by your application. In those cases, you may get a selector not recognized exception when the message is sent to the deallocated object, or you may simply get unexpected behavior from the same method being called on the wrong object.

第一種方法下,你的程式通常下會崩潰,警告給你EXC_BAD_ACCESS,雖然你還可能最後得到一些詭異的結果(通常我們都稱它為heisenbug,這種bug是詭異的出現,並且通常不好重現,以致難以修補)像是一個released對象被dealloced並且它的記憶體之後被你的沖虛中另一個對象利用到。在這種情況下,你可能得到一個selector not recognized異常,當訊息被發送給一個被delloced完的對象,或者在一個錯誤的對象執行你調用的方法後,你可能僅僅得到一個異常結果。
In the other approach, your application will quietly send a message to nil and go about its merry way, generally without a crash or any other immediately identifiable problem.
在另一個方法下,你的程式會給一個nil值的對象發送訊息並且就這麼不了了之了~什麼都沒有發生,沒有程式崩潰(no crash!!),沒有其他任何即時可分辨的問題出現。
The former approach is actually good when you‘re developing, debugging, and doing unit testing, because it makes it easier to find your problematic code. On the other hand, that approach is really, really bad in a shipping application because you really don‘t want to crash on your users if you can avoid it.

前一種方法在你正在開發,調試或者做單元測試時會更有優勢。因為它會讓你很容易找到問題代碼。另一方面,這個方法會非常非常的糟糕,在你發布你的程式後,因為你不想你的使用者在使用時遇到程式crash並且這是你可以避免的crash!。

The latter approach, conversely, can hide bugs during development, but handles those bugs more gracefully when they happen, and you‘re far less likely to have your application go up in a big ball of fire in front of your users.

後一種方法,相反地會在開發過程中掩蓋住你的bugs,但是在bugs發生的時候更溫和的處理掉了,但同時你會讓或多或少可能讓你的程式被火球包裹,然後呈現給你的使用者。

 

The Winner? 勝利者?There really isn‘t a clear cut winner, which is probably why Apple doesn‘t have an official recommendation or stance. During their discussion, Matt and Michael came up with a "best of both worlds" solution, but it requires a fair bit of extra code over either of the common approaches. 
其實並沒有一個明顯的勝利者,或許這就是為什麼蘋果沒有給出一個官方的推薦或者例子的原因。在他們討論期間,Matt and Michael 得出一個權衡之計,既兩種情況都會使程式更好更穩固的解決方案,但是這需要一些額外的代碼,在這兩種通常的方法基礎上。
If you want your application to crash when a released pointer is accessed during development and debugging, the solution is to use the traditional approach in your debug configuration. If you want your application to degrade gracefully for your users, the solution is to use the newer approach in your release and ad hoc configurations. 
在你開發和調試期間,當一個指標被訪問時如果你想要你的程式直接crash,解決方案就是用最傳統的方法在你的調試環境。如果你想你的程式友好的呈現給使用者,解決方案是用新的方法,在你的release並且加上額外配置。
One somewhat pedantic implementation of this approach would be this: 
一種比較死板的實現這個理論的方法會像是這樣:
- (void)dealloc { #if DEBUG [Sneezy release]; [Sleepy release]; [Dopey release]; [Docrelease]; [Happy release]; [Bashful release]; [Grumpy release]; [super dealloc];#else [sneezy release], sneezy = nil; [sleepy release], sleepy = nil; [dopeyrelease], dopey = nil; [doc release], doc = nil; [happy release], happy = nil;[bashful release], bashful = nil; [grumpy release], grumpy = nil; [super dealloc];#endif }

That code assumes that your debug configuration has a precompiler definition of DEBUG, which you usually have to add to your Xcode project - most Xcode project templates do not provide it for you. There are several ways you can add it, but I typically just use the  Preprocessor Macros setting in the project‘s Build 

 

這個代碼假設你的調試配置中有一個先行編譯宏定義,你必須將它添加到你的Xcode 工程中,大多數Xcode工程模板不會提供給你這個。有多種方式添加,但是代表性的,我只使用在工程Build下的先行編譯宏設值

 

配置:

 

Although the code above does, indeed, give us the best of both worlds - a crash during development and debugging and graceful degrading for customers - it at least doubles the amount of code we have to write in every class. We can do better than that, though. How about a little macro magic? If we add the following macro to our project‘s .pch file:
儘管上面的代碼給了我們權衡的答案,也就是在開發和調試時程式會crash,但是在發布給使用者時會平穩的處理掉。可是它至少在我們每一個類中都多使用照原來兩倍的代碼。我們可以做的更好,用一些宏怎麼樣?如果我們在.pch檔案中加入下面的宏變數:

 

  1. #if DEBUG  
  2. #define MCRelease(x) [x release]  
  3. #else  
  4. #define MCRelease(x) [x release], x = nil  
  5. #endif  


 


We can then use that macro in dealloc, and our best-of-both-worlds code becomes much shorter and more readable:
我們可以在dealloc中使用它們,並且我們的“權衡方法”變得更短,更加易讀:
- (void)dealloc { MCRelease(sneezy); MCRelease(sleepy); MCRelease(dopey);MCRelease(doc); MCRelease(happy); MCRelease(bashful); MCRelease(grumpy); [superdealloc]; }


Once you‘ve got the macro in your project, this option is actually no more work or typing than either of the other dealloc methods.
一旦你在你的工程中寫了宏,這種選擇不會比之前的兩種dealloc方法花費額外的工作。
But, you know what? If you want to keep doing it the way you‘ve always done it, it‘s really fine, regardless of which way you do it. If you‘re consistent in your use and are aware of the tradeoffs, there‘s really no compelling reason to use one over the other outside of personal preference.
但是你知道嗎?如果你想保持你之前在dealloc處理對象的方式,其實也是不錯的。無論你現則哪種方式,如果你對你使用並且意識到其中利弊,真的什麼強制的理由讓一個人改變他的個人選擇。
So, in other words, it‘s kind of a silly thing for us all to argue over, especially when there‘s already politics, religions, and sports to fill that role.

 

 

那麼,也就是說,我們沒有必要爭論下去了,需要爭論的東西太多了,像是政策,種族,體育那些...

 

The Garbage Collection Angle  There‘s one last point I want to address. I‘ve heard a few times from different people that setting an instance variable to nil indealloc acts as a hint to the garbage collector when you‘re using the allowed-not-required GC option (when the required option is being used, dealloc isn‘t even called, finalize is). If this were true, forward compatibility would be another possible argument for preferring the newer approach to dealloc over the traditional approach.
還有最後一點我想要指出。好幾次,我從不同的人聽到過,在dealloc方法中賦值給執行個體變數nil值會起到給記憶體回收行程一個鉤子的作用,當你用allowed-not-required GC 選項(當required-option被使用,dealloc不會被調用,finalize會)。如果這是真的,向前相容會變成新的爭論,針對在dealloc裡新的方法與傳統的方法之間。
While it is true that in Java and some other languages with garbage collection, nulling out a pointer that you‘re done with helps the garbage collector know that you‘re done with that object, so it‘s not altogether unlikely that Objective-C‘s garbage collector does the same thing, however any benefit to nil‘ing out instance variables once we get garbage collection in iOS would be marginal at best. I haven‘t been able to find anything authoritative that supports this claim, but even if it‘s 100% true, it seems likely that when the owning object is deallocated a few instructions later, the garbage collector will realize that the deallocated object is done with anything it was using.

 

在java和一些其他的內建記憶體回收的機制的語言中,給一個指標賦值null會協助你讓記憶體回收行程知道你已經用完這個對象了,它們不等同於Objective-C的記憶體回收行程做同樣的操作,但是使用nil賦值給執行個體變數的益處,一旦是iOS的記憶體回收機制它都變得相當的邊緣化了。我沒能找到任何權威性的論據來支援這個聲明,但是即使它是百分百真的,似乎當一個被擁有的對象被指令dealloc執行後,記憶體回收行程會意識到那個被dealloc的對象已經做完所有該做的事情。
If there is a benefit in this scenario, which seems unlikely, it seems like it would be such a tiny difference that it wouldn‘t even make sense to factor it into your decision. That being said, I have no firm evidence one way or the other on this issue and would welcome being enlightened. 

在這種情境下有沒有好處,貌似沒有...似乎它都不能成為你做決定使用那種方法的一個參考因素。也就是說,我沒有有力的證據,在這個問題上歡迎大家來討論互相啟發。

Objective-C 記憶體管理之dealloc方法中變數釋放處理

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.