discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

NSNotification and subclasses


From: Alexander Malmberg
Subject: NSNotification and subclasses
Date: Fri, 09 Aug 2002 01:42:00 +0200

Hi,

Recently, NSNotificationCenter changed to always create its own
NSNotification (GSNotification in practice) object. This broke using
custom sub-classes of NSNotificaion to send extra information outside
the userInfo dictionary, and caused all apps to crash. The text about
sub-classes in:

http://developer.apple.com/techpubs/macosx/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNotification.html

suggests that you're supposed to be able to do this. I've attached a
patch that fixes this (hopefully without breaking anything, but I'm not
sure what the change was intended to do; the NSNotification object
created by postNotificationName:... still gets released before it the
method returns).

This also fixes the apps crashing, but afaict, custom NSNotification
objects aren't used anywhere in the libraries, so I don't know why.
Without this patch, apps would get stuck recursing on something DO (and
gdnc, from what I can tell) related. The core dumps had call stacks
thousands of levels deep.

(Interestingly, the runloop would still run often enough that you
wouldn't notice anything until the app crashed, usually after a few
seconds.)

- Alexander Malmberg
Index: NSNotificationCenter.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/core/base/Source/NSNotificationCenter.m,v
retrieving revision 1.33
diff -u -r1.33 NSNotificationCenter.m
--- NSNotificationCenter.m      7 Aug 2002 13:29:31 -0000       1.33
+++ NSNotificationCenter.m      8 Aug 2002 23:25:22 -0000
@@ -934,15 +934,29 @@
 
 
 /**
- * Posts notification to all the observers that match its NAME and OBJECT.<br 
/>
- * The GNUstep implementation calls -postNotificationName:object:userInfo: to
- * perform the actual posting.
+ * The preferred method for posting a notification.
+ * <br />
+ * For performance reasons, we don't wrap an exception handler round every
+ * message sent to an observer.  This means that, if one observer raises
+ * an exception, later observers in the lists will not get the notification.
  */
-- (void) postNotification: (NSNotification*)notification
+- (void) postNotificationName: (NSString*)name 
+                      object: (id)object
+                    userInfo: (NSDictionary*)info
 {
-  [self postNotificationName: [notification name]
-                     object: [notification object]
-                   userInfo: [notification userInfo]];
+  GSNotification       *notification;
+
+  if (name == nil)
+    {
+      [NSException raise: NSInvalidArgumentException
+                 format: @"Tried to post a notification with no name."];
+    }
+  notification = (id)NSAllocateObject(concrete, 0, NSDefaultMallocZone());
+  notification->_name = [name copyWithZone: GSObjCZone(self)];
+  notification->_object = TEST_RETAIN(object);
+  notification->_info = TEST_RETAIN(info);
+  [self postNotification: notification];
+  RELEASE(notification);
 }
 
 /**
@@ -956,35 +970,32 @@
 }
 
 /**
- * The preferred method for posting a notification.
- * <br />
- * For performance reasons, we don't wrap an exception handler round every
- * message sent to an observer.  This means that, if one observer raises
- * an exception, later observers in the lists will not get the notification.
+ * Posts notification to all the observers that match its NAME and OBJECT.<br 
/>
+ * The GNUstep implementation calls -postNotificationName:object:userInfo: to
+ * perform the actual posting.
  */
-- (void) postNotificationName: (NSString*)name 
-                      object: (id)object
-                    userInfo: (NSDictionary*)info
+- (void) postNotification: (NSNotification*)notification
 {
   Observation  *o;
   unsigned     count;
   volatile GSIArray    a;
   unsigned     arrayBase;
-  GSNotification       *notification;
+  id           object;
+  NSString     *name;
 
-  if (name == nil)
-    {
-      [NSException raise: NSInvalidArgumentException
-                 format: @"Tried to post a notification with no name."];
-    }
-  notification = (id)NSAllocateObject(concrete, 0, NSDefaultMallocZone());
-  name = notification->_name = [name copyWithZone: GSObjCZone(self)];
-  object = notification->_object = TEST_RETAIN(object);
-  notification->_info = TEST_RETAIN(info);
+  if (notification == nil)
+    [NSException raise: NSInvalidArgumentException
+               format: @"Tried to post a nil notification."];
+
+  name = [notification name];
+  object = [notification object];
   if (object != nil)
-    {
-      object = CHEATGC(object);
-    }
+    object = CHEATGC(object);
+
+  if (name == nil)
+    [NSException raise: NSInvalidArgumentException
+               format: @"Tried to post a notification with no name."];
+
   lockNCTable(TABLE);
 
   a = ARRAY;
@@ -1207,14 +1218,12 @@
       GSIArrayRemoveItemsFromIndex(ARRAY, arrayBase);
       unlockNCTable(TABLE);
 
-      DESTROY(notification);   // Get rid of notification we created.
       [localException raise];
     }
   NS_ENDHANDLER
 #endif
 
   unlockNCTable(TABLE);
-  RELEASE(notification);
 }
 
 @end

reply via email to

[Prev in Thread] Current Thread [Next in Thread]