This is NSNotificationCenter.m in view mode; [Download] [Up]
/* NSNotificationCenter.m Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea. All rights reserved. Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro> This file is part of libFoundation. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. We disclaim all warranties with regard to this software, including all implied warranties of merchantability and fitness, in no event shall we be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software. */ #include <Foundation/NSNotification.h> #include <Foundation/NSDictionary.h> #include <Foundation/NSArray.h> #include <Foundation/NSString.h> #include <Foundation/NSUtilities.h> #include <Foundation/NSLock.h> #include <Foundation/common.h> #include <extensions/objc-runtime.h> #include <extensions/NSException.h> #include <extensions/NSException.h> #include <extensions/exceptions/GeneralExceptions.h> #define DEFAULT_CAPACITY 1023 /* * Objects/selectors pair used in sets */ @interface NSNotificationListItem : NSObject { @public id observer; // observer that will receive selector SEL selector; // is a postNotification: } - initWithObject:(id)anObserver selector:(SEL)aSelector; - (BOOL)isEqual:other; - (unsigned int)hash; - (void)postNotification:(NSNotification*)notification; @end @implementation NSNotificationListItem - initWithObject:(id)anObserver selector:(SEL)aSelector { observer = anObserver; selector = aSelector; return self; } - (BOOL)isEqual:other { if ([other isKindOfClass:[NSNotificationListItem class]]) { NSNotificationListItem* obj = other; return (observer == obj->observer) && SEL_EQ(selector, obj->selector); } return NO; } - (unsigned int)hash { return ((int)observer >> 4) + __NSHashCString(NULL, sel_get_name(selector)); } - (void)postNotification:(NSNotification*)notification { [observer perform:selector withObject:notification]; } @end /* * Register for objects to observer mapping */ @interface NSNotificationObserverRegister : NSObject { NSHashTable* observerItems; } - init; - (unsigned int)count; - (void)addObjectsInList:(NSMutableArray*)list; - (void)addObserver:observer selector:(SEL)selector; - (void)removeObserver:observer; @end @implementation NSNotificationObserverRegister - init { observerItems = NSCreateHashTable(NSObjectHashCallBacks, DEFAULT_CAPACITY); return self; } - (void)dealloc { NSFreeHashTable(observerItems); [super dealloc]; } - (unsigned int)count { return NSCountHashTable(observerItems); } - (void)addObjectsInList:(NSMutableArray*)list { id reg; NSHashEnumerator itemsEnum = NSEnumerateHashTable(observerItems); while((reg = (id)NSNextHashEnumeratorItem(&itemsEnum))) [list addObject:reg]; } - (void)addObserver:observer selector:(SEL)selector { NSNotificationListItem* reg = [[[NSNotificationListItem alloc] initWithObject:observer selector:selector] autorelease]; NSHashInsertIfAbsent(observerItems, reg); } - (void)removeObserver:observer { NSMutableArray* list; NSNotificationListItem* reg; NSHashEnumerator itemsEnum; int i; list = [[[NSMutableArray alloc] initWithCapacity:[self count]] autorelease]; itemsEnum = NSEnumerateHashTable(observerItems); while((reg = (id)NSNextHashEnumeratorItem(&itemsEnum))) if (reg->observer == observer) [list addObject:reg]; for (i = [list count]-1; i >= 0; i--) NSHashRemove(observerItems, [list objectAtIndex:i]); } @end /* * Register for objects to observer mapping */ @interface NSNotificationObjectRegister : NSObject { NSMapTable* objectObservers; NSNotificationObserverRegister* nilObjectObservers; } - init; - listToNotifyForObject:object; - (void)addObserver:observer selector:(SEL)selector object:object; - (void)removeObserver:observer object:object; - (void)removeObserver:observer; @end @implementation NSNotificationObjectRegister - init { objectObservers = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSObjectMapValueCallBacks, DEFAULT_CAPACITY); nilObjectObservers = [NSNotificationObserverRegister new]; return self; } - (void)dealloc { NSFreeMapTable(objectObservers); [nilObjectObservers release]; [super dealloc]; } - listToNotifyForObject:object { id reg = nil; int count; id list; if (object) reg = (id)NSMapGet(objectObservers, object); count = [reg count] + [nilObjectObservers count]; list = [[[NSMutableArray alloc] initWithCapacity:count] autorelease]; [reg addObjectsInList:list]; [nilObjectObservers addObjectsInList:list]; return list; } - (void)addObserver:observer selector:(SEL)selector object:object { NSNotificationObserverRegister* reg; if (object) { reg = (id)NSMapGet(objectObservers, object); if (!reg) { reg = [[[NSNotificationObserverRegister alloc] init] autorelease]; NSMapInsert(objectObservers, object, reg); } } else reg = nilObjectObservers; [reg addObserver:observer selector:selector]; } - (void)removeObserver:observer object:object { NSNotificationObserverRegister* reg; if (object) reg = NSMapGet(objectObservers, object); else reg = nilObjectObservers; [reg removeObserver:observer]; } - (void)removeObserver:observer { id obj, reg; NSMapEnumerator regEnum = NSEnumerateMapTable(objectObservers); while (NSNextMapEnumeratorPair(®Enum, (void*)&obj, (void*)®)) [reg removeObserver:observer]; [nilObjectObservers removeObserver:observer]; } @end /* * NSNotificationCenter */ static NSNotificationCenter *defaultCenter = nil; @implementation NSNotificationCenter /* Class methods */ + (NSNotificationCenter*)defaultCenter { if (!defaultCenter) { // THREAD defaultCenter = [[self alloc] init]; } return defaultCenter; } /* Init/dealloc */ - (id)init { nameToObjects = [NSMutableDictionary new]; nullNameToObjects = [NSNotificationObjectRegister new]; return self; } - (void)dealloc { [nameToObjects release]; [nullNameToObjects release]; [super dealloc]; } /* Register && post notifications */ - (void)postNotification:(NSNotification*)notification { NSArray* fromName; NSArray* fromNull; NSNotificationObjectRegister* reg; id name = [notification notificationName]; id object = [notification notificationObject]; if (name == nil) THROW([[InvalidArgumentException alloc] initWithFormat:@"`nil' notification name in postNotification:"]); [lock lock]; // get objects to notify with registered notification name reg = [nameToObjects objectForKey:name]; fromName = [reg listToNotifyForObject:object]; // get objects to notify with no notification name fromNull = [nullNameToObjects listToNotifyForObject:object]; [lock unlock]; // send notifications [fromName makeObjectsPerform:@selector(postNotification:) withObject:notification]; [fromNull makeObjectsPerform:@selector(postNotification:) withObject:notification]; } - (void)addObserver:observer selector:(SEL)selector name:(NSString*)notificationName object:object { NSNotificationObjectRegister* reg; [lock lock]; if (notificationName == nil) reg = nullNameToObjects; else { notificationName = [[notificationName copyWithZone:[notificationName zone]] autorelease]; reg = [nameToObjects objectForKey:notificationName]; if (!reg) { reg = [[[NSNotificationObjectRegister alloc] init] autorelease]; [nameToObjects setObject:reg forKey:notificationName]; } } [reg addObserver:observer selector:selector object:object]; [lock unlock]; } - (void)removeObserver:observer name:(NSString*)notificationName object:object { NSNotificationObjectRegister* reg; [lock lock]; if (notificationName == nil) reg = nullNameToObjects; else reg = [nameToObjects objectForKey:notificationName]; [reg removeObserver:observer object:object]; [lock unlock]; } - (void)removeObserver:observer { id name, enumerator; NSNotificationObjectRegister* reg; [lock lock]; enumerator = [nameToObjects keyEnumerator]; while ((name = [enumerator nextObject])) { reg = [nameToObjects objectForKey:name]; [reg removeObserver:observer]; } [nullNameToObjects removeObserver:observer]; [lock unlock]; } - (void)postNotificationName:(NSString*)notificationName object:object { [self postNotification:[NSNotification notificationWithName:notificationName object:object userInfo:nil]]; } - (void)postNotificationName:(NSString*)notificationName object:object userInfo:(NSDictionary*)userInfo; { [self postNotification:[NSNotification notificationWithName:notificationName object:object userInfo:userInfo]]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.