Форум: "Компоненты";
Текущий архив: 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