组件原码
procedure TComponent.Notification(AComponent: TComponent;
Operation: TOperation);
var
I: Integer;
begin
if (Operation = opRemove) and (AComponent <> nil) then
RemoveFreeNotification(AComponent); // 移除释放通知
if FComponents <> nil then // 还有组件
begin
I := FComponents.Count - 1;
while I >= 0 do // 这个循环很不好理解,艾老师,您能帮解释一下吗?
begin
TComponent(FComponents[I]).Notification(AComponent, Operation); // 这里应该是调用了递归
Dec(I); // 去通知这个组件包含的组件
if I >= FComponents.Count then // 为什么要减 1 呢
I := FComponents.Count - 1; // 由 dec(i) 来控制不就行了吗?
end;
end;
end;
//---------------------------------------
在移除组件中
procedure TComponent.RemoveNotification(AComponent: TComponent);
begin
if FFreeNotifies <> nil then
begin
FFreeNotifies.Remove(AComponent);
if FFreeNotifies.Count = 0 then
begin
FFreeNotifies.Free;
FFreeNotifies := nil;
end;
end;
end;
procedure TComponent.RemoveFreeNotification(AComponent: TComponent);
begin
RemoveNotification(AComponent); // 已经把这个组件给移除了,而下句怎么还用它来通知呢?
AComponent.RemoveNotification(Self);
end;
解答:
procedure TComponent.Notification(AComponent: TComponent;
Operation: TOperation);
var
I: Integer;
begin
if (Operation = opRemove) and (AComponent <> nil) then
RemoveFreeNotification(AComponent); // 移除释放通知
if FComponents <> nil then // 还有组件
begin
I := FComponents.Count - 1;
while I >= 0 do // 这个循环很不好理解?
begin
TComponent(FComponents[I]).Notification(AComponent, Operation); // 这里应该是调用了递归
//准确的说不是递归,只是可能会多次调用不同组件的同名函数
Dec(I); // 去通知这个组件包含的组件
if I >= FComponents.Count then // 为什么要减 1 呢
I := FComponents.Count - 1; // 由 dec(i) 来控制不就行了吗?
//Notification函数是一个函数,一个可重写的虚函数,谁能保证程序员在里面写什么代码呢?
//假定某个程序员在重写这个函数的时候释放了一个FComponents列表中的一个组件呢?
//这时实际上仅仅是一个dec(i),i就可能会大于FComponents.Count,下一个循环就有可能下标溢出。
end;
end;
end;
//---------------------------------------
//这里并不是移除组件的方法,而只是移除其他组件在自己注册的“移除通知”,
//也就是说自己有什么事情的时候将不再通知AComponent了。
procedure TComponent.RemoveNotification(AComponent: TComponent);
begin
if FFreeNotifies <> nil then
begin
FFreeNotifies.Remove(AComponent);
if FFreeNotifies.Count = 0 then
begin
FFreeNotifies.Free;
FFreeNotifies := nil;
end;
end;
end;
procedure TComponent.RemoveFreeNotification(AComponent: TComponent);
begin
RemoveNotification(AComponent);
//AComponent很显然还没有被删除,要知道代码是顺序执行的,组件可能正在被删除,但是还没有被删除,
//而下面的一句也只是让AComponent去除自己(Self)注册的一个“移除通知”,
//也就是说让AComponent将来被释放的时候将不用通知自己了(self),因为自己马上就要被释放了
AComponent.RemoveNotification(Self);
end;