|
1 - 30/4/2013 18:44 - ClubeDelphi - POO - Dominando o uso de Interfaces - Revista Clube Delphi 134
|
|
VITOR RUBIO
|
Na verdade eu cometi um erro aqui, além de ter me expressado mal. Não é quando você converte (objeto as Interface).Metodo que ocorrem erros, e sim quando você converte um objeto para uma interface passando a variável interface para um método.
Quando se chega ao final do método o contador de referencias da interface chega a zero, porque ele não conta com a referência armazenada na variável objeto FORA do escopo da função. Sendo assim o free é chamado e o objeto destruido prematuramente.
Isso acontece quando você faz algo como:
var
objAviao: TAviao;
objCarro: TCarro;
objBarco: TBarco;
UmObjetoQualquer: TInterfacedObject;
OutroVeiculo: IVeiculo;
OutroCarro: ICarro;
OutroBarco: IBarco;
UmSerVivo: ISerVivo;
begin
//cria os objetos e os mantem com referencia em uma variavel do tipo objeto
objaviao:= TAviao.Create;
objCarro:= TCarro.Create;
objBarco:= Tbarco.Create;
UmObjetoQualquer := TCarro.Create;
//não se deve fazer isso direto com os objetos a não ser que exista uma interface apontando para eles
//fazendo isso o contador de referencia pode zerar
FazVeiculoAndar(objaviao); //saindo do escopo dessa função o argumento atinge refcount zero, destruindo objaviao sem ligar para sua referencia objaviao fora da função
FazVeiculoAndar(objCarro); //saindo do escopo dessa função o argumento atinge refcount zero, destruindo objCarro sem ligar para sua referencia objCarro fora da função
FazVeiculoAndar(objBarco); //saindo do escopo dessa função o argumento atinge refcount zero, destruindo objBarco sem ligar para sua referencia objBarco fora da função
//a partir daqui os objetos não funcionam mais porque o contador de referência foi zerado enquanto o objeto foi
//convertido para interface
objAviao.Voar;
objCarro.Rodar;
objBarco.Velejar;
//a partir daqui o erro pode ocorrer a qualquer momento
(objAviao as IAviao).Voar;
(objCarro as ICarro).Rodar;
(objBarco as IBarco).Velejar;
(UmObjetoQualquer as ICarro).Rodar;
Mas o certo seria criar algo como:
var
aviao: IAviao;
carro: ICarro;
barco: IBarco;
OutroVeiculo: IVeiculo;
begin
//conversão objeto/interface
aviao := TAviao.Create;;
carro := TCarro.Create;
barco := Tbarco.Create;
//isso seria o correto
FazVeiculoAndar(aviao);
FazVeiculoAndar(carro);
FazVeiculoAndar(barco);
aviao.Voar;
carro.Rodar;
barco.Velejar;
No meu código original eu tentei mostrar em um mesmo botão a maneira certa e errada de se fazer isso, deixando parte do código comentado, e isso não ficou muito didático. Eu mesmo me enrolei depois de ler.
Separei esse código em 2 botões, sendo o antigo button3 o modo incorreto, e o novo button8 o método correto. O novo exemplo pode ser baixado em: http://www.vitorrubio.com.br/downloads/CD134_Interfaces_V2_Reformulado.zip
|
Responder |
|
|
2 - 30/4/2013 16:43 - ClubeDelphi - POO - Dominando o uso de Interfaces - Revista Clube Delphi 134
|
|
VITOR RUBIO
|
Boa tarde "Softplan". Preciso ver um trecho do seu código e saber qual versão do Delphi você está usando, mas basicamente nesses casos o comportamento esperado seria um erro.
Pode acontecer de o objeto continuar acessível na memória, ou pelo menos alguns métodos que não usem dados internos do objeto, mas esse comportamento não é o esperado e é causado simplesmente por "sujeira" na memória.
Fiz um teste aqui e também funcionou, mesmo assim eu não recomendo. Diferenças na versão do Delphi ou na plataforma podem ocasionar erros.
Na época em que escrevi esse artigo eu usava Delphi XE em um computador de 64 bits, mas não me lembro a versão do Windows.
Hoje fiz o teste tanto no Delphi XE como no Delphi XE 4 usando Windows 7, mas num computador de 32 bits.
O porquê de eu esperar que essa construção cause um erro eu explico:
Dado que interfaces contam referências, então são "Reference Counted" e dado que você cria, converte e usa um objeto dentro de um mesmo método (como o evento click de um botão).
Se você criar o seu objeto já atribuindo ele à uma variável do tipo interface, assim:
var i: ICarro;
begin
i:= TCarro.Create; //1 referencia a um TCarro
(i as ICarro).DeslocarSe; //2 referencias ao TCarro //não precisa disso, apenas mostro como funciona normalmente
i.OutroMetodo;
end; //final do método, 0 referencias ao mesmo TCarro, então o objeto "hospedado" em I é destruido com free.
É esperado que um objeto apresente erro nesse tipo de conversão principalmente quando ele possui outro objeto dentro. Considere um objeto que tenha um StringList como um de seus campos.
var i: TCarro;
begin
i:= TCarro.Create; //1 referencia a um TCarro, no entanto I é um objeto, portanto não conta referências
(i as ICarro).DeslocarSe; //1 referencias ao TCarro hospedado em I convertido para ICarro
i.OutroMetodo; //antes de chegar aqui já temos 0 referências (pois não existe mais a referência temporária que estava sendo usada na conversão para ICarro), portanto Free é acionado e o objeto em I é destruído "por engano". Aqui deve ocorrer um erro ao se executar OutroMetodo, pois o próprio objeto está destruído .
end;
Veja esse exemplo que eu criei no Delphi Xe 4: (em www.vitorrubio.com.br/downloads/TesteInterfaces.zip)
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
IVeiculo = interface (iinterface)
['{1D2F0F1D-60CC-47BE-AD22-4DA59D87C7CA}']
procedure DeslocarSe;
procedure Parar;
end;
IVeiculoTerrestre = interface (IVeiculo)
['{CD718BB9-FE3A-4C19-8CE2-01EBB1843B96}']
procedure DeslocarSe;
procedure Parar;
procedure Rodar;
end;
ICarro = interface (IVeiculoTerrestre)
['{3B167780-8EA0-4F59-9DBF-A9F68F54F595}']
procedure DeslocarSe;
procedure Parar;
procedure Rodar;
end;
//TCarro = class(TInterfacedObject, ICarro) //nessa forma você pode atribuir a criação de um TCarro a uma variável ICarro, IVeiculoTerrestre e IVeiculo, mas não pode fazer conversões do tipo AS entre eles
TCarro = class(TInterfacedObject, ICarro, IVeiculoTerrestre, IVeiculo) //esta forma permite qualquer tipo de atribuição e conversão.
private
FPlaca: TStringList;
function GetPlaca: string;
procedure SetPlaca(value: string);
public
constructor Create;
destructor Destroy; override;
procedure DeslocarSe;
procedure Parar;
procedure Rodar;
property Placa: string read GetPlaca write SetPlaca;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TCarro }
constructor TCarro.Create;
begin
FPlaca := TStringList.Create;
end;
procedure TCarro.DeslocarSe;
begin
ShowMessage(Placa + ' Deslocando-se. ' + self.RefCount.ToString() + ' referências');
end;
destructor TCarro.Destroy;
begin
FPlaca.Free;
inherited;
end;
function TCarro.GetPlaca: string;
begin
Result := FPlaca.Text;
end;
procedure TCarro.Parar;
begin
ShowMessage(Placa + ' Parando.' + self.RefCount.ToString() + ' referências');
end;
procedure TCarro.Rodar;
begin
DeslocarSe;
end;
procedure TCarro.SetPlaca(value: string);
begin
FPlaca.Text := value;
end;
procedure TForm1.Button1Click(Sender: TObject);
var C: TCarro;
begin
C := TCarro.Create; //tenho um objeto, mas C não conta referencias
C.Placa := 'ABC1234';
(C as ICarro).Rodar; //converte e roda na mesma linha, mas zera o contador de referencias na proxima linha
C.Parar; //isso dá erro
C.Rodar;
C.Parar;
end;
procedure TForm1.Button2Click(Sender: TObject);
var C: TCarro;
I: IVeiculoTerrestre;
begin
C := TCarro.Create; //tenho um objeto, mas C não conta referencias
C.Placa := 'ABC1234';
I := (C as ICarro); //Conversão joga para I o controle da contagem de referencias
I.Rodar; //uso normal
I.Parar; //uso normal
I.Rodar; //uso normal
I.Parar; //uso normal
C.Rodar; //Funciona normal, mas não se deve misturar objetos comuns com interfaces, por isso para de usar C uma vez convertido para I
C.Parar; //Funciona normal, mas não se deve misturar objetos comuns com interfaces, por isso para de usar C uma vez convertido para I
end;
procedure TForm1.Button3Click(Sender: TObject);
var C: TCarro;
I: IVeiculo;
begin
C := TCarro.Create; //tenho um objeto, mas C não conta referencias
C.Placa := 'ABC1234';
I := (C as ICarro); //Conversão joga para I o controle da contagem de referencias
I.DeslocarSe;
I.Parar;
//I agora pode ser convertido para qualquer uma das interfaces ancestrais de ICarro sem perder o controle de referência
(I as ICarro).Rodar;
(I as ICarro).Parar;
(I as IVeiculoTerrestre).Rodar;
(I as IVeiculoTerrestre).Parar;
(I as IVeiculo).DeslocarSe;
(I as IVeiculo).Parar;
C.Rodar; //Funciona normal, mas não se deve misturar objetos comuns com interfaces, por isso para de usar C uma vez convertido para I
C.Parar; //Funciona normal, mas não se deve misturar objetos comuns com interfaces, por isso para de usar C uma vez convertido para I
end;
procedure TForm1.Button4Click(Sender: TObject);
var C: TCarro;
iv1, iv2: IVeiculo;
ivt1, ivt2: IVeiculoTerrestre;
ic: ICarro;
begin
C := TCarro.Create;
C.Placa := 'ABC1234';
ic := (C as ICarro);
ivt1 := (C as IVeiculoTerrestre);
iv1 := (C as IVeiculo);
ivt2 := (ic as IVeiculoTerrestre);
iv2 := (ic as IVeiculo);
ic.DeslocarSe;
ic.Parar;
ivt1.Rodar;
ivt1.Parar;
iv1.DeslocarSe;
iv1.Parar;
ivt2.Rodar;
ivt2.Parar;
iv2.DeslocarSe;
iv2.Parar;
end;
procedure TForm1.Button5Click(Sender: TObject);
var C: TCarro;
iv1, iv2: IVeiculo;
ivt1, ivt2: IVeiculoTerrestre;
ic: ICarro;
begin
C := TCarro.Create;
C.Placa := 'ABC1234';
ic := (C as ICarro);
ic.DeslocarSe;
ic.Parar;
if Supports(c, IVeiculoTerrestre, ivt1) then
begin
ivt1.Rodar;
ivt1.Parar;
end;
if Supports(c, IVeiculo, iv1) then
begin
iv1.DeslocarSe;
iv1.Parar;
end;
if Supports(ic, IVeiculoTerrestre, ivt2) then
begin
ivt2.Rodar;
ivt2.Parar;
end;
if Supports(ic, IVeiculo, iv2) then
begin
iv2.DeslocarSe;
iv2.Parar;
end;
end;
procedure TForm1.Button6Click(Sender: TObject);
var C: TCarro;
iv1, iv2: IVeiculo;
ivt1, ivt2: IVeiculoTerrestre;
ic: ICarro;
begin
C := TCarro.Create;
C.Placa := 'ABC1234';
ic := ICarro(C);
ivt1 := IVeiculoTerrestre(C);
iv1 := IVeiculo(C);
ivt2 := IVeiculoTerrestre(ic);
iv2 := IVeiculo(ic);
ic.DeslocarSe;
ic.Parar;
ivt1.Rodar;
ivt1.Parar;
iv1.DeslocarSe;
iv1.Parar;
ivt2.Rodar;
ivt2.Parar;
iv2.DeslocarSe;
iv2.Parar;
end;
end.
Ele
Ele não deu erro como eu esperava no primeiro botão, mesmo assim eu não aconselho a fazer um uso de interfaces + objetos como aquele, principalmente quando seus objetos são passados para métodos ou retornados deles.
Infelizmente não consegui reproduzir esse erro hoje. Compilei e rodei esse código no Delphi XE, no Delphi XE4 e no Lazarus, e em todos os casos funcionou.
Mesmo assim, cuidado redobrado ao se passar variáveis do tipo interface como parâmetros.
|
Responder |
|
|
3 - 30/4/2013 08:49 - ClubeDelphi - POO - Dominando o uso de Interfaces - Revista Clube Delphi 134
|
|
SOFTPLAN PLANEJAMENTO E SISTEMAS LTDA
|
Fiquei com uma dúvida na seguinte afirmação:
"Na Listagem 5 a linha (UmObjetoQualquer as ICarro).DeslocarSe cria uma referência a uma interface Icarro durante a conversão que não existirá mais depois da conversão, depois da execução do método, o que fará com que o objeto UmObjetoQualquer seja destruído."
Fiz o teste aqui e o objeto ainda continua existindo. Não seria o correto?
|
Responder |
|
|
4 - 21/1/2013 19:15 - ClubeDelphi - Criando uma deskbar - Revista Clube Delphi 134
|
|
VITOR RUBIO
|
Infelizmente o stayontop não funcionárá, pois a janela da deskbar ficará na frente da janela maximizada, ocultando uma parte.
|
Responder |
|
|
5 - 21/1/2013 19:14 - ClubeDelphi - Criando uma deskbar - Revista Clube Delphi 134
|
|
VITOR RUBIO
|
Infelizmente eu não sei como o google desktop faz isso. Teria que pesquisar.
Faço uma vaga ideia. Se você tiver o handle de uma janela, obtido com a função GetWindow ou FindWindow, você pode redefinir o tamanho da janela e o estado dela, mesmo se não for uma janela do seu programa.
É bastante trabalhoso encontrar o tamanho máximo, subtrair o tamanho da sua barra e redimensionar todas as outras janelas maximizadas.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633499(v=vs.85).aspx
|
Responder |
|
|
6 - 21/1/2013 08:14 - ClubeDelphi - Criando uma deskbar - Revista Clube Delphi 134
|
|
PAULO QUICOLI
|
Você tentou setar a propriedade FormStyle para fsStayOnTop ?
Abraço
|
Responder |
|
|
7 - 19/1/2013 14:47 - ClubeDelphi - Criando uma deskbar - Revista Clube Delphi 134
|
|
Vinícius Valle
|
Muito bom o artigo, mas como eu faria para deixar esta barra sempre visível, forçando o recurso maximizar de outros aplicativos a não cobrir esta (como o google desktop faz, por exemplo)?
|
Responder |
|
|
8 - 14/5/2012 07:44 - ClubeDelphi - Integre projetos .NET e Win32 - Artigo ClubeDelphi 128
|
|
VITOR RUBIO
|
Carlos, desculpe a demora em responder.
Sempre que você adiciona a referencia a uma DLL do tipo COM/ActiveX é criada automaticamente uma DLL com o mesmo nome e um ".interop". Essa faz o "meio de campo" entre as tecnologias COM e .Net.
Geralmente adicionar a referencia é tudo que se precisa, mas você chama seus objetos e funções através do nome da dll original mesmo, não da interop.
A sua DLL tem os métodos públicos e a guid? Pode postar aqui seu projeto para analisarmos?
|
Responder |
|
|
9 - 12/5/2012 12:56 - ClubeDelphi - Integre projetos .NET e Win32 - Artigo ClubeDelphi 128
|
|
WESLEY YAMAZACK
|
Olá Carlos, sua dúvida foi encaminhada para o autor, peço que aguarde um pouco para que ele possa te atender.
Um abraço.
|
Responder |
|
|
10 - 14/4/2012 14:29 - ClubeDelphi - Integre projetos .NET e Win32 - Artigo ClubeDelphi 128
|
|
Carlos Cesar D. Campos
|
Quando coloco 'add reference' no Delphi Prism apontando uma DLL criada no Delphi XE (dll criada via objeto com) está vindo c/ o nome de Interop.Com.dll e não consigo acesso a classe para retornar o resultado. Alguém já teve esse problema?
|
Responder |
|
|
11 - 28/2/2012 17:58 - Easy .net magazine - Visual Studio: Introdução - Easy .net magazine 2
|
|
WESLEY YAMAZACK
|
Olá Marcio , tudo bem ?
Sobre a sua solicitação enviamos agora mesmo um e-mail para editor chefe da revista. Assim que obtivermos uma resposta entramos em contato com você novamente, tudo bem pra você?
Obrigado pela ideia.
Um abraço
|
Responder |
|
|
12 - 26/2/2012 00:23 - Easy .net magazine - Visual Studio: Introdução - Easy .net magazine 2
|
|
Marcio Pereira de Lima
|
Gostei da vídeo aula de tratamento de erros. Mas gostaria de ver uma aula com os tratamentos de erros que estão disponíveis na IDE do Visual Studio. Obrigado.
|
Responder |
|
|
13 - 18/11/2011 09:56 - ClubeDelphi - POO - Dominando o uso de Interfaces - Revista Clube Delphi 134
|
|
Fernanda Lopes
|
Obrigada, vou fazer os testes e qualquer coisa reportarei aqui.
|
Responder |
|
|
14 - 17/11/2011 10:46 - ClubeDelphi - POO - Dominando o uso de Interfaces - Revista Clube Delphi 134
|
|
VITOR RUBIO
|
Então Fernanda, esse código não funciona com Delphi 7, pois o Delphi 7 não aceita operadores IS e AS para conversões Interface --> Objeto, apenas para Objeto --> Interface.
O que você pode fazer é um typecast forçado, tipo:
var o: TObject; o := TObject(minhainterface);
//operações com O agora podem usar is e as
mas cuidado: a linha o := TObject(minhainterface) cria uma nova referencia a uma instância já existente que não será contada pelo contador de referencias da interface. Se algum método ou trecho de código atribuir nil à minhainterface zerando o contador de referências a instância será destruida antes da hora e "o" terá uma referência inválida. Faça testes para verificar leaks ou corrupção de memória com o Fast Memory Manager 4 e não use o método Free em "o".
|
Responder |
|
|
15 - 17/11/2011 09:06 - ClubeDelphi - POO - Dominando o uso de Interfaces - Revista Clube Delphi 134
|
|
Fernanda Lopes
|
Estou usando o Delphi 7 e usei também GUID.
|
Responder |
|
|
16 - 9/11/2011 15:29 - ClubeDelphi - POO - Dominando o uso de Interfaces - Revista Clube Delphi 134
|
|
VITOR RUBIO
|
Fernanda, boa tarde. Qual é a versão do seu Delphi? Algumas particularidades dos operadores "is" e "as" no sentido interface --> objeto passaram a funcionar apenas no Delphi XE.
Além disso a interface deve obrigatoriamente ter um GUID para que os operadores is e as funcionem com ela.
|
Responder |
|
|
17 - 8/11/2011 18:41 - ClubeDelphi - POO - Dominando o uso de Interfaces - Revista Clube Delphi 134
|
|
Fernanda Lopes
|
Tenho uma dúvida sobre a Matéria de Interface:
Fui tentar fazer exatamente como é mostrado nas listagens apresentadas para exemplos e dá erro quando tento compilar o código da 'listagem 5' da página 49, na seguinte parte:
-> if (aviao is TAviao) then begin ShowMessage('Avião é um TAviao'); (aviao as TAviao).DeslocarSe; end;
O Delphi apresenta a seguinte mensagem de erro: Operator not applicable to this operand type
Se alguém puder me ajudar me explicando o porquê disso, agradeço.
|
Responder |
|
|
18 - 27/10/2011 19:14 - ClubeDelphi - Usando o Padrão Singleton - Revista ClubeDelphi 133
|
|
VITOR RUBIO
|
Corrigi e comentei alguns aspectos do seu singleton. Você pode fazer assim:
unit singleton;
interface
uses sysutils;
type TSingleton = class private FCreationTimeStamp:string; public class function GetInstance: Tsingleton; class function NewInstance: TObject; override; procedure FreeInstance; override; function DoSomethingImportant: string; end;
procedure FreeFirstNilAfter(var Obj); //MeuFreeAndNilBom procedure FreeFirstNilAfterOneReference(var Obj); //OutroFreeAndNilBom
implementation
var //Se o Delphi 2007 não suportasse class vars tudo bem colocar esse campo aqui, mas creio que ele suporta: //consulte os sites: //http://www.marcocantu.com/md2005/UpdateDelphi2006_ch04.html //http://hallvards.blogspot.com/2007/05/hack17-virtual-class-variables-part-i.html //http://edn.embarcadero.com/article/34324 //https://forums.embarcadero.com/thread.jspa?threadID=24246 _Instance: Tsingleton; //eu aconselho a colocar FCreationTimeStamp como um campo de instância privado pois ele é parte intrinseca da lógica de negócio //da instância do singleton. Ele não faz sentido fora da classe e não tem porque ser uma variável estática global. //lembre-se que ele é usado apenas em DoSomethingImportant, que é um método de instância. //como NewInstance é um método de classe inicialize FCreationTimeStamp apenas no Create. //se quiser continuar usando no escopo global de implementation use outro prefixo no lugar de F, pois F é para fields de classes. //usa-lo no NewInstance também é possível como abaixo, mas lembre-se que FCreationTimeStamp é apenas um exemplo que significa uma //propriedade, valor ou recurso do seu negócio, e DoSomethingImportant é algo importante que só o seu singleton pode fazer. //FCreationTimeStamp:string;
class function Tsingleton.GetInstance: Tsingleton; begin // inherited Create; // Result := _Instance;
// essa parte pode ficar assim: Result := inherited Create; // Lembre que chamar Create é como chamar um atalho "especial" para NewInstance, ou seja, já está jogando _Instance no Result end;
class function Tsingleton.NewInstance: TObject; begin if _Instance = nil then begin _Instance := (inherited NewInstance as Tsingleton); //se quiser continuar sem um construtor atribua o valor a FCreationTimeStamp depois de instanciar, e precedido de _Instance _Instance.FCreationTimeStamp:= FormatDateTime('ddmmyyyy_hhnnsszzz', now); end; Result := _Instance; end;
function Tsingleton.DoSomethingImportant: string; begin Result := 'Instância de ' + Self.ClassName + ' Criada em ' + FCreationTimeStamp + ' no endereço ' + IntToStr(integer(self)); end;
procedure Tsingleton.FreeInstance; begin //destruirá apenas quando for permitido if _Instance <> nil then begin inherited FreeInstance; _Instance := nil; end; end;
procedure FreeFirstNilAfter(var Obj); //MeuFreeAndNilBom var Temp: TObject; begin Temp := TObject(Obj); //primeiro joga a instancia num objeto temporario Temp.Free; //invoca free na segunda referência, temporária, que será liberada Pointer(Obj) := nil; //nulifica a variável por último end;
procedure FreeFirstNilAfterOneReference(var Obj); //OutroFreeAndNilBom begin TObject(Obj).Free; //invoca free Pointer(Obj) := nil; //nulifica a variável end;
initialization
finalization //não se esqueça da seção initilization e finalization para que o //singleton possa ser de fato destruido if _Instance <> nil then begin FreeFirstNilAfter(_Instance); //funciona //FreeFirstNilAfterOneReference(_Instance); //funciona //FreeAndNil(_Instance); //não funciona //_Instance.Free; //_Instance := nil; end; //FreeAndNil(_Instance); //não funciona //nunca use FreeAndNil aqui pois freeandnil atribui nil à referência antes //de efetivamente destruir a instância, o que causaria leak e faria FreeInstance falhar //use free e depois atribua nil
{ isso é curioso, veja o source de freeandnil:
procedure FreeAndNil(var Obj); var Temp: TObject; begin Temp := TObject(Obj); //primeiro joga a instancia num objeto temporario Pointer(Obj) := nil; //nulifica a variável e perde a referencia antes de invocar free Temp.Free; //invoca free na segunda referência, temporária, que será liberada end;
como FreeAndNil poderia ser:
procedure FreeFirstNilAfter(var Obj); //MeuFreeAndNilBom var Temp: TObject; begin Temp := TObject(Obj); //primeiro joga a instancia num objeto temporario Temp.Free; //invoca free na segunda referência, temporária, que será liberada Pointer(Obj) := nil; //nulifica a variável por último end;
ou
procedure FreeFirstNilAfterOneReference(var Obj); //OutroFreeAndNilBom begin TObject(Obj).Free; //invoca free Pointer(Obj) := nil; //nulifica a variável end;
}
end.
{ Considere o exemplo 5 do artigo, ele pode servir para você: unit singleton5;
interface
uses sysutils;
type Tsingleton5 = class strict private class var _Instance: Tsingleton5; class var _PodeDestruir: boolean; FCreationTimeStamp: string; class destructor Destroy; class constructor Create; public class function GetInstance: Tsingleton5; class function NewInstance: TObject; override; procedure FreeInstance; override; constructor Create; function DoSomethingImportant: string; end;
implementation
class function Tsingleton5.GetInstance: Tsingleton5; begin if Tsingleton5._Instance = nil then Tsingleton5._Instance := TSingleton5.Create; Result := Tsingleton5._Instance; end;
class constructor Tsingleton5.Create; begin Tsingleton5._PodeDestruir := false; end;
class destructor Tsingleton5.Destroy; begin Tsingleton5._PodeDestruir := true; if Tsingleton5._Instance <> nil then Tsingleton5._Instance.Destroy; end;
class function Tsingleton5.NewInstance: TObject; begin if _Instance = nil then _Instance := (inherited NewInstance as Tsingleton5); Result := _Instance; end;
constructor Tsingleton5.Create; begin FCreationTimeStamp:= DateTimeToStr(now); end;
function Tsingleton5.DoSomethingImportant: string; begin Result := 'Instância de ' + Self.ClassName + ' Criada em ' + FCreationTimeStamp + ' no endereço ' + IntToStr(integer(self)); end;
procedure Tsingleton5.FreeInstance; begin //destruirá apenas quando for permitido if _PodeDestruir then begin inherited FreeInstance; _Instance := nil; end; end;
end. }
e usar como no exemplo 5 :)
|
Responder |
|
|
19 - 27/10/2011 10:59 - ClubeDelphi - Usando o Padrão Singleton - Revista ClubeDelphi 133
|
|
VITOR RUBIO
|
Vagner, bom dia. Infelizmente não tenho o Delphi 2007 para testar, mas se você acompanhar os exemplos do meu blog verá que é possível criar boas implementações de singleton mesmo no Delphi 7 ou lazarus.
O importante do singleton é ter mecanismos que assegurem sua única instância, que não seja possível criar uma segunda por engano e que ele não cause um leak.
O artigo na Clube Delphi 133 pode ser interpretado como a "parte 5" dessa série sobre singletons, já que usei uma abordagem um pouquinho diferente.
http://blog.vitorrubio.com.br/2010/11/existem-1001-maneiras-de-preparar.html
|
Responder |
|
|
20 - 27/10/2011 10:36 - ClubeDelphi - Bancos de Dados Gratuitos - Revista ClubeDelphi 132 - parte 2
|
|
VITOR RUBIO
|
Fico feliz com seu feedback. Sinta-se à vontade para perguntar se tiver alguma dúvida.
|
Responder |
|
|
21 - 27/10/2011 10:32 - ClubeDelphi - Bancos de Dados Gratuitos - Revista ClubeDelphi 132 - parte 2
|
|
AUGUSTO LEFEVRE
|
Estou começando a ler a série. Quando terminar direi o que achei. Por enquanto acho útil.
|
Responder |
|
|
22 - 13/10/2011 20:12 - ClubeDelphi - Usando o Padrão Singleton - Revista ClubeDelphi 133
|
|
club athletico paulistano
|
Gostei da matéria, parabéns ao Vitor.
Não sei se está conforme os padrões, mas para o Delphi2007 fiz assim.
type TSingleton = class public class function GetInstance: Tsingleton;
class function NewInstance: TObject; override; procedure FreeInstance; override;
function DoSomethingImportant: string; end;
implementation var _Instance: Tsingleton; FCreationTimeStamp:string;
class function Tsingleton.GetInstance: Tsingleton; begin inherited Create;
Result := _Instance; end;
class function Tsingleton.NewInstance: TObject; begin if _Instance = nil then begin FCreationTimeStamp:= FormatDateTime('ddmmyyyy_hhnnsszzz', now); _Instance := (inherited NewInstance as Tsingleton); end;
Result := _Instance; end;
function Tsingleton.DoSomethingImportant: string; begin Result := 'Instância de ' + Self.ClassName + ' Criada em ' + FCreationTimeStamp + ' no endereço ' + IntToStr(integer(self)); end;
procedure Tsingleton.FreeInstance; begin //destruirá apenas quando for permitido if _Instance <> nil then begin inherited FreeInstance; _Instance := nil; end; end;
(Vagner)
|
Responder |
|
|
23 - 18/9/2011 20:03 - ClubeDelphi - Bancos de Dados Gratuitos - Revista ClubeDelphi 133 - Parte 3
|
|
VITOR RUBIO
|
Quando dá a mensagem que falta algum arquivo, dcu ou pas (geralmente pas) é porque o local onde está esse arquivo não está no searching path e no browsing path. Só procurar o diretório onde está o arquivo e adicionar nos dois paths na configuração do Delphi.
|
Responder |
|
|
24 - 17/9/2011 20:03 - ClubeDelphi - Bancos de Dados Gratuitos - Revista ClubeDelphi 133 - Parte 3
|
|
Rodrigo Pereira Barra
|
Pessoal, tinha mandado a dúvida, mas depois de quebrar a cabeça consegui instalar. Eu peguei os nomes dos arquivos que estavam dando problema, e pesquisei a localização exata desses .dcu. Aí adicionei no library e browsing path o caminho exato deles. Aí foi compilando e dando erro em outros. Aí fui fazendo a mesma coisa e deu certo. Postei pq mais algum sem muita experiência pode precisar.
|
Responder |
|
|
25 - 17/9/2011 19:44 - ClubeDelphi - Bancos de Dados Gratuitos - Revista ClubeDelphi 133 - Parte 3
|
|
Rodrigo Pereira Barra
|
Vitor artigo muito bom. Mas preciso de ajuda sua ou de alguém que saiba. Eu baixei o Zeos7-alpha modificado por você para o Delphi XE, beleza. Aí eu adicionei as librarys e browsing paths. Comecei a compilar os pacotes do group. Os 4 primeiros compilaram beleza. Aí cheguei no ZComponent150.bpl dá erro não compila. dá erros nas linhas dos drivers ( ZDbcAdo, ZDbcMySql,ZDbcPostgreSql,ZDbcInterbase6,ZDbcSqLite, ZDbcOracle,ZDbcASA) e em baixo o erro: F1026 File not found: 'ZDbcAdo.dcu'. Aí devido á este erro o ZComponentDesign150.bpl também não compila e nem instala. Se alguém puder me ajudar. Porque estou precisando muito conectar DELPHI XE + MYSQL e não consigo. Desde já agradeço.
|
Responder |
|
|
26 - 27/5/2011 17:57 - ClubeDelphi - Integre projetos .NET e Win32 - Artigo ClubeDelphi 128
|
|
CARLOS GONZAGA
|
Vitor, realmente estava usando o mesmo guid. Troquei e gerei novamente e continua dando o erro. Envie os projetos (.net/win32) p/ seu e-mail
|
Responder |
|
|
27 - 27/5/2011 17:06 - ClubeDelphi - Integre projetos .NET e Win32 - Artigo ClubeDelphi 128
|
|
VITOR RUBIO
|
Carlos Gonzaga, boa tarde.
Esse erro pode acontecer por vários motivos. O Assembly feito em Prism ou C# deve ser "com visible", isso você pode ver nas propriedades do projeto ou no assemblyinfo, dependendo da versão de seu visual studio/prism. Além de ser comvisible o assembly precisa de uma GUID, e a interface dentro do código - fonte (que você implementa) precisa de outra guid, não pode ser igual. É essa guid que deve ser usada pela interface no lado Delphi. Essa DLL deve ter um strong name, ou seja, deve ser compilada com um arquivo .snk gerado pela ferramenta sn.exe. Depois de compilar a DLL deve ser registrada no GAC. Se o problema persistir, por favor me mande o seu fonte e a DLL para eu examinar. Pode ser problema de ambiente também. Testei no winXP 32 bits.
|
Responder |
|
|
28 - 27/5/2011 15:14 - ClubeDelphi - Integre projetos .NET e Win32 - Artigo ClubeDelphi 128
|
|
CARLOS GONZAGA
|
Artigo muito interessante pra quem gosta de codificar os recursos extras indente de assistentes. Mas seguindo o exemplo, na hora da chamada do metodo da o seguinte erro: "OLE error 80131522". O q pode estar acontecendo?
Nota1: o assembly foi registrado normal (delphi 2007/windows 7 32 bits)
|
Responder |
|
|
29 - 6/12/2010 17:29 - ClubeDelphi - Design Patterns - Parte 3 - Artigo Clube Delphi 124
|
|
Vitor Luiz Rubio
|
Leonardo e Guess Soluções, Boa tarde.
As duas formas mencionadas por vocês está correta, apenas não coloquei o código para verificar tipo (com o operador as) para simplificar o artigo. Teoricamente seria possível fazer essa verificação em qualquer ponto que não causasse a inclusão de uma unit a mais no uses gerando acoplamento.
Nesse caso específico um TNossoAdoDataset só seria usado caso o ini estivesse configurado para uso com o ADO, e se o ini estivesse configurado assim então uma fábrica de ADO database seria criada. Como o parâmetro bd não é colocado pelo programador nem pelo usuário, mas é retornado pela fábrica, há uma garantia (fraca, implícita) de que o objeto bd seja realmente um TAdoConnection (caso o ini esteja corretamente configurado) devido a maneira como usamos o conjunto TNossoXXXDataset e a fábrica.
De qualquer forma, mesmo não sendo possível que a fábrica de TAdoConnection gere um TForm, é possível sim que um programador desavisado utilizasse apenas uma parte do framework e passasse um TForm para o método SetBancoDados. Dessa forma uma verificação de tipo seria uma segurança a mais.
Em última instância um objeto do tipo errado nessa parte dispararia uma mensagem de invalid typecast antes que qualquer problema de corrupção ou perda de dados pudesse ocorrer.
Agradeço pelo feedback.
PS.: Fiquei curioso sobre o uso da metaclasse, poderia compartilhar aqui ou no fórum para um intercâmbio de conhecimento?
|
Responder |
|
|
30 - 4/12/2010 11:53 - ClubeDelphi - Design Patterns - Parte 3 - Artigo Clube Delphi 124
|
|
GUESS SOLUçõES EM INFORMáTICA LTME ME
|
Caro Leonardo,
acredito que uma melhor solução, seria criar uma meta classe e utilizá-la como parâmetro de entrada para este método, desta maneira, o tipo de entrada seria fiel ao esperado.
Ou de repente, usar até mesmo o tipo TDataSet como parâmetro.
|
Responder |
|
|
31 - 3/12/2010 14:18 - ClubeDelphi - Design Patterns - Parte 3 - Artigo Clube Delphi 124
|
|
LEONARDO COELHO BORGES
|
procedure TNossoAdoDataset.SetBancoDados(bd: TObject); begin if bd <> nil then begin FDataset.Connection := (bd as TADOConnection); end else raise Exception.Create(Objeto banco de dados nulo!); end;
Conversando com um colega de trabalho, estavamos verificando este método, ele colocou a seguinte situação:
O que acontece se no bd eu passar um TForm em tempo de execução??? O método vai tentar fazer o cast para TADOConnection.
ele colocou a seguinte situação: poderia fazer a verificação do tipo antes do cast.
procedure TNossoAdoDataset.SetBancoDados(bd: TObject); begin
if (bd = nil) then raise Exception.Create(Objeto banco de dados nulo!);
if (db.ClassType = TADOConnection) then begin FDataset.Connection := (bd as TADOConnection); end else
raise Exception.Create(Objeto não é do tipo esperado!); end;
|
Responder |
|
|
32 - 7/8/2010 02:14 - ClubeDelphi - Strings - Clube Delphi 120
|
|
MARLON NARDI
|
Referente a ferramenta encontrei em sua lista de Links:
|
Responder |
|
|
33 - 7/8/2010 02:05 - ClubeDelphi - Strings - Clube Delphi 120
|
|
MARLON NARDI
|
Vitor,
Li sobre seu artigo, mas não consegui identificar a solução para o problema no qual não migrei minhas Aplicações Desenvolvida no Delphi 2007 para o Delphi 2010.
O problema é este: 
Conversei com alguns mais experientes na area, e os mesmos me disseram que eu teria que remover a adicionar novamente os meus Tfields, mas isso vai ser muito trabalhoso, em uma aplicação grande. vou ficar varios dias fazendo isso ate regularizar toda a minha aplicação, não teria uma outra forma para resolver este problema?
Outra coisa, poderia passar o Link da ferramenta, Figura 2 :
Att, Marlon Nardi
|
Responder |
|