390 likes | 410 Views
Programming mobile devices. Part II Programming Symbian devices with Symbian C++. Basic Symbian programming. Content of this part. Basic Data Types Classes Error handling Cleanup Panics Libraries. Basic Data Types. TInt, TUint integer, natural word length
E N D
Programming mobile devices Part II Programming Symbian devices with Symbian C++ Basic Symbian programming
Content of this part • Basic Data Types • Classes • Error handling • Cleanup • Panics • Libraries
Basic Data Types • TInt, TUint integer, natural word length • TInt8, TInt16, TInt32 integers of 8b,16b... • TUint8, TUint16, TUint32 unsigned integers of 8b,16b and 32b • TInt64 64 bit integer with operators(+,-,...) • TText8, TText16, TText characters • TChar A character class with several methods for manipulating
Basic Data Types • TBool ETrue / EFalse • TReal32, TReal64, TReal floating point numbers (TReal64 and TReal map to double) • TAny like void, used in situations other than return values of functions
Classes • 4 main gategories with agreed prefixes • T for data type classes (e.g. TInt) • C for Heap allocated classes (these inherit from CBase class) • R for Resource classes (which reserve resources) • M for Interface classes
Data Type Classes • Encapsulate basic data types, such as TInt and int • Usually have methods for manipulating the data • e.g. TChar.loweCase() • Comparison usually implemented • Used instead of basic data types
Heap Classes • All inherit from the CBase class • Instantiated on the heap (using the new operation) • CBase has a virtual destructor (A heap class hence has to implement it) • zero initialization to all members
Resource classes • Control resources owned by someone else • e.g. client in a client/server communication • usually allocated on the stack • for example: RFile, RSocket, RThread • Pointers to a resource, deleting the class does not usually delete the resource • A resource has a reference count (How many pointers point to it)
Interface classes • M for Mixin • Abstract classes that define interfaces • No member variables • Methods usually pure virtual • Note: Even though multiple inheritance is possible in C++, in Symbian programminig it is usually used only through interfaces. • Basically: use interfaces as in Java
Errors and Exceptions • Handling errors and exceptions is utterly important in mobile phone apps. • Sources of exceptions are vast; out of memory, incoming call, empty battery... • Users have high expectations of robustness of the phones and the software on them.
Return Codes • Function's return value tells the result of excecution • KErrNone -success • Others include an error code that tells what went wrong, e.g. KErrNoMemory • Used extensively in the APIs • Still, not the best possible error handling mechanism. why ?
Leave/Trap • Corresponding to Javas try-catch and C++ throw-catch, Symbian has a mechanism called leave-trap • leave is like throw in java • trap is similar to catch • The mechanism is also familiar, a leave "bubbles" up the call stack like in java until it is handled by a trap (if ever)
Leave • Programmer can call User::Leave(KErrorCode); which corresponds to throw(Exception) in java • The execution of that function is stopped immediately and the control returns to the calling code. • Also an API function can (and most do) leave.
Trap • Trapping is done with a marco TRAP (or TRAPD). • The code is executed onward from the next line after a TRAP (stops "bubbling") • The macro takes 2 parameters: a TInt to store the leave code and the name of the function to be executed TInt LeaveResult; TRAP(LeaveResult, func1());
Example code void func1() { TInt result; result = somefunc(); if(result) { User::Leave(KSomeError); } } void TestFunc() { TInt LeaveResult; TRAP(LeaveResult, func1()); if(LeaveResult) { // Leave happened in func1() that has to be handled } }
Example code void func1() { TInt result; result = somefunc(); if(result) { User::Leave(KSomeError); } } void TestFunc() { TRAPD(LeaveResult, func1()); // Defines LeaveResult if(LeaveResult) { // Leave happened in func1() that has to be handled } }
Trap return values • If leave does not occur KErrNone, integer 0 is returned. • In trap, the return value of the function can also be saved: TRAPD(LeaveResult, resval = func1());
Leave functions • User:: namespace has a set of static API leave functions: • User::Leave(leavecode); • User::LeaveNoMemory(); //KErrNoMemory • User::LeaveIfError(leavecode); // If leavecode is negatice, leave with error as the reason. • User::LeaveIfNull(TAny *pointer); //KErrNoMemory as the reason
The L suffix • Symbian uses a convention to use a suffix L in functions that may leave • This is to signal the programmer that it may be necessary to trap such a function • Unless trapped, the code to follow might not be executed
A couple words about memory • In contrast to Java, in C++ you must actively free any memory you have allocated. • Not doing so will result in leaking of memory. • Usually you use new to generate new objects and delete to destroy them • Also, it is a good practice to set pointers to null after they no longer point to an object
Leaving and memory What if? void func1() { CSomeObject *testObj = new CSomeObject; TInt result = testObj.somefunc(); // which may leave delete testObj; testObj = null; } void TestFunc() { TRAPD(LeaveResult, func1()); // Defines LeaveResult if(LeaveResult) { // Leave happened in func1() that has to be handled } }
Cleanup • Obviously, we have a problem • Since leave can result in skipping some code, we must be careful with allocated memory not to have code that leaks • In previous example testObj is an automatic variable that goes out of scope when func1 exits • Result: the created object is left in the memory and cannot be deleted
Cleanup stack • The solution to our problem is something called a cleanup stack • It can be thought of a storage of pointers to created objects (which might otherwise be lost) • Think of it as a memory accounting device • push • pop
Cleanup stack • Items that must be cleaned are pushed into the stack • If leave occurs, these items are automatically popped from the stack and deleted • If no leave occurs, you must pop the items yourself • Watch out for double deletion
An example void myTestfunc() { CTestObj *obj = new CTestObj(); CleanupStack::PushL(obj); MyOtherFuncL(); // may leave CleanupStack::Pop(); delete obj; }
An example void myTestfunc() { CTestObj *obj = new CTestObj(); CleanupStack::PushL(obj); MyOtherFuncL(); // may leave CleanupStack::PopAndDestroy(); delete obj; // WRONG! obj already deleted }
Creating a cleanup stack • Cleanup stack is automatically created for GUI applications • For your own threads you have to create the cleanup stac yourself • CTrapCleanup *clstack = CTrapCleanup::New() • remember to delete the stac when finished • delete clstack;
Object types • PushL(CBase *) • delete is called when object is popped • calls the destructor of the derived class • PushL(TAny *) • User::Free() is called when object is popped • destructor is not called
What if PushL leaves? • What if there is no space in the stack? • Symbian always keeps at least one free spot on the cleanup stack. • If the PushL leaves, the pushed item will still be pushed to the stack • Allocating the next slot may fail resulting PushL leaving
Complex cleanup • Sometimes we have objects that require more complex cleanup than just delete • PushL(TCleanupItem userCleanup) • TCleanupItem is a wrapper class for a function that handles cleanup
Other cleanup functions • CleanupClosePushL <class T>(T& obj) • Pop calls obj.Close() • used mainly for R classes, which require Close() to be called • CleanupReleasePushL<class T>(T& obj) • calls Release()
Other cleanup functions • CleanupDeletePushL <class T>(T& obj) • Using templates, the pop function calls the actual destructor of the object regardless of the type of the object • Hence, the object doesn't have to be derived from CBase • you should use this for all non CBase derived classes that have a destructor.
Templates • Were created to make function code re-use possible (instead of just overloading functions) • Templates basically achieve the same as a superclass in Java
LC functions • LC suffix denotes functions that automatically push a reference of a created object to the cleanup stack • For example: User::AllocLC(100) allocates memory and pushes a pointer to the cleanupstack • No need for User::PushL(...)
Leave in object creation • The new operation may fail due to inadequate memory. • You can use a ELeave when calling the constructor to assure that leave occurs if object creation (new operation) fails • CMyObject *obj = new (ELeave) CMyObject; • Constructor itself should never leave (why?)
Two phase constructors • After creating the object with new we call a constructor function which may leave • This call can be trapped • Often we name this function as ConstructL
ConstructL void testL() { CTestObj *o = new (ELeave) CTestObj; CleanupStack::PushL(o); o->ConstructL(); ... }
Panics • Don' t panic • The operating system may do that. • An unrecoverable error that causes the thread to finish • User::panic(const TDes &Category, TInt reason) • On the device the execution ends and the device shows a dialog box
Libraries • static (linked at build) • DLLs (Dynamic Link Library) • loaded and linked at runtime • one copy is shared by multiple programs