mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +00:00
NotificationCenter removeObserver (#396)
This modifies the NotificationCenter class to do the following: - add an ivar to the class for an array to hold observers that need to be released when they are removed - adds an observer to that array if the observer is of class GSNotificationObserver - upon removing an observer, check if it is in that array, if so remove it from the array and release it. This replaces the previous implementation which checked the class of the observer as it was being removed, which would cause a crash if the observer had been deallocated.
This commit is contained in:
parent
94cf2026b6
commit
21a48f6136
2 changed files with 25 additions and 7 deletions
|
@ -74,7 +74,7 @@ GS_EXPORT_CLASS
|
|||
{
|
||||
#if GS_EXPOSE(NSNotificationCenter)
|
||||
@private
|
||||
void *_table;
|
||||
void *_table;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#import "Foundation/NSLock.h"
|
||||
#import "Foundation/NSOperation.h"
|
||||
#import "Foundation/NSThread.h"
|
||||
#import "Foundation/NSHashTable.h"
|
||||
#import "GNUstepBase/GSLock.h"
|
||||
|
||||
static NSZone *_zone = 0;
|
||||
|
@ -240,6 +241,7 @@ typedef struct NCTbl {
|
|||
GSIMapTable cache[CACHESIZE];
|
||||
unsigned short chunkIndex;
|
||||
unsigned short cacheIndex;
|
||||
NSHashTable *retainedObjectsTable;
|
||||
} NCTable;
|
||||
|
||||
#define TABLE ((NCTable*)_table)
|
||||
|
@ -388,7 +390,9 @@ static void endNCTable(NCTable *t)
|
|||
NSZoneFree(NSDefaultMallocZone(), (void*)t->cache[i]);
|
||||
}
|
||||
NSZoneFree(NSDefaultMallocZone(), t->chunks);
|
||||
RELEASE(t->retainedObjectsTable);
|
||||
NSZoneFree(NSDefaultMallocZone(), t);
|
||||
|
||||
}
|
||||
|
||||
static NCTable *newNCTable(void)
|
||||
|
@ -404,6 +408,7 @@ static NCTable *newNCTable(void)
|
|||
GSIMapInitWithZoneAndCapacity(t->nameless, _zone, 16);
|
||||
GSIMapInitWithZoneAndCapacity(t->named, _zone, 128);
|
||||
t->named->extra = YES; // This table retains keys
|
||||
t->retainedObjectsTable = [[NSHashTable alloc] initWithOptions:NSHashTableObjectPointerPersonality capacity:10];
|
||||
|
||||
t->_lock = [NSRecursiveLock new];
|
||||
return t;
|
||||
|
@ -722,7 +727,7 @@ static NSNotificationCenter *default_center = nil;
|
|||
- (void) dealloc
|
||||
{
|
||||
[self finalize];
|
||||
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -758,10 +763,18 @@ static NSNotificationCenter *default_center = nil;
|
|||
* the notification center before releasing these objects.<br />
|
||||
* </p>
|
||||
*
|
||||
* <p>While it is good practice to remove an observer before releasing it,
|
||||
* currently on MacOS it is possible to remove an observer even after the
|
||||
* object has been deallocated. This is not documented behavior from Apple
|
||||
* and could change at any time. In the interests of compatibility, this behavior
|
||||
* will also be supported here.
|
||||
* </p>
|
||||
*
|
||||
* <p>NB. For MacOS-X compatibility, adding an observer multiple times will
|
||||
* register it to receive multiple copies of any matching notification, however
|
||||
* removing an observer will remove <em>all</em> of the multiple registrations.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
- (void) addObserver: (id)observer
|
||||
selector: (SEL)selector
|
||||
|
@ -793,6 +806,11 @@ static NSNotificationCenter *default_center = nil;
|
|||
|
||||
o = obsNew(TABLE, selector, observer);
|
||||
|
||||
if (object_getClass(observer) == GSNotificationObserverClass)
|
||||
{
|
||||
[TABLE->retainedObjectsTable addObject:observer];
|
||||
}
|
||||
|
||||
/*
|
||||
* Record the Observation in one of the linked lists.
|
||||
*
|
||||
|
@ -1050,15 +1068,15 @@ static NSNotificationCenter *default_center = nil;
|
|||
GSIMapRemoveKey(NAMED, (GSIMapKey)((id)name));
|
||||
}
|
||||
}
|
||||
unlockNCTable(TABLE);
|
||||
|
||||
/* As a special case GSNotificationObserver instances are owned by the
|
||||
* notification center and are released when they are removed.
|
||||
*/
|
||||
if (object_getClass(observer) == GSNotificationObserverClass)
|
||||
if ([TABLE->retainedObjectsTable containsObject:observer])
|
||||
{
|
||||
[TABLE->retainedObjectsTable removeObject:observer];
|
||||
RELEASE(observer);
|
||||
}
|
||||
|
||||
unlockNCTable(TABLE);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue