《Mastering Delphi 6》學習筆記之八 (轉)
構件自動清除的內幕
我們已經知道,TComponent在釋放自身的時候會自動刪除它Owns的所有Component,這是的一個極大特點。否則的話,任何動態生成的比如Menu Items都要自己維護和刪除,那將是多麼痛苦。VCL是如何做到這一點的呢?可以想象到,每個Component內部應該保持一個列表,記錄它所擁有的Components,在自身的析構中將列表中的所有物件同時刪除即可。基本上這個想法是正確的,不過應該考慮到兩種可能的情況:(1)構件刪除自身的時候,將它所擁有的子構件全部清除,這種情況下子構件是被動的;(2)某個子構件主動地了Free或者Destroy,這個時候,父構件應該有辦法得到通知,並且維持列表的同步。否則的話,就可能出現某個子構件被析構兩次以上的情況,其後果如何大概也可以想到了。:namespace prefix = o ns = "urn:schemas--com::office" />
要保持列表的同步,子構件在建立的時候就必須向父構件報告,退出的時候也必須給父構件打個招呼才行。
原理不復雜,現在來看看VCL是如何實現的。TComponent的構造方法叫做Create,帶有一個AOwner引數:
constructor TComponent.Create(AOwner: TComponent);
begin
FComponentStyle := [csInheritable];
if AOwner <> nil then AOwner.InsertComponent(Self);
end;
InsertComponent正是我們關心的地方。找找看它的具體實現:
procedure TComponent.InsertComponent(AComponent: TComponent);
begin
AComponent.ValidateContainer(Self);
ValidateRename(AComponent, ', AComponent.FName);
Insert(AComponent);
AComponent.SetReference(True);
if csDesigning in ComponentState then
AComponent.SetDesigning(True);
Notification(AComponent, opInsert);
end;
雖然有些地方還不大明白,不過關鍵的部分看來是Insert(AComponent)一句。再找到Insert:
procedure TComponent.Insert(AComponent: TComponent);
begin
if FComponents = nil then FComponents := TList.Create;
FComponents.Add(AComponent);
AComponent.FOwner := Self;
end;
我們所猜想的內部列表終於現身,它是一個通用的,可以容納任何T或者Pointer的TList型別。
另外,從上面的程式碼段也可以看到VCL中比較典型的一種處理方法,那就是物件“只有在需要的時候才建立”,比如上面建立FComponents就是屬於這種情況。當然,在每次建立一個構件時都檢查一遍FComponent的有效性將會稍稍影響程式的執行速度,但是考慮到程式所佔用的(Form和Application一般有應該有Components列表,而一般的構件則完全沒有必要,如果每個構件都建立一個List的話,那麼佔用的記憶體是相當可觀的),這種處理方法也有它的道理。
現在再來看看析構時的情況:
destructor TComponent.Destroy;
begin
Destroying;
if FFreeNotifies <> nil then
begin
while Assigned(FFreeNotifies) and (FFreeNotifies.Count > 0) do
TComponent(FFreeNotifies[FFreeNotifies.Count - 1]).Notification(Self, opRemove);
FreeAndNil(FFreeNotifies);
end;
DestroyComponents;
if FOwner <> nil then FOwner.RemoveComponent(Self);
inherited Destroy;
end;
這裡有兩個重要的地方:(1)DestroyComponents一句,顯然是刪除其所擁有的Components;(2)FOwner.RemoveComponents(Self),看來是把自身從父構件的FComponents列表中移走。
procedure TComponent.DestroyComponents;
var
Instance: TComponent;
begin
while FComponents <> nil do
begin
Instance := FComponents.Last;
if (creeNotification in Instance.FComponentState)
or (FComponentState * [csDesigning, csInline] = [csDesigning, csInline]) then
RemoveComponent(Instance)
else
Remove(Instance);
Instance.Destroy;
end;
end;
procedure TComponent.RemoveComponent(AComponent: TComponent);
begin
ValidateRename(AComponent, AComponent.FName, ');
Notification(AComponent, opRemove);
AComponent.SetReference(False);
Remove(AComponent);
end;
RemoveComponent內部又呼叫了Remove,再看看這個函式:
procedure TComponent.Remove(AComponent: TComponent);
begin
AComponent.FOwner := nil;
FComponents.Remove(AComponent);
if FComponents.Count = 0 then
begin
FComponents.Free;
FComponents := nil;
end;
end;
很簡單,是麼?透過這一番遊歷,相信“構件在何種情況下會被自動清除和如何被清除”這個問題應該有了明確的答案,以後寫起程式碼來也應該放心多了。
附記:透過上面的例子,我才體會到Delphi中的導航鍵是多麼方便!不論是自己的單元還是VCL內部單元,用Ctrl+點選和Ctrl+Shift+Up/Down,以及Code Editor中的Back/For按鈕,三兩下就可以定位到任何地方。在Visual C++中就沒有這樣的方便,不論是用Trace還是用 Browser,都必須先編譯透過才行,即使用Find In Files也不見得快多少。相比起來,在Delphi中跟蹤要方便多了。雖說Delphi的啟動速度確實慢了點,不過它在其他方面提供的快捷方便還是應該肯定的。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990616/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ES6學習筆記(八)【class】筆記
- hive學習筆記之八:SqoopHive筆記OOP
- 前端學習筆記之ES6~~~前端筆記
- ES6學習筆記之Function筆記Function
- JavaScript學習筆記(八)—— 補JavaScript筆記
- 彙編學習筆記之轉移指令筆記
- java學習筆記6Java筆記
- vue學習筆記6Vue筆記
- HexMap學習筆記(八)——水體筆記
- ES6學習筆記之Set和Map筆記
- ES6語法學習筆記之promise筆記Promise
- Redis學習筆記八:叢集模式Redis筆記模式
- es6學習筆記筆記
- ES6 學習筆記筆記
- ES6 學習筆記筆記
- Delphi TMSMQTT使用筆記MQQT筆記
- Golang 學習筆記八 錯誤異常Golang筆記
- Java學習筆記——第八天Java筆記
- PHP 第八週函式學習筆記PHP函式筆記
- 工作學習筆記(八)去重校驗筆記
- Java IO學習筆記八:Netty入門Java筆記Netty
- .NET 6學習筆記(6)——SSL證書的匯出和格式轉換筆記
- ES6的學習筆記筆記
- ES6 學習筆記一筆記
- ES6 學習筆記二筆記
- ES6 學習筆記三筆記
- ES6 學習筆記四筆記
- Oracle學習筆記(6)——函式Oracle筆記函式
- G01學習筆記-6筆記
- repuest轉發學習筆記一筆記
- node學習筆記第八節:模組化筆記
- 學習筆記之測試筆記
- JS學習筆記之this指向JS筆記
- flask學習筆記之blueprintFlask筆記
- Swoft 學習筆記之配置筆記
- 學習筆記:DOM之appendChild筆記APP
- node學習筆記之39筆記
- Web之http學習筆記WebHTTP筆記
- Netty學習筆記之ChannelHandlerNetty筆記