Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Компоненты";
Текущий архив: 2006.02.12;
Скачать: [xml.tar.bz2];

Вниз

Уничтожение компонентов   Найти похожие ветки 

 
z0ne   (2005-08-18 11:57) [0]

1. есть связка компонентов: ТКомпонент1 использует ТКомпонент2
2. ТКомпонент2 могут использовать также и ТКомпонент3 и ТКомпонент4
3. все компоненты невизуальные и набросаны на DataModule
4. + есть возможность создания экземпляров ТКомпонент3 или  ТКомпонент1 в run-time.

проблема возникает когда DataModule начинает уничтожаться.

мне нужно определить порядок уничтожения компонентов, чтобы ТКомпонент2 был уничтожен последним. Иначе при обращении к ТКомпонент2 из, например, ТКомпонент3 получаю Access Violation


 
Джо ©   (2005-08-18 13:05) [1]

Упростим ситуацию для наглядности.

 TInnerControl = class (TControl)
 end;

 TOuterControl = class (TControl)
 private
   FMyControl: TControl;
   procedure SetMyControl(const Value: TControl);
 protected
   procedure Notification(AComponent: TComponent;
     Operation: TOperation); override;
 published
   property MyControl: TControl read FMyControl write SetMyControl;
 end;

implementation

procedure TOuterControl.Notification(AComponent: TComponent;
 Operation: TOperation);
begin
 inherited Notification(AComponent, Operation);
 if Operation = opRemove then
   if AComponent = MyControl then
     MyControl := nil;
end;

procedure TOuterControl.SetMyControl(const Value: TControl);
begin
 FMyControl := Value;
 if FMyControl <> nil then
   FMyControl.FreeNotification(Self);
end;


Перед своим уничтожением, объект класса TInner (неважно, каким образом это произойдет) уведомит об этом TOuter. И он вовремя обнулит свою ссылку на удаляемый объект.


 
Юрий Зотов ©   (2005-08-18 13:12) [2]

> z0ne   (18.08.05 11:57)

> нужно определить порядок уничтожения компонентов

Не нужно определять порядок уничтожения компонентов. Нужно у компонентов, ссылающихся на другие компоненты, перекрыть метод Notification и в нем очищать ссылки. А потенциально опасных местах кода, перед обращением по этим ссылкам проверять их на nil, вот и все.

type
 TComponent2 = class(...)
   ...
 end;

 TComponent1 = class(...)
 private
   FComponent2: TComponent2;
   procedure SetComponent2(const Value: TComponent2);
 protected
   procedure Notification(AComponent: TComponent; Operation: TOperation); override;
   ...
   procedure DoSomethingWithComponent2;
   ...
 published
   ...
   property Component2: TComponent2 read FComponent2 write SetComponent2;
   ...
 end;

procedure TComponent1.Notification(AComponent: TComponent; Operation: TOperation); override;
begin
 inherited;
 if (Operation = opRemove) and (AComponent = FComponent2) then
   FComponent2 := nil
end;

procedure TComponent1.SetComponent2(const Value: TComponent2);
begin
 if FComponent2 <> Value then
 begin
   if FComponent2 <> nil then
     RemoveFreeNotification(FComponent2);
   FComponent2 := Value;
   if FComponent2 <> nil then
     FreeNotification(FComponent2)
 end
end;

procedure TComponent1.DoSomethingWithComponent2;
begin
 if FComponent2 <> nil then
   ...
end;


 
z0ne   (2005-08-18 13:20) [3]

>Перед своим уничтожением, объект класса TInner (неважно, каким >образом это произойдет) уведомит об этом TOuter. И он вовремя >обнулит свою ссылку на удаляемый объект.

проблема как раз в том что ТКомпонент2 ДОЛЖЕН жить пока существуют на него ссылки!!! т.е. не давать себя разрушить.
и как посчитать ссылки ??? делать наследников для ТКомпонент1,3,4???


 
Юрий Зотов ©   (2005-08-18 14:07) [4]

> z0ne   (18.08.05 13:20) [3]

> ТКомпонент2 ДОЛЖЕН жить пока существуют на него ссылки!!!

Не должен. А если без этого что-то не получается - значит, это "что-то" неверно задумано или неверно спроектировано.

Поэтому давайте начнем с начала - в чем, собственно, задумка-то?


 
Reindeer Moss Eater ©   (2005-08-18 14:07) [5]

проблема как раз в том что ТКомпонент2 ДОЛЖЕН жить пока существуют на него ссылки!!!

Надуманная проблема.
Метод Notification как раз предназначен для убийства недействительных ссылок.


 
z0ne   (2005-08-18 15:20) [6]

>Поэтому давайте начнем с начала - в чем, собственно, задумка-то?

всегда все приходят к этому главному вопросу :)
компонент который "должен жить" это прослойка в наследнике от TDataSet которая отвечает за работу с конкретным SQLСервером соответственно черезнего работают все запросы типа StartTransaction, ExecSQL, SELECT ну и прочие.
на него опирается ещё пара-тройка компонент, которые хотят общаться с базой.
т.е. схема такая T_DataSet -> TProv -> IBSQL примерно!!!
и вот убивание этого самого TProv и портит мне жисть.
так что вариант с Notification и обнулением ссылки .... неподходит :(
проект где используются эта "штуковина" не первый ...
может раньше как-то складывалось всё удачно, назнаю!

за пол дня придумал пока только в Дестрое создавать копию себя и в мессаге сообщать свой новый адрес ..... но это так ....


 
Reindeer Moss Eater ©   (2005-08-18 15:57) [7]

и вот убивание этого самого TProv и портит мне жисть.
так что вариант с Notification и обнулением ссылки .... неподходит :(


Бред.
Жизнь будет портиться только если ты не проверяешь свойства - объекты на nil перед тем как их использовать.

за пол дня придумал пока только в Дестрое создавать копию себя и в мессаге сообщать свой новый адрес ..... но это так ....

Ну вот. А говорили нет пророка в своем отечестве. А они тут пачками ходят.
:)))


 
z0ne   (2005-08-18 16:41) [8]

