This is MiscTee.m in view mode; [Download] [Up]
// // MiscTee.h -- An object which will pass a message on to any of the objects // connected to it. This is useful for splitting an action // message to multiple recipients or for allowing multiple // delegates to be connected to provide different services. // // Written by David Fedchenko. Copyright 1994 by David Fedchenko. // Version 1.1 All rights reserved. // Additions by Don Yacktman to remove warnings and avoid infinite loops. // // This notice may not be removed from this source code. // // This object is included in the MiscKit by permission from the author // and its use is governed by the MiscKit license, found in the file // "LICENSE.rtf" in the MiscKit distribution. Please refer to that file // for a list of all applicable permissions and restrictions. // #import "MiscTee.h" typedef struct { // Object *idObject; // Using this would remove warnings _if_ isa were // not protected, but as things stand, we'll have to live with the // warnings. :-( That's what you get for "isa hacking"! //id idObject; // This is where we got warnings...original definition... struct objc_class *idObject; // This seems to work right... SEL selAction; } CONPAIR; @implementation MiscTee - init { [super init]; inTee = NO; idConnections = [[Storage alloc] initCount:0 elementSize:sizeof(CONPAIR) description:@encode(CONPAIR)]; return self; } - free { [idConnections free]; return [super free]; } - addConnection:anObject with:(SEL)anAction { CONPAIR cp; CONPAIR * pcp; int i; cp.idObject = anObject; cp.selAction = anAction; // replace the action if the object is already in the list for (i = 0; i < [idConnections count]; i++) { pcp = (CONPAIR *)[idConnections elementAt:i]; if (pcp->idObject == anObject) { pcp->selAction = anAction; return self; } } // new connection [idConnections addElement:&cp]; return self; } - removeConnection:anObject { CONPAIR * pcp; int i; for (i = 0; i < [idConnections count]; i++) { pcp = (CONPAIR *)[idConnections elementAt:i]; if (pcp->idObject == anObject) { [idConnections removeElementAt:i]; break; } } return self; } - ping:sender { int i; CONPAIR * pcp; if (inTee) return self; inTee = YES; for (i = 0; i < [idConnections count]; i++) { pcp = (CONPAIR *)[idConnections elementAt:i]; if (strcmp(pcp->idObject->isa->name, "FREED(id)") && pcp->idObject != sender && pcp->selAction) { [pcp->idObject perform:pcp->selAction with:sender]; } } inTee = NO; return self; } - forward:(SEL)aSelector :(marg_list)argFrame { int i; CONPAIR * pcp; void * pv = nil; BOOL fSent = NO; if (inTee) return self; inTee = YES; for (i = 0; i < [idConnections count]; i++) { pcp = (CONPAIR *)[idConnections elementAt:i]; if (strcmp(pcp->idObject->isa->name, "FREED(id)") && [pcp->idObject respondsTo:aSelector]) { pv = [pcp->idObject performv:aSelector :argFrame]; fSent = YES; } } if (!fSent) { [self doesNotRecognize:aSelector]; } inTee = NO; return (id)pv; } -(BOOL) respondsTo:(SEL)aSelector { int i; CONPAIR * pcp; if ([super respondsTo:aSelector]) { return YES; } for (i = 0; i < [idConnections count]; i++) { pcp = (CONPAIR *)[idConnections elementAt:i]; if (strcmp(pcp->idObject->isa->name, "FREED(id)") && [pcp->idObject respondsTo:aSelector]) { // don't worry about multiple positive responses return YES; } } return NO; } - read:(NXTypedStream *)stream { [super read:stream]; idConnections = NXReadObject(stream); inTee = NO; return self; } - write:(NXTypedStream *)stream { [super write:stream]; NXWriteObject(stream, idConnections); return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.