mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
New file.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1054 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
c86c5f3459
commit
dba54a8bd3
7 changed files with 1190 additions and 0 deletions
47
Headers/gnustep/base/Notification.h
Normal file
47
Headers/gnustep/base/Notification.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* Interface for holding and dispatching notifications
|
||||
Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
|
||||
Created: March 1996
|
||||
|
||||
This file is part of the GNU Objective C Class Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <objects/stdobjects.h>
|
||||
#include <objects/NSString.h>
|
||||
#include <objects/KeyedCollecting.h>
|
||||
#include <objects/NotificationDispatcher.h>
|
||||
|
||||
@interface Notification : NSObject
|
||||
{
|
||||
id _name;
|
||||
id _object;
|
||||
id _info;
|
||||
}
|
||||
|
||||
+ notificationWithName: (id <String>)name
|
||||
object: object;
|
||||
|
||||
+ notificationWithName: (id <String>)name
|
||||
object: object
|
||||
userInfo: info;
|
||||
|
||||
- (id <String>) name;
|
||||
- object;
|
||||
- userInfo;
|
||||
|
||||
@end
|
188
Headers/gnustep/base/NotificationDispatcher.h
Normal file
188
Headers/gnustep/base/NotificationDispatcher.h
Normal file
|
@ -0,0 +1,188 @@
|
|||
/* Interface to object for broadcasting Notification objects
|
||||
Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
|
||||
Created: March 1996
|
||||
|
||||
This file is part of the GNU Objective C Class Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __NotificationDispatcher_h_OBJECTS_INCLUDE
|
||||
#define __NotificationDispatcher_h_OBJECTS_INCLUDE
|
||||
|
||||
/* A class for posting notifications to observer objects that request
|
||||
them.
|
||||
|
||||
This implementation has several advantages over OpenStep's
|
||||
NSNotificationCenter:
|
||||
|
||||
(1) Heavier use of hash tables and the use of LinkedList's make it
|
||||
faster. Removing from the middle of LinkedList's is much more
|
||||
efficient than removing from the middle of Array's.
|
||||
|
||||
(2) The way in which notifications are dispatched can be specified as
|
||||
invocation objects instead of just selectors. Invocation objects
|
||||
are more flexible than selectors in that they can hold more context
|
||||
and, if desired, can call C functions instead of sending a message
|
||||
to an object, (this way you may be able to avoid creating a new
|
||||
class just to handle certain notifications).
|
||||
|
||||
(3) Instead of sending +defaultCenter, you can simply send -add...,
|
||||
-remove... and -post... messages directly to the class object.
|
||||
The class uses a static variable directly, instead of taking
|
||||
the time for the extra +defaultCenter method call. It's both
|
||||
easier for the user and more time efficient.
|
||||
|
||||
Although it offers extra features, the implementation has an
|
||||
OpenStep-style interface also.
|
||||
|
||||
*/
|
||||
|
||||
#include <objects/stdobjects.h>
|
||||
#include <objects/LinkedList.h>
|
||||
#include <Foundation/NSMapTable.h>
|
||||
#include <objects/NSString.h>
|
||||
|
||||
@interface NotificationDispatcher : NSObject
|
||||
{
|
||||
/* For those observer requests with NAME=nil and OBJECT=nil. */
|
||||
LinkedList *anonymous_nr_list;
|
||||
/* For those observer requests with NAME=nil and OBJECT!=nil. */
|
||||
NSMapTable *object_2_nr_list;
|
||||
/* For those observer requests with NAME!=nil, OBJECT may or may not =nil .*/
|
||||
NSMapTable *name_2_nr_list;
|
||||
|
||||
/* The keys are observers; the values are Array's containing all
|
||||
NotificationInvocation objects associated with the observer key. */
|
||||
NSMapTable *observer_2_nr_array;
|
||||
|
||||
/* `nr' stands for Notification Request Object; the interface for
|
||||
this class is defined in the .m file. One of these is created
|
||||
for each -add... call. */
|
||||
}
|
||||
|
||||
|
||||
/* Adding new observers. */
|
||||
|
||||
/* Register observer to receive future notifications that match NAME
|
||||
and OBJECT. A nil passed as either NAME or OBJECT acts as a wild-card.
|
||||
If NAME is nil, send to the observer all notification pertaining to
|
||||
OBJECT. If OBJECT is nil, send to the observer all notification
|
||||
pertaining to NAME. If both OBJECT and NAME are nil, send to the
|
||||
observer all notifications.
|
||||
|
||||
The notification will be posted by sending -invokeWithObject: to
|
||||
INVOCATION argument. The argument of -invokeWithObject: will be
|
||||
a Notification object. This use of Invocation objects is more
|
||||
flexible than using a selector, since Invocation's can be set up
|
||||
with more arguments, hold more context, and can be C functions.
|
||||
|
||||
Typically, in cases that INVOCATION is a MethodInvocation, the
|
||||
target of INVOCATION will the OBSERVER, but this is not required.
|
||||
When OBSERVER is not the same as the target, and is non-nil, it can
|
||||
still be useful for organizational help in removing a coherent set
|
||||
of observation requests, when used as an argument to -removeObserver:.
|
||||
|
||||
Neither OBSERVER nor OBJECT are retained; this is so these objects
|
||||
can tell when there are no outstanding non-notification references
|
||||
remaining. If an object may have added itself as an observer, it
|
||||
should call +removeObserver: in its -dealloc method.
|
||||
|
||||
INVOCATION and NAME, however, are retained. */
|
||||
|
||||
- (void) addObserver: observer
|
||||
invocation: (id <Invoking>)invocation
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
|
||||
/* For those that want the simplicity of specifying a selector instead of
|
||||
an invocation as a way to contact the observer.
|
||||
|
||||
The notification will be posted by sending -perform:withObject:
|
||||
to the observer, with SEL and OBJECT as arguments.
|
||||
|
||||
Comments above about retaining apply here also. */
|
||||
|
||||
- (void) addObserver: observer
|
||||
selector: (SEL)sel
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
|
||||
/* Class versions of the above two methods that send these messages
|
||||
to the default NotificationDispatcher for the class. */
|
||||
|
||||
+ (void) addObserver: observer
|
||||
invocation: (id <Invoking>)invocation
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
+ (void) addObserver: observer
|
||||
selector: (SEL)sel
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
|
||||
|
||||
|
||||
/* Removing observers. */
|
||||
|
||||
/* Remove all records pertaining to OBSERVER. For instance, this
|
||||
should be called before the OBSERVER is -dealloc'ed. */
|
||||
|
||||
- (void) removeObserver: observer;
|
||||
|
||||
/* Remove the notification requests for the given parameters. As with
|
||||
adding an observation request, nil NAME or OBJECT act as wildcards. */
|
||||
|
||||
- (void) removeObserver: observer
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
|
||||
/* Class versions of the above two methods that send these messages
|
||||
to the default NotificationDispatcher for the class. */
|
||||
|
||||
+ (void) removeObserver: observer;
|
||||
+ (void) removeObserver: observer
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
|
||||
|
||||
|
||||
/* Post NOTIFICATION to all the observers that match its NAME and OBJECT. */
|
||||
|
||||
- (void) postNotification: notification;
|
||||
- (void) postNotificationName: (id <String>)name
|
||||
object: object;
|
||||
- (void) postNotificationName: (id <String>)name
|
||||
object: object
|
||||
userInfo: (id <ConstantKeyedCollecting>)info_dictionary;
|
||||
|
||||
/* Class versions of the above two methods that send these messages
|
||||
to the default NotificationDispatcher for the class. */
|
||||
|
||||
+ (void) postNotification: notification;
|
||||
+ (void) postNotificationName: (id <String>)name
|
||||
object: object;
|
||||
+ (void) postNotificationName: (id <String>)name
|
||||
object: object
|
||||
userInfo: (id <ConstantKeyedCollecting>)info_dictionary;
|
||||
|
||||
@end
|
||||
|
||||
@interface NotificationDispatcher (OpenStepCompat)
|
||||
+ defaultCenter;
|
||||
@end
|
||||
|
||||
#endif /* __NotificationDispatcher_h_OBJECTS_INCLUDE */
|
102
Source/Notification.m
Normal file
102
Source/Notification.m
Normal file
|
@ -0,0 +1,102 @@
|
|||
/* Implementation of object for holding a notification
|
||||
Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
|
||||
Created: March 1996
|
||||
|
||||
This file is part of the GNU Objective C Class Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <objects/Notification.h>
|
||||
|
||||
@implementation Notification
|
||||
|
||||
/* This is the designated initializer. */
|
||||
- initWithName: (id <String>)name
|
||||
object: object
|
||||
userInfo: info
|
||||
{
|
||||
[super init];
|
||||
_name = [name retain];
|
||||
_object = [object retain];
|
||||
_info = [info retain];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[_name release];
|
||||
[_object release];
|
||||
[_info release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
/* Creating autoreleased Notification objects. */
|
||||
|
||||
+ notificationWithName: (id <String>)name
|
||||
object: object
|
||||
userInfo: info
|
||||
{
|
||||
return [[[self alloc] initWithName: name
|
||||
object: object
|
||||
userInfo: info]
|
||||
autorelease];
|
||||
}
|
||||
|
||||
+ notificationWithName: (id <String>)name
|
||||
object: object
|
||||
{
|
||||
return [self notificationWithName: name
|
||||
object: object
|
||||
userInfo: nil];
|
||||
}
|
||||
|
||||
|
||||
/* Querying a Notification object. */
|
||||
|
||||
- (id <String>) name
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
- object
|
||||
{
|
||||
return _object;
|
||||
}
|
||||
|
||||
- userInfo
|
||||
{
|
||||
return _info;
|
||||
}
|
||||
|
||||
|
||||
/* NSCopying protocol. */
|
||||
|
||||
- copyWithZone: (NSZone*)zone
|
||||
{
|
||||
if (NSShouldRetainWithZone (self, zone))
|
||||
return [self retain];
|
||||
|
||||
/* xxx How deep should the copy go? Should we copy _name, etc.? */
|
||||
return [[[self class] allocWithZone: zone]
|
||||
initWithName: _name
|
||||
object: _object
|
||||
userInfo: _info];
|
||||
}
|
||||
|
||||
@end
|
560
Source/NotificationDispatcher.m
Normal file
560
Source/NotificationDispatcher.m
Normal file
|
@ -0,0 +1,560 @@
|
|||
/* Implementation of object for broadcasting Notification objects
|
||||
Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
|
||||
Created: March 1996
|
||||
|
||||
This file is part of the GNU Objective C Class Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <objects/NotificationDispatcher.h>
|
||||
#include <objects/Notification.h>
|
||||
#include <objects/LinkedListNode.h>
|
||||
#include <objects/Array.h>
|
||||
#include <objects/Invocation.h>
|
||||
#include <Foundation/NSException.h>
|
||||
|
||||
/* The implementation for NotificationDispatcher.
|
||||
|
||||
First we define an object for holding the observer's
|
||||
notification requests: */
|
||||
|
||||
|
||||
/* One of these objects is created for each -addObserver... request.
|
||||
It holds the requested invocation, name and object. Each object
|
||||
is placed
|
||||
(1) in one LinkedList, as keyed by the NAME/OBJECT parameters (accessible
|
||||
through one of the ivars: anonymous_nr_list, object_2_nr_list,
|
||||
name_2_nr_list), and
|
||||
(2) in the Array, as keyed by the OBSERVER (as accessible through
|
||||
the ivar observer_2_nr_array.
|
||||
|
||||
To post a notification in satisfaction of this request,
|
||||
send -postNotification:.
|
||||
*/
|
||||
|
||||
@interface NotificationRequest : LinkedListNode
|
||||
{
|
||||
int retain_count;
|
||||
id name;
|
||||
id object;
|
||||
}
|
||||
|
||||
- initWithName: n object: o;
|
||||
- (id <String>) notificationName;
|
||||
- notificationObject;
|
||||
- (void) postNotification: n;
|
||||
@end
|
||||
|
||||
@implementation NotificationRequest
|
||||
|
||||
- initWithName: n object: o
|
||||
{
|
||||
[super init];
|
||||
retain_count = 0;
|
||||
name = [n retain];
|
||||
object = o;
|
||||
/* Note that OBJECT is not retained. See the comment for
|
||||
-addObserver... in NotificationDispatcher.h. */
|
||||
return self;
|
||||
}
|
||||
|
||||
/* Implement these retain/release methods here for efficiency, since
|
||||
NotificationInvocation's get retained and released by all their
|
||||
holders. Doing this is a judgement call; I'm choosing speed over
|
||||
space. */
|
||||
|
||||
- retain
|
||||
{
|
||||
retain_count++;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (oneway void) release
|
||||
{
|
||||
if (!retain_count--)
|
||||
[self dealloc];
|
||||
}
|
||||
|
||||
- (unsigned) retainCount
|
||||
{
|
||||
return retain_count;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[name release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id <String>) notificationName
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
- notificationObject
|
||||
{
|
||||
return object;
|
||||
}
|
||||
|
||||
- (void) postNotification: n
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface NotificationInvocation : NotificationRequest
|
||||
{
|
||||
id invocation;
|
||||
}
|
||||
- initWithInvocation: i name: n object: o;
|
||||
@end
|
||||
|
||||
@implementation NotificationInvocation
|
||||
|
||||
- initWithInvocation: i name: n object: o
|
||||
{
|
||||
[super initWithName: n object: o];
|
||||
invocation = [i retain];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[invocation release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) postNotification: n
|
||||
{
|
||||
[invocation invokeWithObject: n];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface NotificationPerformer : NotificationRequest
|
||||
{
|
||||
id target;
|
||||
SEL selector;
|
||||
}
|
||||
- initWithTarget: t selector: (SEL)s name: n object: o;
|
||||
@end
|
||||
|
||||
@implementation NotificationPerformer
|
||||
|
||||
- initWithTarget: t selector: (SEL)s name: n object: o
|
||||
{
|
||||
[super initWithName: n object: o];
|
||||
/* Note that TARGET is not retained. See the comment for
|
||||
-addObserver... in NotificationDispatcher.h. */
|
||||
target = t;
|
||||
selector = s;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) postNotification: n
|
||||
{
|
||||
[target perform: selector withObject: n];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
@implementation NotificationDispatcher
|
||||
|
||||
/* The default instance, most often the only one created.
|
||||
It is accessed by the class methods at the end of this file. */
|
||||
static NotificationDispatcher *default_notification_dispatcher = nil;
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [NotificationDispatcher class])
|
||||
default_notification_dispatcher = [self new];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Initializing. */
|
||||
|
||||
- init
|
||||
{
|
||||
[super init];
|
||||
anonymous_nr_list = [LinkedList new];
|
||||
|
||||
/* Use NSNonOwnedPointerOrNullMapKeyCallBacks so we won't retain
|
||||
the object. We will, however, retain the LinkedList's. */
|
||||
object_2_nr_list =
|
||||
NSCreateMapTable (NSNonOwnedPointerOrNullMapKeyCallBacks,
|
||||
NSObjectMapValueCallBacks, 0);
|
||||
|
||||
/* Likewise. */
|
||||
/* xxx Should we retain NAME here after all? */
|
||||
name_2_nr_list =
|
||||
NSCreateMapTable (NSNonOwnedPointerOrNullMapKeyCallBacks,
|
||||
NSObjectMapValueCallBacks, 0);
|
||||
|
||||
/* Likewise. */
|
||||
observer_2_nr_array =
|
||||
NSCreateMapTable (NSNonOwnedPointerOrNullMapKeyCallBacks,
|
||||
NSObjectMapValueCallBacks, 0);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/* Adding new observers. */
|
||||
|
||||
/* This is the designated method for adding observers. */
|
||||
- (void) _addObserver: observer
|
||||
notificationRequest: nr
|
||||
name: (id <String>)name
|
||||
object: object
|
||||
{
|
||||
/* Record the request in an array of all the requests by this observer. */
|
||||
if (observer)
|
||||
{
|
||||
Array *nr_array = NSMapGet (observer_2_nr_array, observer);
|
||||
if (!nr_array)
|
||||
{
|
||||
nr_array = [Array new];
|
||||
/* nr_array is retained; observer is not. */
|
||||
NSMapInsert (observer_2_nr_array, observer, nr_array);
|
||||
[nr_array release];
|
||||
}
|
||||
[nr_array appendObject: nr];
|
||||
}
|
||||
|
||||
/* Record the request in one, and only one, LinkedList. The LinkedList
|
||||
is stored in a hash table accessed by a key. Which key is used
|
||||
depends on what combination of NAME and OBJECT are non-nil. */
|
||||
if (!name)
|
||||
{
|
||||
if (!object)
|
||||
{
|
||||
[anonymous_nr_list appendObject: nr];
|
||||
}
|
||||
else
|
||||
{
|
||||
LinkedList *nr_list = NSMapGet (object_2_nr_list, object);
|
||||
if (!nr_list)
|
||||
{
|
||||
nr_list = [LinkedList new];
|
||||
/* nr_list is retained; object is not retained. */
|
||||
NSMapInsert (object_2_nr_list, object, nr_list);
|
||||
[nr_list release];
|
||||
}
|
||||
[nr_list appendObject: nr];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LinkedList *nr_list = NSMapGet (name_2_nr_list, name);
|
||||
if (!nr_list)
|
||||
{
|
||||
nr_list = [LinkedList new];
|
||||
/* nr_list is retained; object is not retained. */
|
||||
NSMapInsert (name_2_nr_list, name, nr_list);
|
||||
[nr_list release];
|
||||
}
|
||||
[nr_list appendObject: nr];
|
||||
}
|
||||
|
||||
/* Since nr was retained when it was added to the collection above,
|
||||
we can release it now. */
|
||||
[nr release];
|
||||
}
|
||||
|
||||
- (void) addObserver: observer
|
||||
invocation: (id <Invoking>)invocation
|
||||
name: (id <String>)name
|
||||
object: object
|
||||
{
|
||||
/* The NotificationInvocation we create to hold this request. */
|
||||
id nr;
|
||||
|
||||
/* Create the NotificationInvocation object that will hold
|
||||
this observation request. This will retain INVOCATION and NAME. */
|
||||
nr = [[NotificationInvocation alloc]
|
||||
initWithInvocation: invocation
|
||||
name: name
|
||||
object: object];
|
||||
|
||||
/* Record it in all the right places. */
|
||||
[self _addObserver: observer
|
||||
notificationRequest: nr
|
||||
name: name
|
||||
object: object];
|
||||
}
|
||||
|
||||
|
||||
/* For those that want to specify a selector instead of an invocation
|
||||
as a way to contact the observer.
|
||||
If for some reason we didn't want to use Invocation's, we could
|
||||
additionally create another kind of "NotificationInvocation" that
|
||||
just used selector's instead. */
|
||||
|
||||
- (void) addObserver: observer
|
||||
selector: (SEL)sel
|
||||
name: (id <String>)name
|
||||
object: object
|
||||
{
|
||||
/* The NotificationInvocation we create to hold this request. */
|
||||
id nr;
|
||||
|
||||
/* Create the NotificationInvocation object that will hold
|
||||
this observation request. This will retain INVOCATION and NAME. */
|
||||
nr = [[NotificationPerformer alloc]
|
||||
initWithTarget: observer
|
||||
selector: sel
|
||||
name: name
|
||||
object: object];
|
||||
|
||||
/* Record it in all the right places. */
|
||||
[self _addObserver: observer
|
||||
notificationRequest: nr
|
||||
name: name
|
||||
object: object];
|
||||
}
|
||||
|
||||
|
||||
/* Remove all records pertaining to OBSERVER. For instance, this
|
||||
should be called before the OBSERVER is -dealloc'ed. */
|
||||
|
||||
- (void) removeObserver: observer
|
||||
{
|
||||
Array *observer_nr_array;
|
||||
NotificationInvocation *nr;
|
||||
|
||||
/* Get the array of NotificationInvocation's associated with OBSERVER. */
|
||||
observer_nr_array = NSMapGet (observer_2_nr_array, observer);
|
||||
|
||||
if (!observer_nr_array)
|
||||
/* OBSERVER was never registered for any notification requests with us.
|
||||
Nothing to do. */
|
||||
return;
|
||||
|
||||
/* Remove each of these from it's LinkedList. */
|
||||
FOR_ARRAY (observer_nr_array, nr)
|
||||
{
|
||||
[[nr linkedList] removeObject: nr];
|
||||
}
|
||||
END_FOR_ARRAY (observer_nr_array);
|
||||
|
||||
/* Remove from the MapTable the list of NotificationInvocation's
|
||||
associated with OBSERVER. This also releases the observer_nr_array,
|
||||
and its contents. */
|
||||
NSMapRemove (observer_2_nr_array, observer);
|
||||
}
|
||||
|
||||
|
||||
/* Remove the notification requests for the given parameters. As with
|
||||
adding an observation request, nil NAME or OBJECT act as wildcards. */
|
||||
|
||||
- (void) removeObserver: observer
|
||||
name: (id <String>)name
|
||||
object: object
|
||||
{
|
||||
Array *observer_nr_array;
|
||||
NotificationInvocation *nr;
|
||||
|
||||
/* Get the list of NotificationInvocation's associated with OBSERVER. */
|
||||
observer_nr_array = NSMapGet (observer_2_nr_array, observer);
|
||||
|
||||
if (!observer_nr_array)
|
||||
/* OBSERVER was never registered for any notification requests with us.
|
||||
Nothing to do. */
|
||||
return;
|
||||
|
||||
/* Find those NotificationInvocation's from the array that
|
||||
match NAME and OBJECT, and remove them from the array and
|
||||
their linked list. */
|
||||
{
|
||||
NotificationInvocation *nr;
|
||||
int count = [observer_nr_array count];
|
||||
unsigned matching_nr_indices[count];
|
||||
int i;
|
||||
|
||||
for (i = count-1; i >= 0; i--)
|
||||
{
|
||||
nr = [observer_nr_array objectAtIndex: i];
|
||||
if ((!name || [name isEqual: [nr notificationName]])
|
||||
&& (!object || [object isEqual: [nr notificationObject]]))
|
||||
{
|
||||
/* We can remove from the array, even though we are "enumerating"
|
||||
over it, because we are enumerating from back-to-front,
|
||||
and the indices of yet-to-come objects don't change when
|
||||
high-indexed objects are removed. */
|
||||
[observer_nr_array removeObjectAtIndex: i];
|
||||
[[nr linkedList] removeObject: nr];
|
||||
}
|
||||
}
|
||||
/* xxx If there are some LinkedList's that are empty, I should
|
||||
remove them from the map table's. */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Post NOTIFICATION to all the observers that match its NAME and OBJECT. */
|
||||
|
||||
- (void) postNotification: notification
|
||||
{
|
||||
/* This cast avoids complaints about different types for -name. */
|
||||
id notification_name = [(Notification*)notification name];
|
||||
id notification_object = [notification object];
|
||||
id nr;
|
||||
LinkedList *nr_list;
|
||||
|
||||
/* Make sure the notification has a name. */
|
||||
if (!notification_name)
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Tried to post a notification with no name."];
|
||||
|
||||
/* Post the notification to all the observers that specified neither
|
||||
NAME or OBJECT. */
|
||||
if ([anonymous_nr_list count])
|
||||
{
|
||||
FOR_COLLECTION (anonymous_nr_list, nr)
|
||||
{
|
||||
[nr postNotification: notification];
|
||||
}
|
||||
END_FOR_COLLECTION (anonymous_nr_list);
|
||||
}
|
||||
|
||||
/* Post the notification to all the observers that specified OBJECT,
|
||||
but didn't specify NAME. */
|
||||
if (notification_object)
|
||||
{
|
||||
nr_list = NSMapGet (object_2_nr_list, notification_object);
|
||||
if (nr_list)
|
||||
{
|
||||
FOR_COLLECTION (nr_list, nr)
|
||||
{
|
||||
[nr postNotification: notification];
|
||||
}
|
||||
END_FOR_COLLECTION (nr_list);
|
||||
}
|
||||
}
|
||||
|
||||
/* Post the notification to all the observers of NAME; (and if the
|
||||
observer's OBJECT is non-nil, don't send unless the observer's OBJECT
|
||||
matches the notification's OBJECT). */
|
||||
nr_list = NSMapGet (name_2_nr_list, notification_name);
|
||||
if (nr_list)
|
||||
{
|
||||
FOR_COLLECTION (nr_list, nr)
|
||||
{
|
||||
id nr_object = [nr notificationObject];
|
||||
if (!nr_object || nr_object == notification_object)
|
||||
[nr postNotification: notification];
|
||||
}
|
||||
END_FOR_COLLECTION (nr_list);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) postNotificationName: (id <String>)name
|
||||
object: object
|
||||
{
|
||||
[self postNotification: [Notification notificationWithName: name
|
||||
object: object]];
|
||||
}
|
||||
|
||||
- (void) postNotificationName: (id <String>)name
|
||||
object: object
|
||||
userInfo: info
|
||||
{
|
||||
[self postNotification: [Notification notificationWithName: name
|
||||
object: object
|
||||
userInfo: info]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Class methods. */
|
||||
|
||||
+ (void) addObserver: observer
|
||||
invocation: (id <Invoking>)invocation
|
||||
name: (id <String>)name
|
||||
object: object
|
||||
{
|
||||
[default_notification_dispatcher addObserver: observer
|
||||
invocation: invocation
|
||||
name: name
|
||||
object: object];
|
||||
}
|
||||
|
||||
+ (void) addObserver: observer
|
||||
selector: (SEL)sel
|
||||
name: (id <String>)name
|
||||
object: object
|
||||
{
|
||||
[default_notification_dispatcher addObserver: observer
|
||||
selector: sel
|
||||
name: name
|
||||
object: object];
|
||||
}
|
||||
|
||||
+ (void) removeObserver: observer
|
||||
{
|
||||
[default_notification_dispatcher removeObserver: observer];
|
||||
}
|
||||
|
||||
+ (void) removeObserver: observer
|
||||
name: (id <String>)name
|
||||
object: object
|
||||
{
|
||||
[default_notification_dispatcher removeObserver: observer
|
||||
name: name
|
||||
object: object];
|
||||
}
|
||||
|
||||
+ (void) postNotification: notification
|
||||
{
|
||||
[default_notification_dispatcher postNotification: notification];
|
||||
}
|
||||
|
||||
+ (void) postNotificationName: (id <String>)name
|
||||
object: object
|
||||
{
|
||||
[default_notification_dispatcher postNotificationName: name
|
||||
object: object];
|
||||
}
|
||||
|
||||
+ (void) postNotificationName: (id <String>)name
|
||||
object: object
|
||||
userInfo: info
|
||||
{
|
||||
[default_notification_dispatcher postNotificationName: name
|
||||
object: object
|
||||
userInfo: info];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NotificationDispatcher (OpenStepCompat)
|
||||
|
||||
/* For OpenStep compatibility. */
|
||||
+ defaultCenter
|
||||
{
|
||||
return default_notification_dispatcher;
|
||||
}
|
||||
|
||||
@end
|
47
Source/objects/Notification.h
Normal file
47
Source/objects/Notification.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* Interface for holding and dispatching notifications
|
||||
Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
|
||||
Created: March 1996
|
||||
|
||||
This file is part of the GNU Objective C Class Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <objects/stdobjects.h>
|
||||
#include <objects/NSString.h>
|
||||
#include <objects/KeyedCollecting.h>
|
||||
#include <objects/NotificationDispatcher.h>
|
||||
|
||||
@interface Notification : NSObject
|
||||
{
|
||||
id _name;
|
||||
id _object;
|
||||
id _info;
|
||||
}
|
||||
|
||||
+ notificationWithName: (id <String>)name
|
||||
object: object;
|
||||
|
||||
+ notificationWithName: (id <String>)name
|
||||
object: object
|
||||
userInfo: info;
|
||||
|
||||
- (id <String>) name;
|
||||
- object;
|
||||
- userInfo;
|
||||
|
||||
@end
|
188
Source/objects/NotificationDispatcher.h
Normal file
188
Source/objects/NotificationDispatcher.h
Normal file
|
@ -0,0 +1,188 @@
|
|||
/* Interface to object for broadcasting Notification objects
|
||||
Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
|
||||
Created: March 1996
|
||||
|
||||
This file is part of the GNU Objective C Class Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __NotificationDispatcher_h_OBJECTS_INCLUDE
|
||||
#define __NotificationDispatcher_h_OBJECTS_INCLUDE
|
||||
|
||||
/* A class for posting notifications to observer objects that request
|
||||
them.
|
||||
|
||||
This implementation has several advantages over OpenStep's
|
||||
NSNotificationCenter:
|
||||
|
||||
(1) Heavier use of hash tables and the use of LinkedList's make it
|
||||
faster. Removing from the middle of LinkedList's is much more
|
||||
efficient than removing from the middle of Array's.
|
||||
|
||||
(2) The way in which notifications are dispatched can be specified as
|
||||
invocation objects instead of just selectors. Invocation objects
|
||||
are more flexible than selectors in that they can hold more context
|
||||
and, if desired, can call C functions instead of sending a message
|
||||
to an object, (this way you may be able to avoid creating a new
|
||||
class just to handle certain notifications).
|
||||
|
||||
(3) Instead of sending +defaultCenter, you can simply send -add...,
|
||||
-remove... and -post... messages directly to the class object.
|
||||
The class uses a static variable directly, instead of taking
|
||||
the time for the extra +defaultCenter method call. It's both
|
||||
easier for the user and more time efficient.
|
||||
|
||||
Although it offers extra features, the implementation has an
|
||||
OpenStep-style interface also.
|
||||
|
||||
*/
|
||||
|
||||
#include <objects/stdobjects.h>
|
||||
#include <objects/LinkedList.h>
|
||||
#include <Foundation/NSMapTable.h>
|
||||
#include <objects/NSString.h>
|
||||
|
||||
@interface NotificationDispatcher : NSObject
|
||||
{
|
||||
/* For those observer requests with NAME=nil and OBJECT=nil. */
|
||||
LinkedList *anonymous_nr_list;
|
||||
/* For those observer requests with NAME=nil and OBJECT!=nil. */
|
||||
NSMapTable *object_2_nr_list;
|
||||
/* For those observer requests with NAME!=nil, OBJECT may or may not =nil .*/
|
||||
NSMapTable *name_2_nr_list;
|
||||
|
||||
/* The keys are observers; the values are Array's containing all
|
||||
NotificationInvocation objects associated with the observer key. */
|
||||
NSMapTable *observer_2_nr_array;
|
||||
|
||||
/* `nr' stands for Notification Request Object; the interface for
|
||||
this class is defined in the .m file. One of these is created
|
||||
for each -add... call. */
|
||||
}
|
||||
|
||||
|
||||
/* Adding new observers. */
|
||||
|
||||
/* Register observer to receive future notifications that match NAME
|
||||
and OBJECT. A nil passed as either NAME or OBJECT acts as a wild-card.
|
||||
If NAME is nil, send to the observer all notification pertaining to
|
||||
OBJECT. If OBJECT is nil, send to the observer all notification
|
||||
pertaining to NAME. If both OBJECT and NAME are nil, send to the
|
||||
observer all notifications.
|
||||
|
||||
The notification will be posted by sending -invokeWithObject: to
|
||||
INVOCATION argument. The argument of -invokeWithObject: will be
|
||||
a Notification object. This use of Invocation objects is more
|
||||
flexible than using a selector, since Invocation's can be set up
|
||||
with more arguments, hold more context, and can be C functions.
|
||||
|
||||
Typically, in cases that INVOCATION is a MethodInvocation, the
|
||||
target of INVOCATION will the OBSERVER, but this is not required.
|
||||
When OBSERVER is not the same as the target, and is non-nil, it can
|
||||
still be useful for organizational help in removing a coherent set
|
||||
of observation requests, when used as an argument to -removeObserver:.
|
||||
|
||||
Neither OBSERVER nor OBJECT are retained; this is so these objects
|
||||
can tell when there are no outstanding non-notification references
|
||||
remaining. If an object may have added itself as an observer, it
|
||||
should call +removeObserver: in its -dealloc method.
|
||||
|
||||
INVOCATION and NAME, however, are retained. */
|
||||
|
||||
- (void) addObserver: observer
|
||||
invocation: (id <Invoking>)invocation
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
|
||||
/* For those that want the simplicity of specifying a selector instead of
|
||||
an invocation as a way to contact the observer.
|
||||
|
||||
The notification will be posted by sending -perform:withObject:
|
||||
to the observer, with SEL and OBJECT as arguments.
|
||||
|
||||
Comments above about retaining apply here also. */
|
||||
|
||||
- (void) addObserver: observer
|
||||
selector: (SEL)sel
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
|
||||
/* Class versions of the above two methods that send these messages
|
||||
to the default NotificationDispatcher for the class. */
|
||||
|
||||
+ (void) addObserver: observer
|
||||
invocation: (id <Invoking>)invocation
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
+ (void) addObserver: observer
|
||||
selector: (SEL)sel
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
|
||||
|
||||
|
||||
/* Removing observers. */
|
||||
|
||||
/* Remove all records pertaining to OBSERVER. For instance, this
|
||||
should be called before the OBSERVER is -dealloc'ed. */
|
||||
|
||||
- (void) removeObserver: observer;
|
||||
|
||||
/* Remove the notification requests for the given parameters. As with
|
||||
adding an observation request, nil NAME or OBJECT act as wildcards. */
|
||||
|
||||
- (void) removeObserver: observer
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
|
||||
/* Class versions of the above two methods that send these messages
|
||||
to the default NotificationDispatcher for the class. */
|
||||
|
||||
+ (void) removeObserver: observer;
|
||||
+ (void) removeObserver: observer
|
||||
name: (id <String>)name
|
||||
object: object;
|
||||
|
||||
|
||||
|
||||
/* Post NOTIFICATION to all the observers that match its NAME and OBJECT. */
|
||||
|
||||
- (void) postNotification: notification;
|
||||
- (void) postNotificationName: (id <String>)name
|
||||
object: object;
|
||||
- (void) postNotificationName: (id <String>)name
|
||||
object: object
|
||||
userInfo: (id <ConstantKeyedCollecting>)info_dictionary;
|
||||
|
||||
/* Class versions of the above two methods that send these messages
|
||||
to the default NotificationDispatcher for the class. */
|
||||
|
||||
+ (void) postNotification: notification;
|
||||
+ (void) postNotificationName: (id <String>)name
|
||||
object: object;
|
||||
+ (void) postNotificationName: (id <String>)name
|
||||
object: object
|
||||
userInfo: (id <ConstantKeyedCollecting>)info_dictionary;
|
||||
|
||||
@end
|
||||
|
||||
@interface NotificationDispatcher (OpenStepCompat)
|
||||
+ defaultCenter;
|
||||
@end
|
||||
|
||||
#endif /* __NotificationDispatcher_h_OBJECTS_INCLUDE */
|
58
Testing/nsnotification.m
Normal file
58
Testing/nsnotification.m
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* The simplest of tests for the NSNotification and NSNotificationCenter
|
||||
classes. These tests should be expanded.
|
||||
|
||||
(The Tcp*Port classes, however, do test the notification mechanism
|
||||
further.) */
|
||||
|
||||
#include <Foundation/NSNotification.h>
|
||||
#include <Foundation/NSString.h>
|
||||
|
||||
@interface Observer : NSObject
|
||||
- (void) gotNotificationFoo: not;
|
||||
@end
|
||||
|
||||
@implementation Observer
|
||||
|
||||
- (void) gotNotificationFoo: (NSNotification*)not
|
||||
{
|
||||
printf ("Got %@\n", [not name]);
|
||||
}
|
||||
|
||||
- (void) gotNotificationFooNoObject: (NSNotification*)not
|
||||
{
|
||||
printf ("Got %@ without object\n", [not name]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
id foo = @"NotificationTestFoo";
|
||||
|
||||
int main ()
|
||||
{
|
||||
id o1 = [NSObject new];
|
||||
id observer1 = [Observer new];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: observer1
|
||||
selector: @selector(gotNotificationFoo:)
|
||||
name: foo
|
||||
object: o1];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: observer1
|
||||
selector: @selector(gotNotificationFooNoObject:)
|
||||
name: foo
|
||||
object: nil];
|
||||
|
||||
/* This will cause two messages to be printed, one for each request above. */
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName: foo
|
||||
object: o1];
|
||||
|
||||
/* This will cause one message to be printed. */
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName: foo
|
||||
object: nil];
|
||||
|
||||
exit (0);
|
||||
}
|
Loading…
Reference in a new issue