>не проверяешь свойства - объекты на nil перед тем как их использовать

Ну буду я проверять .... и чего ???
обьект-то убит :(((
а вечное пересоздание самого себя так это рекурсия и всё-такое прочее, опять флажки вешать :(

короче нормального решения нет :(((((
буду плакать и страдать...


 
z0ne   (2005-08-18 16:47) [9]

нет у нас согласия ......

Иду я с пивом и думаю щас допью и обоссусь.
что делать ???

вы мне советуете: как начнёшь ссацца - проверь пил ли ты пиво!

а мне надо: не пить пиво!

собственно вот.
засим, наверное, прощщевайте. пойду куличики лепить.
Завтра может загляну ещё раз. на всякий случай ;)


 
Reindeer Moss Eater ©   (2005-08-18 17:17) [10]

компонент который "должен жить" это прослойка в наследнике от TDataSet которая отвечает за работу с конкретным SQLСервером соответственно черезнего работают все запросы типа StartTransaction, ExecSQL, SELECT ну и прочие.
на него опирается ещё пара-тройка компонент, которые хотят общаться с базой.


Обычно в таких случаях эти компоненты, "которые должны жить" оформляются не как компоненты, а просто как классы.
Например для каждого специфичного сервера рисуется модуль со специфичным для модуля классом. В intialization этого модуля этот класс регистрируется в списке всех доступных серверов.
А общий T_DataSet, который ничего не знает о конкретном сервере работает именно через эти зарегистрированные фичи для конкретного сервера.

Хороший пример реализации подобной схемы можно найти в EhLib"е (каталог DataServices). Там для работы грида используется именно такой механизм.
Причем за убийством нужных компонентов следить не надо, так как их нет. Есть экземпляры классов, создаваемые если соотв. модуль есть в uses проекта.


 
z0ne   (2005-08-18 17:48) [11]

о !!!
а это хорошая идея !!!
..
хотелось бы конечно визуальности ... но это мы обернём :)
ОГРОМНОЕ ЧЕЛОВЕЧЕСКОЕ СПАСИБО


 
Reindeer Moss Eater ©   (2005-08-18 18:08) [12]

Визуальности можно добиться таким нехитрым приемом:
В модуле, специфичном для конкретного сервера реализуется класс компонента - пустышки:

TSomeServerFeatures = class(TComponent)
end;

Компонент регистрируется в палитре.
Все кто его помещают на форму получают в uses имя нужного модуля и соответственно получают функциональность для нужного сервера.


 
Юрий Зотов ©   (2005-08-18 19:06) [13]

Еще вариант - интерфейс. Подсчет ссылок - автоматический, самоубийство - тоже.


 
Наиль ©   (2005-08-18 20:57) [14]

>[6] и [10]
Не знаю почему, но мне это жутко напоминает TSession и TDataBase.
Существуют, даже если компонента на форму не брошена. Но если уж брошена, то можно поуправлять.


 
z0ne   (2005-08-19 09:39) [15]

как грится все идеи хороши - выбирай на вкус
всем спасибо!
по итогам обсуждения приняты вырианты:
1. компонента - пустышки
2. интерфейс
3. в Create(!) вечноживущего компонента при его создании в run-time AOwner заменяется на Application :) или AOwner.Owner. ... .Owner.


 
z0ne   (2005-08-23 10:15) [16]

если кому ещё интересно :))))
всё решилось так:

1. в Create
[Code]
If (not (csDesignins in ComponentState)) and
  (AOwner<>NIL)
then FreeNotinication(AOWner)
[/Code]

2. в Notifycation
[Code]
If (AComponent=Owner) and (Operation=opRemove)
then begin
 RemoveFreeNotifycation(Owner) // ??? не помню, вродебы так
 Owner.RemoveComponent(Self);
 Application.InsertComponent(Self);
end;
[/Code]


 
Юрий Зотов ©   (2005-08-23 13:43) [17]

В таком случае почему бы вместо всего этого сразу не написать в конструкторе inherited Create(Application)?


 
z0ne   (2005-08-24 16:44) [18]

а потому что другие компоненты на DataSource, которые привязятись  к "живчику" у disign-time при загрузке ищут его в Owner.Components ... а мы его засандалили к Application ...



Страницы: 1 вся ветка

Форум: "Компоненты";
Текущий архив: 2006.02.12;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.5 MB
Время: 0.042 c
1-1136791731
beglec
2006-01-09 10:28
2006.02.12
Долгое копирование потока. Как решить?


1-1136908476
Arazel
2006-01-10 18:54
2006.02.12
TreeView и TObject (Как добратся до самого Object а не Text)?


4-1133225072
Германн
2005-11-29 03:44
2006.02.12
Как перезапустить службу на удаленном компьютере


3-1134372919
VIB
2005-12-12 10:35
2006.02.12
SQLScripts


2-1138080657
Janbolat
2006-01-24 08:30
2006.02.12
FTP-Админ как?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский