學習Symbian開發過程中在網上找的一些好的資料,下面的這個symbian開發22條軍規轉自:
http://blog.csdn.net/lius1984/archive/2009/12/26/5082364.aspx
1、 確保您的應用程序能夠對系統關機事件做出響應。在您的AppUi::HandleCommandL()方法中,必須要對EEikCmdExit(以及任何特定平臺相關的事件,例如Series 60上的EAknSoftkeyBack)做出響應。
2、
要對外來系統事件做出響應。請牢記,您的應用程序在一個多任務電話系統上運行,您需要將注意力集中于剛獲得/丟失的事件上,以確保當用戶獲得一個高優先級
的通知時您能夠做出正確響應。例如,正打進來的電話會干擾您的應用程序的運行,這時應確保您已保存了系統狀態和數據(即:您需要對標準的“背景”事件采取
恰當的行動—請參閱SDK)。一般來說,系統框架會處理這個問題,您不需要采取任何特殊行動—但一定要確保您沒有妨礙系統框架的正常操作。
3、內存處理是Symbian OS需要考慮的一個重要課題。在這一點上,應注意電話有時會不同于模擬器。因此在將您的應用程序呈交給“Symbian 認證簽名”進行測試之前,務必確保已經在實際電話設備上測試了您的程序。
4、 內存堆棧空間有限!應盡可能將對象放到內存堆中,而不要放到棧里。KERN-EXEC 3異常(panic)發生的主要原因之一就是棧的破壞/溢出。
5、 應用程序發生異常(panic)表明您的代碼中一定有錯誤。以下是一些主要的、常見的錯誤:
Ⅰ:忘記將非對象成員、被分配到堆的變量加到CleanupStack上。
Ⅱ:將成員變量放到CleanupStack上—這一點要千萬避免(在析構函數中將這些變量刪除就可以了)。
Ⅲ:“重復刪除”--例如,沒有正確的從CleanupStack上Pop()出已經被銷毀的對象,造成CleanupStack以后試圖再次刪除它。或者使用過一個對象之后將其刪除但忘記將其值設成NULL,從而在析構函數里又試圖刪除一次。
Ⅳ:用可能不存在于您的析構函數中的變量調用函數。例如,以下代碼可能導致異常因為有可能您在分配內存之前您的對象已經被銷毀,或者在應用程序的另一處已經刪除了該內存,這樣iSomeServer就會處于NULL:
CMyClass::~CMyClass()
{
iSomeServer->Close();
delete iSomeServer;
}
應該如下編寫該代碼:
CMyClass::~CMyClass()
{
If(iSomeServer)
{
iSomeServer->Close();
delete iSomeServer;
}
}
Ⅴ:在NULL指針上調用函數。
Ⅵ:函數調用另一個函數,而其使用的變量已經超出范疇,例如:
把一個棧變量傳送到一個異步函數的回調(callback)里。
6、 在系統資源不夠的情況下,得體的處理失效情況是非常重要的。最受限制的資源通常是系統RAM,因此您需要注意正確的處理內存不足的情況。采用“兩端構造方法”和如下所述的CleanupStack機制,對這種防御性編程來說是必不可少和極其重要的。
7、 對帶“R”字頭、具備Close()方法的類,總是使用CleanupClosePushL()。這將確保當Leave事件發生時,它們會被恰當的清除。例如:
RFile file;
User:LeaveIfError(file.Open(…));
CleanupClosePushL(file);
…
CleanupStack::PopAndDestroy(&file);
對用Release()或Destroy()的“R”類,亦可使用CleanupDeletePushL()及CleanupRelasePushL()來取代Close()。
8、
另外,請記住CleanupStack機制是可擴展的,面對所有Leave事件,都可以用它來有效的清除任何對象。即使您需要處理的是較復雜的情況,也不
應該忽略采用正規的清理機制。欲進一步了解TCleanupItem,請參閱Symbian OS Library文檔。
9、
倘若您意圖對HBufC變量重新分配資源,在清除它們之后,總是將其設為NULL。由于HBufC的資源分配或其再分配可能會導致Leave事件的發生,
從而可能會出現析構函數試圖刪除已經不存在的HBufC變量的情況。當然,對于任何由堆分配資源的變量而言都應如此,對HBufC變量采取此做法更是已經
成為普遍的使用模式。
10、 當必須采用自己的TRAP時,請忽略所有的報錯。常見的編碼錯誤是:
TRAPD(err, DoSomethingL());
If(err == KErrNone || err == KErrNotFound)
{
//Do something else
}
這意味著其他錯誤碼都被忽略。然而,倘若您非用上述模式不可,應采用Leave機制來處理其他錯誤:
TRAPD(err, DoSomethingL());
If(err == KErrNone||err == KerrNotFound)
{
//Do something else
}
else
User::Leave(err);
⒒、不要延遲將對象PushL()到CleanupStack上。所有新創建的對象(成員變量除外)應被立即壓入該堆棧。例如,下面的做法是錯的:
Void doExampleL()
{
CSomeObject* myObject1 = new (ELeave)CSomeObject;
CSomeObject* myObject2 = new (ELeave)CSomeObject;
…
//Do something here with the variables
CleanupStack::PushL(myObject1);
CleanupStack::PushL(myObject2);
//Do something more with the variables
…
CleanupStack::PopAndDestroy(2);
//myObject2,myObject1
}
因為myObject2的創建可能失敗,造成myObject1”懸”在那里不能被清理。應該這樣來實現:
Void doExampleL()
{
CSomeObject* myObject1 = new (ELeave)CSomeObject;
CleanupStack::PushL(myObject1);
CSomeObject* myObject2 = new (ELeave)CSomeObject;
CleanupStack::PushL(myObject2);
…
//Do something here with the variables
…
CleanupStack::PopAndDestroy(2);
//myObject2,myObject1
}
12、注意,那些名稱有大寫字母C結尾的函數(例如NewLC())會自動把其對象置于CleanupStack。您不應該自己來將這些對象壓入CleanupStack,否則該對象會入棧兩次。當您創建非成員變量并為其分配內存時,這些由C結尾的函數很有用。
13、“兩端構造方法”是Symbian OS內存管理的關鍵部分。基本原則是Symbian
OS中的構造函數或析構函數永遠不應該發生Leave。倘若一個C++構造函數Leave,構造過程未完成的對象得不到清理,因為還沒有生成指針指向該對
象。為此,Symbian
OS中的構造函數僅將該對象實例化,而后調用該對象的ConstructL()函數,在其中將成員數據實例化。一旦ConstructL()發生
Leave,標準的析構函數將被調用來清除所有至此已被成功分配的成員變量。在您的編碼中照用這一設計模式來防止內存泄漏,至為關鍵。當您寫每一行代碼
時,都應該問自己:“這一行代碼能否發生Leave?”假如回答為“是”,則應考慮“是否所有資源都將被釋放?”。
14、編碼中請勿使用_L()宏---而應使用_LIT()。_L()自Symbian OS
V5起已是“不推薦使用”(deprecated),它的問題在于它將調用TPtrC(const
TText*)構造函數,該構造函數會調用strlen()函數來計算該字串的長度。雖然這不會帶來額外的RAM開銷,卻會在運行時占用更多CPU周期。
相反,宏_LIT()直接創建了一個在編譯時就全部實例化的對象,節省了構造TPtrC的CPU開銷。當然,您首先應該考慮的是否應該使用硬編碼的字符串
常量,因為當您將來地方化(localize)您的程序時,這種常量類型的描述符(descriptor)可能需要重新編碼(我覺得作者這里寫的有問
題,_LIT()及_L()定義的是常量字符串,并非描述符,它不能夠用描述符的一些通用的方法,只有調用_LIT()和_L()重載的()運算符才會變
成const TDesC&類型的描述符,并使TDesC的一些通用方法可用---孫東風注)。
15、當在函數參數中使用描述符(descriptor)時,應缺省使用基類。在大多數情況下,以const TDesC&形式來傳遞描述符。對可修改的描述符,則應使用TDes&。
16、當在函數中傳遞或返回對象時,應確保如果您擁有該對象的所有權,您應負責將其清除!Symbian采取的約定是:函數中的指針表示所有權轉移到調用者,而使用引用則表示被傳遞對象的所有權仍屬于原所有者。
17、Active Objects是Symbian OS的重要特性之一。請仔細研究SDK文檔、Symbian Developer NetWork白皮書,以充分理解其工作原理。下面有一些有用的竅門:
Ⅰ:在RunL()內無需使用TRAP()。Active Scheduler本身會TRAP函數RunL()并在其發Leave時調用CActive::RunError()。
Ⅱ:為此,您應實現自己的RunError()函數來處理從RunL()的Leave事件。
Ⅲ:保證RunL()操作盡可能簡短。長時間運行的RunL()將阻塞其他Active Objects。
Ⅳ:總是實現DoCancel()函數,總是在AO析構函數中調用Cancel()。
18、您應盡可能利用Active
Object框架機制。對于使用電池供電的設備,在一個循環中緊密不斷地進行輪流檢測(polling)是極其不適當的,將帶來大量耗電。寫游戲時,對此
尤需特別注意,詳情參閱Symbian Developer Network網站的技術文檔:
www.symbian.com/developer/techli ... /XenGames_paper.pdf
19、ViewSrv 11異常對于繁忙運行的程序(例如游戲)是一個潛在的問題。當您的,或者其他任何程序中的ViewSrv
active object不能及時響應View
Server時就會導致此種異常。典型的最長回應時間是10-20秒。FAQ-0900有詳細解釋,FAQ-0920有針對如何避免此類問題的實用技巧。
二者均可從www3.symbian.com/faq.nsf網頁上的Symbian OS FAQ數據庫獲取。
20、您無需使用HBufC::Des()來進入一個HBufC對象。只需采用*操作符來為HBufC對象解除引用(dereference)。這對于向某個接受TDesC&(上文的推薦做法)的函數傳遞HBufC參數時尤其有用。
21、.當使用標準的程序.INI文件的功能時(即在您的應用UI類中使用
Application()->OpenIniFileLC();API時),確保將版本號信息寫入流(stream)中。這樣使您能夠在未來新版
本的程序中建立新的流,意味著即使某個最終用戶將來安裝您的軟件的新版本時,不會因為在舊的.INI文件中找不到正確配置或流時發生異常。
22.、在您的程序中實現框架類(framework
class)時要小心。應該始終從所提供的平臺相關的框架類中繼承。例如,對UIQ而言,不要從CQikAppUi繼承。所有的應用基類
(CQikAppUi、CQikApplication、CQikDocument)添加的功能支持更廣的框架范圍來保證應用程序正確運行。