Friends -
I have a package that I installed into a clean image. The app that is contained in the package runs perfectly, and its main view opens fine. The app allows the user to browse a collection of people, and view information about them. The person class contains a bunch of other classes, each of which contain some other classes. The problem: I simply added an instance variable to one of those nested classes, and now the main app won't open. Method STBCollectionProxy(STBProxy)stbFixup: at: iterates through its dictionary, and eventually encounters Dictionary>>add: anAssociation. That method sends the "key" method to the association, which happens to be an instance of SmallInteger - which causes the walkback. My guess is that somehow, the shell view knows about the objects that it displays - but I never set things up that way. I seem to remember some facility for exporting views separately from "business logic". Could someone help me unglue these things, so that I can change the business objects again ? Thanks so much ! - Ken |
Ken,
> The app allows the user to browse a collection of people, and view > information about them. The person class contains a bunch of other classes, > each of which contain some other classes. > > The problem: I simply added an instance variable to one of those nested > classes, and now the main app won't open. It sounds like you have an instance captured (probably as a model) by one of your view resource, and when it's in-filed from the resource, the instance variables don't line up. Have a look at STB Layout Changes on http://www.object-arts.com/wiki/html/Dolphin/BinaryFiler.htm That should allow you to do a #nextPut:, either of nil or a reasonable default value, to make your views work again. Assuming that the layout change caused the problem, the conversion method will "fix" the view immediately, and you really don't need to do anything else. However, it doesn't hurt to re-save the view resource to capture an updated STB stream for your model - that way, the conversion won't need to run every time you (or your end users) open the view. You can "script" the VC to open and save multiple view resources if that's appropriate. FWIW, I've gotten away from deliberately capturing models in view resources. I'm not saying it's a bad practice, but, it didn't help enough to justify the break on refactoring that came with it. I considered creating a "dummy" class with just enough behavior to look like one of the models, but with no instance variables. The idea would be to have the views capture that object and then have it replaced by a presenter in #onViewOpened. As it turns out, that doesn't work terribly well because the point of capturing things in views (IMHO) is to make them look right in the VC, and that can't happen with a dummy object. So, I end up with "holes" in the VC, but no STB hassles. Caveat emptor: I've changed my mind on this before, and might do so again :) Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
Bill -
> It sounds like you have an instance captured (probably as a model) by one of > your view resource, and when it's in-filed from the resource, the instance > variables don't line up. Have a look at STB Layout Changes on > > http://www.object-arts.com/wiki/html/Dolphin/BinaryFiler.htm > > That should allow you to do a #nextPut:, either of nil or a reasonable > default value, to make your views work again. Thanks for your response - but could you please elaborate on this a little ? Frankly, I am surprised that Dolphin somehow allows a View to know so much about an object it presents, that it becomes impossible to change the object - but that's just me ! - Ken |
Ken,
> Thanks for your response - but could you please elaborate on this a > little ? First, make a backup in case this gets ugly. Assuming that you never changed the version number, it will be zero, so add a class-side #stbVersion to answer 1. File in #stbConvertFrom: - it almost always works as-is, unless you are messing around with views themselves; you are changing a model so it will probably be fine. Then create a #stbConvertFromVersion0: method, also on the class-side; #stbConvertFrom: will call it as needed. You might try setting a breakpoint in the last method and opening one of the offending views in the VC, which should give you a chance to look at the data that you are given for the conversion. Basically, you get an array of the instance variables of the old-format object that you are about to convert, and you need to create an array of instance variables for it in the new format. Streams are a nice way to do the job. The example from the Wiki: Something class>>stbConvertFromVersion0:versionArray "Private - Convert version 0 notes to version 1 format. Added #helpText and #searchTag as the fourth and fifth instance variables; note that subclasses will have ivs starting at four, and these need to slide down by two. To acheive this, copy across the first three instance variables, put a couple of nils, and then copy the remainder of the data. Something and its subclasses all have the same STB version, at least for now. See ResourceAccessor for the source of this stream trick; there, the change is a little simpler as the added variable appears at the beginning of the list." | versionStream | versionStream := versionArray readStream. ^Array writeStream nextPutAll:( versionStream next:3 ); nextPut:nil; "helpText" nextPut:nil; "searchTag" nextPutAll:versionStream upToEnd; contents This basically just shoves across three instance variables that the two formats have in common, and adds nil place-holders for two more that have been added - in your case, you might specify default values other than nil. The #upToEnd is something that often (though not always!) takes care of subclasses. In short, think of variables in slots, and your job is to make sure that the new format slots have the right things in them. The more you changed, the more you have to work at it. Note that as you add future changes and corresponding STB version numbers, you'll add #stbConvertFromVersion*: methods, each of which does one incremental conversion. For example, your future #stbConvertFromVersion1: method will get a version one input and create a version 2 output. #stbConvertFrom: will call as many of the methods as needed to make the overall conversion. > Frankly, I am surprised that Dolphin somehow allows a View to know so > much about an object it presents, that it becomes impossible to change > the object - but that's just me ! It _can_ be quite useful. Consider a custom view that draws some kind of design diagram, and suppose that the diagrams always have some kind of border or something. Ok, I'm stretching a bit, but, by placing a model in the view, the border, perhaps drawn by the model, can appear in the VC as the view is being edited, and aspects of that model can be changed to provide different starting points in different view resource names. OTOH, it is STB dependent, and can be quite a break on change. Having tried both approaches, I'm pretty steadily doing setup from Presenter>>onViewOpened, with the cost that my views don't necessarily "look right" in the VC, but, they don't cause me the kinds of problems you are having right now. Also, as tempting as "just edit it in the VC" might be, the problem is that after a while, the configuration details are easy to forget. Any specific questions? This is daunting at first and gets a lot easier after you go through it a couple of times. Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
In reply to this post by Ken Lee-2
"Ken Lee" <[hidden email]> wrote in message
news:[hidden email]... > Bill - > > > It sounds like you have an instance captured (probably as a model) by one of > > your view resource, and when it's in-filed from the resource, the instance > > variables don't line up. Have a look at STB Layout Changes on > > > > http://www.object-arts.com/wiki/html/Dolphin/BinaryFiler.htm > > > > That should allow you to do a #nextPut:, either of nil or a reasonable > > default value, to make your views work again. > > Thanks for your response - but could you please elaborate on this a > little ? > > Frankly, I am surprised that Dolphin somehow allows a View to know so > much about an object it presents, that it becomes impossible to change > the object - but that's just me ! > > - Ken It may not be directly applicable in this case, but a useful trick to know about during development is to have any view resources containing a view one is about to add instance variables to (or otherwise modify) open in View Composers. These "running" instances will be updated by the normal mechanisms that the ClassBuilder uses to update existing instances when the shape of a class changes. One can then save down the views with the new shape. Obviously one must open the view resources before modifying the class definition, or if one forgets to do that it is probably worth reversing out the change temporarily so that one can load up the view resources. Other useful tips to minimize the amount of work one needs to do writing STB conversions: - Add some spare instance variables. This is certainly worth doing when one finds the need to write an STB conversion, as otherwise it will probably become necessary again in the near future. - Avoid rearranging the instance variables (and that includes deleting old ones), since this will make the STB conversion much harder, especially if there are subclasses. - The STBDebugger can be helpful in finding out precisely what is ending up in a view resource. It's use is straightforward (e.g. (STBDebugger on: <stream>) [next|basicNext]). It isn't really a debugger so much as a disassembler which prints its output to the Transcript. Regards Blair |
Blair-
> It may not be directly applicable in this case, but a useful trick to know > about during development is to have any view resources containing a view one > is about to add instance variables to (or otherwise modify) open in View > Composers. These "running" instances will be updated by the normal > mechanisms that the ClassBuilder uses to update existing instances when the > shape of a class changes. One can then save down the views with the new > shape. Obviously one must open the view resources before modifying the class > definition, or if one forgets to do that it is probably worth reversing out > the change temporarily so that one can load up the view resources. Thanks for your help ! I have tried this, but I get the same result. Perhaps I am missing something obvious. I have a View that contains a custom View. I opened up the main View in the View Composer, and then added a variable to the class in question. I saved the main View. I then tried to save the package, and got a dialog box with the following message: "SmallInteger does not understand #key The package will not load if saved in this form so the package file has not been saved. Would you like to browse the package prerequisites in order to track down the problem ?" If I press the Yes button, a walkback occurs, with the message "SmallInteger does not understand #key". If I press the Debug button to have a look at the walkback, I get another walkback, saying the same thing. Note that the class to which I am adding an instance variable is not a View, or the custom View, but a class that is deeply nested in the class that is presented by the main View and its custom View. The main view has a list presenter that shows you a list of person names, and when you select a person, the custom View represents information about the person. The class to which I am adding an instance variable, is nested way down in the person class. For example, it represents something like the phone number, to which I am adding an area code. |
In reply to this post by Blair McGlashan
> It may not be directly applicable in this case, but a useful trick to know
> about during development is to have any view resources containing a view one > is about to add instance variables to (or otherwise modify) open in View > Composers. These "running" instances will be updated by the normal > mechanisms that the ClassBuilder uses to update existing instances when the > shape of a class changes. One can then save down the views with the new > shape. Obviously one must open the view resources before modifying the class > definition, or if one forgets to do that it is probably worth reversing out > the change temporarily so that one can load up the view resources. In light of this not working, I have tried refactoring. I created a new class, gave it all the same methods and instance variables, and added a few variables. I renamed all references to the old class, to the new one. I opened the View, and everything worked nicely. I deleted the original class, and removed it from its package. Nevertheless, the package cannot be saved, because there are *invisible* references to the now-non-existent class - over which I have no control. I freely admit that I am unable to fix this problem by following your or Bill's kind advice. I am not the most clever developer. At the same time, I find this general design principle to be inconsistent with the excellence that permeates the rest of Dolphin. Is there not some other, simple solution - for a simpleton like me ? Best wishes, Ken |
Ken,
> Nevertheless, the package cannot be saved, because there are > *invisible* references to the now-non-existent class - over which I > have no control. If you haven't tried already, click on the "panic" button in the Dolphin system folder. That often fixes things like this. Make sure you save any open workspaces beforehand. -- Louis |
In reply to this post by Ken Lee-2
Ken,
> In light of this not working, I have tried refactoring. I created a > new class, gave it all the same methods and instance variables, and > added a few variables. I renamed all references to the old class, to > the new one. I opened the View, and everything worked nicely. I > deleted the original class, and removed it from its package. > Nevertheless, the package cannot be saved, because there are > *invisible* references to the now-non-existent class - over which I > have no control. Latent might be a better word for them, and you do have control. You can either delete the view resources and rebuild them, or you can put back the class that they need to load. The latter might not work in your current image because of the changes you've made. > I freely admit that I am unable to fix this problem by following your > or Bill's kind advice. I am not the most clever developer. At the same > time, I find this general design principle to be inconsistent with the > excellence that permeates the rest of Dolphin. Is there not some > other, simple solution - for a simpleton like me ? STB versioning is definitely not simple the first time, so don't beat yourself up over it. If you're willing to work through it, I'm confident that we can fix the problem - your first step would probably be to restore that backup I mentioned at the beginning :) From there, a few questions and file-ins later, we should have it working. If you don't want to do that, just open the resource browser and delete the broken resources, then rebuild them. As for this representing a "lack of excellence" in Dolphin, I don't agree. It *is* a consequence of a design decision to use binary filed prototypes vs. source code to create composite views. Your options include: (1) delete/recreate view resources that break; (2) Use STB versioning to fix same; (3) avoid capturing your own objects in view resources; (4) use my ViewGenerator goodie so that view resources become discardable intermediates. I use all of the above methods for various projects. Simple view resouces are often easier to recreate than to salvage. ViewGenerator is probably too drastic for most situations. It got started with a seriously big presenter that is connected to a very structured model. It was cheaper to write and debug ViewGenerator than to try to create that monster by hand. I use a subclass of ViewGenerator for that project. More recently, I've been experimenting with using it for more routine tasks, but, it's too soon to say whether it's worth the effort. Also, have a look at http://www.mitchellscientific.com/smalltalk/PresenterGenTool.htm which tackles the MVP code generating problem from a different angle. My tools start with meta data and generate the whole thing, Chris' allow you to draw the interface and then he takes over. That won't help in your current situation, but, you might find that it saves time for the situations that need a little recovery work. Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
Free forum by Nabble | Edit this page |