|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
把上面两个对象连在一起把他们变成一个整体所有的CD操作都是通过这个类的这个需要仔细看文档了举个不恰当的例子就像三个人收拾衣服一个人负责衣服的存放位置(NSManagedObjectModel)一个人负责把衣服分类冬天穿夏天穿等(NSPersistentStoreCoordinator)本文作者:ScottGruby,PalmOS认证开辟职员
为何我要思索这个成绩?
作为一个临时处置PalmOS开辟的职员,我见证了PalmOS的成熟和开辟手艺的变更。几年前,开辟职员很体贴内存空间(仓库空间)的成绩,因而只管写小型、松散的代码。跟着使用程序可用内存的增添,内存不再是开辟职员最忧虑的成绩了。几年前,当Metrowerks入手下手同意开辟职员利用C++编程时(有一些限定),包含我自己在内的一些开辟职员因为“代码收缩”而不往利用它。当时候,因为设备上无限的可用空间,一些人以为面向对象/C++编程带来的代价不敷以抵消它所酿成的开支。我看到良多关于C和C++的争辩,以为C++增添了开支。而在我看来,C++会增添开支只是个感到成绩。
从当时起,事变有了很年夜的变更。新的设备带有大批的内存,这使我不能不从头思索利用C++。客岁,当我正在编写厥后的Mark/SpaceMail软件的时分,无机会利用了BrianHall开辟的一些C++类库。固然这些类库其实不像POL那样丰厚,并且还没有把盘算机课上传授的一切C++手艺都用上,但它的确坦荡了我的眼界,使我意想到在分歧的使用程序中重复利用这些类是何等的复杂。
象别的编程言语一样,利用C++一样有优弱点。我见过一些贸易代码,它们的作者以为一切程序都必需用C++完成。我以为这些开辟职员是方才从年夜学的盘算机系卒业的先生,想在一个PalmOS程序中把从黉舍学到的每样工具都用上。我以为在PalmOS上如许利用C++并非一个较好的办法。PalmOS编程某些部分很好地利用了C++,而有些部分其实不利用。相反,我看到一些代码利用十分复杂的C++特征来构造函数,而且能够很简单地会见到这些函数的大众变量。固然,一定有开辟职员分歧意这个概念。假如代码因为承继、虚函数等变得太庞大而没法了解的话,那末大概就不太合适利用C++了。我并非想成为一个C++专家,C++中的良多特征(好比,模板)我都还没有利用过。可是,因为处置了大批的PalmOS和C++的程序计划,我晓得即便是对C++最基础的利用,也能经由过程代码重用来加速开辟速率。
我发明在PalmOS使用程序中利用C++比利用C有以下次要长处:
- 代码重用。年夜多半开辟职员都编写过量个PalmOS使用程序,这些程序之间有良多不异的部分。没有来由一遍又一各处从头编写不异的代码。
- 一个bug一经修改,一切利用这个类的使用程序城市被修改。反之,假如一个类呈现一个bug,那末一切利用它的使用程序也会同时呈现此bug。在我的某些开辟中利用了基于TCP/IP协定的类库,只需修改了次要类中的毛病,就会影响一切利用它的使用程序。比方,Mark/SpaceMail和Mark/SpaceOnline都利用了一个大众的TCP类,如许,一个bug的修改将同时影响这两个产物。
- 数据和函数封装。我老是教训你们,在你们的使用程序中不该该利用全局变量。但是这类做法其实不实践,以是我会限定全局变量的利用,如许能进步代码的可读性,也更简单保护。把近似的功效封装成一个类,能进步代码的可读性。
在PalmOS和别的平台上利用C++另有其他的长处,下面只是我团体喜好利用C++的缘故原由。跟着PalmOS设备上可用内存的增添,我没发明利用C++有甚么害处。
用C写过量个数据库程序的人城市晓得,要一遍又一各处重写那些会见数据库的经常使用函数是何等单调。毫无疑问,你一定会把那些次要的数据库代码一遍又一各处复制、粘贴。这时候,利用C++仍是对照完善的办理计划。当第一次见到数据库类的完成时,我想这是对C++的最好利用。我这里有几个数据库类的完成,在这篇文章中,我将给出一个复杂的数据库类,来演示在使用程序中利用C++是何等简单的一件事。
本文中的代码能够在任何开辟情况中利用。这些代码是收费的,但还没有经由周全测试。写这篇文章的时分,我利用gcc在MacOSX上测试过这些代码。
让我们入手下手吧。PalmOSSDK中的年夜部分示例代码都会见了一个或多个数据库。对数据库的会见遍及全部程序,并且每一个程序用来会见数据库的函数都很类似。比方,示例Mail经由过程上面的代码来获得一笔记录:
ErrMailGetRecord(DmOpenRefdbP,UInt16index,MailDBRecordPtrr,
MemHandle*handleP)
{
MemHandlehandle;
MailPackedDBRecordPtrsrc;
handle=DmQueryRecord(dbP,index);
ErrFatalDisplayIf(DmGetLastErr(),"ErrorQueryingrecord");
src=(MailPackedDBRecordPtr)MemHandleLock(handle);
if(DmGetLastErr())
{
*handleP=0;
returnDmGetLastErr();
}
MailUnpackRecord(src,r);
*handleP=handle;
return0;
}
而示例Address的代码以下:
ErrAddrDBGetRecord(DmOpenRefdbP,UInt16index,AddrDBRecordPtrrecordP,
MemHandle*recordH)
{
PrvAddrPackedDBRecord*src;
*recordH=DmQueryRecord(dbP,index);
src=(PrvAddrPackedDBRecord*)MemHandleLock(*recordH);
if(src==NULL)
returndmErrIndexOutOfRange;
PrvAddrDBUnpack(src,recordP);
return0;
}
你们也看到了,这两个函数做的事变实践上是一样的。可是,它们在毛病反省时略微有一点区分。我嫌疑个中一个已经修正过,而另外一个却没有。假如这两个函数都被封装在类Cdatabase中,那末对个中一个的修正也会使用到另外一个上。如许,就不用在几个项目之间查找不异的bug,举行不异的修正。
我编写过的一切数据库会见程序差未几城市用到以下几个复杂的函数:翻开、封闭、查询纪录、创立纪录、删除纪录和排序。在对数据库举行处置时还会用到良多其他的函数,这里只是复杂先容一下除排序和创立纪录以外的函数。我们利用基础的Cdatabase类和固有的CmailDatabase类来演示重用类非常简单。记着,这只是个示例,也许其实不能间接用在您的程序中。别的,其他开辟职员都有分歧的编码作风,以分歧的体例构造类。这里只是用示例来演示C++类是怎样简化开辟历程的。只需编写完基础的Cdatabase类,一切的使用程序都可使用它。创立这个类必要一些工夫,但从这个类衍生其他类时会节俭更多的工夫。
Cdatabase类的头文件相似以下代码:
#ifndef__CDatabase_h__
#define__CDatabase_h__
#definenoRecordSelected0xFFFF
classCDatabase
{
public:
CDatabase(void);
~CDatabase(void);
ErrOpen(UInt32type,UInt32creator,UInt16mode,Char*name);
ErrRemoveRecord(UInt16recordIndex);
ErrRemoveCurrentRecord(void);
protected:
UInt32mType;
UInt32mCreator;
ErrCreate(Char*name);
private:
DmOpenRefmDatabaseRef;
UInt16mCurrentRecordIndex;
ErrQueryRecord(UInt16recordIndex,void*recordP,MemHandle*recordHandle);
ErrUnpackRecord(void*src,void*destination);
};
#endif
这个类的机关函数和析构函数都很直不雅。
//CDatabaseconstructor
CDatabase::CDatabase()
{
mCurrentRecordIndex=noRecordSelected;
mDatabaseRef=NULL;
mType=0;
mCreator=0;
}
//CDatabasedestructor
CDatabase::~CDatabase()
{
if(mDatabaseRef!=NULL)
{
(void)DmCloseDatabase(mDatabaseRef);
}
}
假如数据库处于翻开形态,析构函数会封闭它。在析构函数中封闭数据库而且确保删除用完的对象,如许能够包管数据库总能封闭。
我发明在年夜多半情形下,当翻开数据库时,假如数据库不存在,就必要创立一个。因而,Open办法思索了这一点,它会在数据库不存在的时分试图创立一个。
//CDatabaseopen
ErrCDatabase::Open(UInt32type,UInt32creator,UInt16mode,Char*name)
{
Errerr=errNone;
if(type==0||creator==0)
{
returndmErrCantFind;
}
mType=type;
mCreator=creator;
mDatabaseRef=DmOpenDatabaseByTypeCreator(type,creator,mode);
if(mDatabaseRef==NULL)
{
err=DmGetLastErr();
//Ifwecan"topenthedatabasebecauseitdoesn"texist,createit
if(err==dmErrCantFind)
{
err=Create(name);
if(err==errNone)
{
mDatabaseRef=DmOpenDatabaseByTypeCreator(type,creator,mode);
if(mDatabaseRef==NULL)
{
err=DmGetLastErr();
}
}
}
}
returnerr;
}
//Createthedatabasegivenaname
ErrCDatabase::Create(Char*name)
{
Errerr=errNone;
if(name==NULL)
{
returndmErrCantFind;
}
err=DmCreateDatabase(0,name,mCreator,mType,false);
returnerr;
}
关于熟习PalmOS数据库挪用的开辟职员来讲,这些代码无需注释。这一段代码次要是试图以指定的范例和创立者翻开数据库(固然,这一段代码没有处置必要会见一个或多个不异范例和创立者的数据库的情形,比方,从一组电子图书中读取数据)。这一段代码能够很好地用在AddressBook和Mail程序中。
一切利用数据库的使用程序都要会见数据库中的纪录。您会记得,在以只读的体例检索纪录时利用Query挪用。Cdatabase类的查询例程中,查询到纪录后会把它“解紧缩”。如AddressBook和Mail使用程序的示例所示,数据库中的纪录是以紧缩格局保留的,如许能够节俭空间。因为每一个数据库以分歧的办法对纪录举行紧缩息争紧缩,以是我只创立了一个通用的解紧缩例程,在AddressBook和Mail程序中将由类掩盖。
ErrCDatabase::QueryRecord(UInt16recordIndex,void*recordP,MemHandle*recordHandle)
{
void*src;
Errerr=errNone;
mCurrentRecordIndex=noRecordSelected;
if(mDatabaseRef==NULL)
{
returndmErrNoOpenDatabase;
}
*recordHandle=DmQueryRecord(mDatabaseRef,recordIndex);
if(*recordHandle==NULL)
{
returndmErrNotValidRecord;
}
src=MemHandleLock(*recordHandle);
if(src==NULL)
{
returndmErrIndexOutOfRange;
}
err=UnpackRecord(src,recordP);
if(err!=errNone)
{
MemHandleUnlock(*recordHandle);
}
mCurrentRecordIndex=recordIndex;
returnerr;
}
ErrCDatabase::UnpackRecord(void*src,void*dest)
{
Errerr=errNone;
returnerr;
}
我在基类中供应的最初一个办法用来删除纪录。必需起首创立纪录,然后才干删除。创立纪录的办法留给读者作为实习。
ErrCDatabase::RemoveRecord(UInt16inRecordIndex)
{
Errerr=errNone;
if(mDatabaseRef==NULL)
{
returndmErrNoOpenDatabase;
}
err=DmRemoveRecord(mDatabaseRef,inRecordIndex);
if(inRecordIndex==mCurrentRecordIndex)
{
mCurrentRecordIndex=noRecordSelected;
}
returnerr;
}
ErrCDatabase::RemoveCurrentRecord(void)
{
returnRemoveRecord(mCurrentRecordIndex);
}
这些函数其实不庞大,却演示了怎样在基类中增加复杂的毛病处置机制,如许就不至于全部程序都要举行一样的毛病处置。你们在本人的代码里也实行了毛病处置,是如许吗?因为RemoveRecord办法已处置了数据库援用为空的情形,以是就不必要每次挪用DmRemoveRecord的时分都往反省。
如今基类创立完成,本文剩下的部分将给出一个复杂的衍生类,这个类能够用在Mail使用程序中,而且在这个新类中可使用一些挪用。
要创建CmailDatabase类,只需掩盖一个办法(在本例中为UnpackRecord办法)。
#ifndef__CMailDatabase_h__
#define__CMailDatabase_h__
#include"CDatabase.h"
classCMailDatabase:publicCDatabase
{
private:
ErrUnpackRecord(void*src,void*destination);
};
#endif
UnpackRecord函数以下所示:
ErrCMailDatabase::UnpackRecord(void*inSrc,void*inDest)
{
Errerr=errNone;
MailPackedDBRecordPtrsrc=inSrc;
MailDBRecordPtrdest=inDest;
char*p;
dest->date=src->date;
dest->time=src->time;
dest->flags=src->flags;
p=&src->firstField;
//Getthe"subject"field.
if(*p)
{
dest->subject=p;
p+=StrLen(p)+1;
}
else
{
dest->subject=p;
p++;
}
//Etc.
returnerr;
}
正如你所看到的,只需很少的事情,就能够创立一个能翻开数据库并会见纪录的CmailDatabase类。在我们的主代码中,会见数据库的一切代码是:
gMailDatabase=newCMailDatabase;
gMailDatabase->Open(mailDBType,sysFileCMail,dmModeReadWrite,"MailDatabase");
利用终了后,只需删除对象便可:
deletegMailDatabase;
固然这个例子十分复杂,但它的确演示了为经常使用函数创立通用C++类的功效。要使这个类的功效对照周全,还要给它增加用于创立纪录、排序等的办法。别的,大概还要增加一个办法,用于把QueryRecord办法的前往值转换到准确范例,如许就不必每次挪用的时分都要举行转换了。
利用C++时有一些注重事项,本文还没有说起。它们包含:
- 非全局代码利用虚函数(年夜部分情形下做不到这一点)。
- 非常处置会占用分外内存。假如利用了C++非常处置,编译器将会为今生成分外的代码。假如不必要非常处置,就要确信在编译器中已封闭了这一项。
- 非常处置的范围性。在某些特定情形下,非常处置机制没法事情。比方,不克不及跳过OS挪用抛出非常(在事务处置函数中,不克不及跳过FrmDispatchEvent抛出非常然后再前往到主事务轮回)。
固然C++在PalmOS的开辟中有这么多长处,但遗憾的是年夜多半基础的PalmOS程序计划书本都没有说起C++。别的,示例代码大概会对C++举行反省修正,并简化代码。正如本文所演示的一样,最少有两个(也许更多)示例利用了反复的十分类似的例程(不完整不异)。只需熟习C++的利用办法,就没有来由不把它用在PalmOS的程序计划中。关于年夜部分代码而言,C++的代码复用和便利的数据封装这些基础利用都能使你受益不浅。
感激NeilRhodes、SteveLemke和BrianHall为本文举行考核和供应录进。
关于作者
ScottGruby是一个自力的软件开辟职员,他住在圣地亚哥。他处置PalmOS开辟事情已6年多了。从智能德律风开辟到电子邮件使用程序和键盘驱动程序的开辟,他做了大批的项目。假如你必要一个有履历的开辟职员或是一个用户界面的专家,他是一个很符合的互助者。经由过程palmdeveloper@gruby.com能够接洽到作者。
打开.xib的文件打开的就是IBIB和代码交互用的是IBActionIBOutlet这些标记这些标记追踪到他们的定义其实对编译器来说什么都不表示 |
|