Updater Object In 2 Xib in the same application

Asked by Sandro Noel

I folowed the instruction in the documentation, I placed a Updater object in my mainmenu.xib file and another one in my preferences.xib file. Accepting for notion that Updater object is a shared instance.

Whenver I instanciate my preferences window, the debugger complains with <objc_exception_throw+9>
to remove complaint that I need to delete one of the instance, and then everything is fine.

#0 0x93e2ce17 in objc_exception_throw
#1 0x90361dcb in +[NSException raise:format:arguments:]
#2 0x90361e0a in +[NSException raise:format:]
#3 0x94ed03dd in -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:]
#4 0x94ed01b4 in -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:]
#5 0x92651d05 in -[NSController removeObserver:forKeyPath:]
#6 0x0006307a in dyld_stub_roundf
#7 0x00063b0e in dyld_stub_roundf
#8 0x000624d6 in dyld_stub_roundf
#9 0x000625fe in dyld_stub_roundf
#10 0x924387a7 in -[NSCustomObject nibInstantiate]
#11 0x92419199 in -[NSIBObjectData instantiateObject:]
#12 0x924188ba in -[NSIBObjectData nibInstantiateWithOwner:topLevelObjects:]
#13 0x9240efba in loadNib
#14 0x9240e91c in +[NSBundle(NSNibLoading) _loadNibFile:nameTable:withZone:ownerBundle:]
#15 0x9240e55f in +[NSBundle(NSNibLoading) loadNibFile:externalNameTable:withZone:]
#16 0x9244e8a1 in -[NSWindowController loadWindow]
#17 0x9244e63a in -[NSWindowController window]
#18 0x000076d4 in -[BMAppDelegate showPreferences:] at BMAppDelegate.m:869
#19 0x92519e8f in -[NSApplication sendAction:to:from:]

Anny suggestion ? i'm using the latest framework, Sparkle 1.5b6.
thank you.

Question information

Language:
English Edit question
Status:
Solved
For:
Sparkle Edit question
Assignee:
No assignee Edit question
Solved by:
Andy Matuschak
Solved:
Last query:
Last reply:
Revision history for this message
Best Andy Matuschak (andymatuschak) said :
#1

SUUpdater is not *that* aggressive in maintaing its shared instance-ness. I recommend you make the updater a property of your app delegate and access it in your preferences .xib that way.

Revision history for this message
Sandro Noel (sandro-noel) said :
#2

ok, i'll try that.

thank you!

Revision history for this message
Sandro Noel (sandro-noel) said :
#3

Thanks Andy Matuschak, that solved my question.

Revision history for this message
Hofman (cmhofman) said :
#4

This makes no sense. The SUUpdater instance SHOULD be unique in this case. I think there's something else wrong. Though I don't understand the description, and I wonder what exception is thrown. Could it be that you're binding the updater to something?

Revision history for this message
Andy Matuschak (andymatuschak) said :
#5

Weeeell, I'm not so sure about that, Hofman. We don't override allocWithZone.

Revision history for this message
Sandro Noel (sandro-noel) said :
#6

No the updater object was in both nib's not bound to anything.
just having 2 instances of the object breaks, even if it is not connected to any controls or properties.

I solved the problem in moving all my property window's related stuff to the main nib.

Revision history for this message
Hofman (cmhofman) said :
#7

Not overriding allocWithZone: is not a relevant issue, because all custom objects in a nib are created by sending alloc+init (and before anything else is done with it), an uninitialized object will never be used for anything. And the updater returned by -init should always be the shared instance.

Now if the bundle objects were not unique, then the bundlePath should be used as the key in the dictionary. Much of the code assumes that the updater is shared.

BTW, I still don't know what the exception is.

Revision history for this message
Andy Matuschak (andymatuschak) said :
#8

I thought they're all created by sending alloc + initWithCoder.

Revision history for this message
Hofman (cmhofman) said :
#9

No, not custom objects. NSObject does not even implement NSCoding. Custom subclasses of NSObject (and NSWindow, NSView, and NSControl) are instantiated using the designated initializer, which for NSObject is just -init.

Revision history for this message
Sandro Noel (sandro-noel) said :
#10

instead of arguing for semantics why don't you guy's try it out.

1: mainmenu.xib, add a updater object foloing the instructions in the documentation
2: bind a check updates button to the updater object
3: save the nib.

4: create a window Xib for the preference pane,
5: instanciate another Updater object foloing the preferences instruction in the documentation.

create the glue code to load the nib and show the preference window, ino debug mode XCode will will report a binding problem.

a bit of code... load the nib and show the window.

 if (!preferenceWindowController) {
  preferenceWindowController = [[PreferenceWindowController alloc] init];
 }
 preferenceWindowController.mount = mount;
 [preferenceWindowController showWindow:self];

Revision history for this message
Andy Matuschak (andymatuschak) said :
#11

An excellent point. :)

I'll give it a try next time I'm hitting the bug queue.

Revision history for this message
Hofman (cmhofman) said :
#12

First of all: this is not semantics, it's an important part of the design of Sparkle. If this fails, there's a serious bug somewhere.

Also, when I do what you say I see no problems.

Revision history for this message
Sandro Noel (sandro-noel) said :
#13

humm.

I've tried it again and again...

Revision history for this message
Hofman (cmhofman) said :
#14

me too...

Revision history for this message
Hofman (cmhofman) said :
#15

I wonder if it's not the -unregisterAsObserver in -[SUUpdater dealloc]. That's potentially dangerous and moreover totally unnecessary, because instances that did register as observer will never be deallocated (as they're retained by the sharedUpdaters dictionary), while instances that are deallocated are never initialized (and therefore never registered).

Sandro, perhaps you can rebuild Sparkle with that line (SUUpdater line 373) commented out, and use that build instead in your test case?

Revision history for this message
Tony Arnold (tony-tonyarnold) said :
#16

Hofman, I was having the same issue and have done as you've indicated. It certainly stops the exception from occurring, but what other flow on effects will this have? Is there a cleaner answer to this problem?

Revision history for this message
Nathan Kinsinger (nkinsinger) said :
#17

It is -unregisterAsObserver that is causing the NSException.

Andy, many of us have a breakpoint set for NSException (and/or objc_exception_throw) in XCode. So every time we run the app and get to the point of the second nib instance it causes the breakpoint to fire and stop execution. This gets rather annoying after a while. :)

I solved this by adding a flag to SUUpdater called hasRegisteredObservers. I set it in -registerAsObserver and in -unregisterAsObserver if it is not set it returns.

No more unnecessary NSExceptions.

Revision history for this message
Andy Matuschak (andymatuschak) said :
#18

Ah, thanks. See related bug.