![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Уничтожение компонентов [D5, D7]
z0ne © (2005-08-18 11:57:00)1. есть связка компонентов: ТКомпонент1использует ТКомпонент2
2. ТКомпонент2могут использовать также и ТКомпонент3и ТКомпонент4
3. все компоненты невизуальные и набросаны на DataModule
4. + есть возможность создания экземпляров ТКомпонент3или ТКомпонент1в run-time.
проблема возникает когда DataModule начинает уничтожаться.
мне нужно определить порядок уничтожения компонентов, чтобы ТКомпонент2был уничтожен последним. Иначе при обращении к ТКомпонент2из, например, ТКомпонент3получаю Access Violation
z0ne (2005-08-24 16:44:00) [1]а потому что другие компоненты на DataSource, которые привязятись к "живчику" у disign-time при загрузке ищут его в Owner.Components ... а мы его засандалили к Application ...
Юрий Зотов (2005-08-23 13:43:00) [2]В таком случае почему бы вместо всего этого сразу не написать в конструкторе inherited Create(Application)?
z0ne (2005-08-23 10:15:00) [3]если кому ещё интересно :))))
всё решилось так:
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]
z0ne (2005-08-19 09:39:00) [4]как грится все идеи хороши - выбирай на вкус
всем спасибо!
по итогам обсуждения приняты вырианты:
1. компонента - пустышки
2. интерфейс
3. в Create(!) вечноживущего компонента при его создании в run-time AOwner заменяется на Application :) или AOwner.Owner. ... .Owner.
Наиль (2005-08-18 20:57:00) [5]>[6] и [10]
Не знаю почему, но мне это жутко напоминает TSession и TDataBase.
Существуют, даже если компонента на форму не брошена. Но если уж брошена, то можно поуправлять.
Юрий Зотов (2005-08-18 19:06:00) [6]Еще вариант - интерфейс. Подсчет ссылок - автоматический, самоубийство - тоже.
Reindeer Moss Eater (2005-08-18 18:08:00) [7]Визуальности можно добиться таким нехитрым приемом:
В модуле, специфичном для конкретного сервера реализуется класс компонента - пустышки:
TSomeServerFeatures = class(TComponent)
end;
Компонент регистрируется в палитре.
Все кто его помещают на форму получают в uses имя нужного модуля и соответственно получают функциональность для нужного сервера.
z0ne (2005-08-18 17:48:00) [8]о !!!
а это хорошая идея !!!
..
хотелось бы конечно визуальности ... но это мы обернём :)
ОГРОМНОЕ ЧЕЛОВЕЧЕСКОЕ СПАСИБО
Reindeer Moss Eater (2005-08-18 17:17:00) [9]компонент который "должен жить" это прослойка в наследнике от TDataSet которая отвечает за работу с конкретным SQLСервером соответственно черезнего работают все запросы типа StartTransaction, ExecSQL, SELECT ну и прочие.
на него опирается ещё пара-тройка компонент, которые хотят общаться с базой.
Обычно в таких случаях эти компоненты, "которые должны жить" оформляются не как компоненты, а просто как классы.
Например для каждого специфичного сервера рисуется модуль со специфичным для модуля классом. В intialization этого модуля этот класс регистрируется в списке всех доступных серверов.
А общий T_DataSet, который ничего не знает о конкретном сервере работает именно через эти зарегистрированные фичи для конкретного сервера.
Хороший пример реализации подобной схемы можно найти в EhLib'е (каталог DataServices). Там для работы грида используется именно такой механизм.
Причем за убийством нужных компонентов следить не надо, так как их нет. Есть экземпляры классов, создаваемые если соотв. модуль есть в uses проекта.
z0ne (2005-08-18 16:47:00) [10]нет у нас согласия ......
Иду я с пивом и думаю щас допью и обоссусь.
что делать ???
вы мне советуете: как начнёшь ссацца - проверь пил ли ты пиво!
а мне надо: не пить пиво!
собственно вот.
засим, наверное, прощщевайте. пойду куличики лепить.
Завтра может загляну ещё раз. на всякий случай ;)
z0ne (2005-08-18 16:41:00) [11]>не проверяешь свойства - объекты на nil перед тем как их использовать
Ну буду я проверять .... и чего ???
обьект-то убит :(((
а вечное пересоздание самого себя так это рекурсия и всё-такое прочее, опять флажки вешать :(
короче нормального решения нет :(((((
буду плакать и страдать...
Reindeer Moss Eater (2005-08-18 15:57:00) [12]и вот убивание этого самого TProv и портит мне жисть.
так что вариант с Notification и обнулением ссылки .... неподходит :(
Бред.
Жизнь будет портиться только если ты не проверяешь свойства - объекты на nil перед тем как их использовать.
за пол дня придумал пока только в Дестрое создавать копию себя и в мессаге сообщать свой новый адрес ..... но это так ....
Ну вот. А говорили нет пророка в своем отечестве. А они тут пачками ходят.
:)))
z0ne (2005-08-18 15:20:00) [13]>Поэтому давайте начнем с начала - в чем, собственно, задумка-то?
всегда все приходят к этому главному вопросу :)
компонент который "должен жить" это прослойка в наследнике от TDataSet которая отвечает за работу с конкретным SQLСервером соответственно черезнего работают все запросы типа StartTransaction, ExecSQL, SELECT ну и прочие.
на него опирается ещё пара-тройка компонент, которые хотят общаться с базой.
т.е. схема такая T_DataSet -> TProv -> IBSQL примерно!!!
и вот убивание этого самого TProv и портит мне жисть.
так что вариант с Notification и обнулением ссылки .... неподходит :(
проект где используются эта "штуковина" не первый ...
может раньше как-то складывалось всё удачно, назнаю!
за пол дня придумал пока только в Дестрое создавать копию себя и в мессаге сообщать свой новый адрес ..... но это так ....
Reindeer Moss Eater (2005-08-18 14:07:00) [14]проблема как раз в том что ТКомпонент2 ДОЛЖЕН жить пока существуют на него ссылки!!!
Надуманная проблема.
Метод Notification как раз предназначен для убийства недействительных ссылок.
Юрий Зотов (2005-08-18 14:07:00) [15]> z0ne (18.08.05 13:20) [3]
> ТКомпонент2 ДОЛЖЕН жить пока существуют на него ссылки!!!
Не должен. А если без этого что-то не получается - значит, это "что-то" неверно задумано или неверно спроектировано.
Поэтому давайте начнем с начала - в чем, собственно, задумка-то?
z0ne (2005-08-18 13:20:00) [16]>Перед своим уничтожением, объект класса TInner (неважно, каким >образом это произойдет) уведомит об этом TOuter. И он вовремя >обнулит свою ссылку на удаляемый объект.
проблема как раз в том что ТКомпонент2 ДОЛЖЕН жить пока существуют на него ссылки!!! т.е. не давать себя разрушить.
и как посчитать ссылки ??? делать наследников для ТКомпонент1,3,4???
Юрий Зотов (2005-08-18 13:12:00) [17]> 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;
Джо (2005-08-18 13:05:00) [18]Упростим ситуацию для наглядности.
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. И он вовремя обнулит свою ссылку на удаляемый объект.