Handling circular dependencies in Swiz Framework

Swiz is an amazing framework. I was playing around with it this weekend converting a simple Cairngorm project. Swiz handled all autowiring without any problems, until I had to access autowired bean from getter of another autowired bean, that's where I ran into the notorious TypeError: Error #1009: Cannot access a property or method of a null object reference. The problem is that in this case there is no way that Swiz could know that injected property is using another autowired bean in its getter. Note that I was using version 0.6.4-flex3, in latter versions this issue can be fixed or better work around found.

Here are snippets from my classes:

When swiz autowires beans in BeanLoader, LoginPresentationModel comes before ApplicationModel, and when it tries to set up binding between LoginPresentationModel.languageToTranslate and ApplicationModel.languageToTranslate flex throws NPE, as a result of ApplicationModel.so being null at this point. If ApplicationModel came first in the list of candidates for autowiring then I wouldn't get this NPE.

There are couple solutions for this problem:

The first one is to add a condition to the property getter that returns some default value if "so" is null. That would leave the binding to be created.

This solution just doesn't look right.

Another way, which I'm using at least for now, is to manually specify the bean to inject.

In Beans.mxml

You can also implement IInitializingBean and let the controller initialize SO persisted data in the IInitializingBean initialize method.
It will be called after dependencies have been injected. This is much cleaner anyway and keeps the model lightweight.

Comment

Displaying multiple consecutive Flex Calendars

The Flex DateChooser is notorious for being difficult to work with and extend. In a recent project I was developing a scheduling mechanism and wanted to display more than one month at a time to the user. While searching for other components utilizing a calendar I found that not much has been done with customizing the DateChooser.

I started with laying out a customizable number of calendars in a row, and added buttons to navigate forward and backward month by month. When navigating all calendars change at the same time and stay in consecutive order so you can see a span of time instead of being confined to one month.

I also added in listeners for selecting a date from one calendar so that there would be only one currently selected date across all calendars.. I finished it off with redispatching a dateChanged event to make it easy for outside components to listen for a date being selected.

Feel free to make use of this component in your own projects and post any comments or questions, the code can be found here in our SVN.

Comments

Custom Xcode Templates with connected XIB / NIB

I recently found myself complaining about the many ways that UITableViewController falls short for the hundredth time. It is fine if you are only concerned with displaying a single table, but adding any other controls becomes difficult. There are also a few bugs with UITableView that require additional views to work around, so it’s common to add more views even if you are using a very simple table. There is a very clear workaround for all of these things, which is to use UIViewController and implement the UITableViewDataSource and UITableViewDelegate protocols yourself. There is an Xcode File Template for a UITableViewController that stubs in all of these methods for you, which is super useful. I wanted to create a template with the same stubs but with the UIViewController+UITableViewDataSource/UITableViewDelegate pattern.

The basics of doing this are simple enough. Copy the “UITableViewController subclass with XIB.pbfiletemplate” folder from

/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/File Templates/Cocoa Touch Class/

to somewhere you want to edit it, then edit the class.m and class.h files until they look like what you want. In our case we added a few things and removed a few things from the .m, and made the appropriate class changes in the .h. Copy the resulting folder into

~/Library/Application Support/Developer/Shared/Xcode/File Templates/Cocoa Touch Class/

(you may have to create some of those folders) and it’ll appear in the source list in Xcode.

However, I wanted to get a bit fancier. Shouldn’t my template come with a XIB already prewired with outlets from my controller to a view and tableview, as well as delegate/datasource connections from the tableview to the controller? Seems like the point of having the template is to be able to write code as soon as possible, so I decided I’d hook up the XIB beforehand.

The first step is to rename the view.xib.preprocessed file to view.xib, so that we can open it in Interface Builder. I added a UITableView as a subclass of the main view. The main view is already connected to File’s Owner’s view property, exactly as we want. We want to connect the tableview to the tableView outlet of our new class. It seems that Interface Builder isn’t able to decipher the template class.h to figure out that our class has this outlet though. I thought I was out of luck, but then I remembered that the X in XIB stands for XML (or at least I think it does!).

Open the XIB in your favorite text editor and you’ll see (fairly) straightforward XML. Search for the line

<object class="NSMutableArray" key="connectionRecords">.

This array contains all of the connections set up in IB. We want to add 3 connections, so head to the bottom of this array (line before <object class="IBMutableOrderedSet" key="objectRecords">). Our connections look like


<object class="IBConnectionRecord">
    <object class="IBCocoaTouchOutletConnection" key="connection">
        <string key="label">mTableView</string>
        <reference key="source" ref="372490531"/>
        <reference key="destination" ref="873029372"/>
    </object>
    <int key="connectionID">11</int>
</object>

<object class="IBConnectionRecord">
    <object class="IBCocoaTouchOutletConnection" key="connection">
        <string key="label">dataSource</string>
        <reference key="source" ref="873029372"/>
        <reference key="destination" ref="372490531"/>
    </object>
    <int key="connectionID">12</int>
</object>

<object class="IBConnectionRecord">
    <object class="IBCocoaTouchOutletConnection" key="connection">
        <string key="label">delegate</string>
        <reference key="source" ref="873029372"/>
        <reference key="destination" ref="372490531"/>
    </object>
    <int key="connectionID">13</int>
</object>

The “ref=” parts refer to the objects defined in the (<object class="IBMutableOrderedSet" key="objectRecords">) section. Each object is given a unique ID. In our case we want the ref of “File’s Owner” (372490531 for us). The ref of our TableView is 873029372. Your values may differ. The one tricky thing here is that the connectionID must be unique (I think) so look above and make sure you haven’t duplicated any of them. If you have, just start counting at the next number. I thought I would be good to go at this point, but if you try to use this template and then build the project you will get a warning (an error if you’re treating warnings as errors as you should) about the outlet being connected but no longer defined in your controller. The reason for this is a bit further in the XML file. Search for the line

<string key="className">«FILEBASENAMEASIDENTIFIER»</string>

This is in the middle of the definition for your new controller class. Add the following lines (under the “superClassName” line, though it shouldn’t matter).

<object class="NSMutableDictionary" key="outlets">
    <string key="NS.key.0">mTableView</string>
    <string key="NS.object.0">UITableView</string>
</object>

What does this mean? It is a dictionary mapping outlet names to type. So NS.key.X maps to type of NS.object.X. In our case we just have the one outlet to define so it's just the two lines.

With that complete, save the XIB, and rename it to view.xib.unpreprocessed. You can now edit the TemplateInfo.plist file to give your template a decent description.

Your file template is ready to go, just drop it in

~/Library/Application Support/Developer/Shared/Xcode/File Templates/Cocoa Touch Class/

and get back to coding.

Comments

Getting to know Adobe PatchPanel

Adobe has a new way to easily create Actionscript / Flex apps that can deeply control the Creative Suite products.

PatchPanel is a library from Adobe Labs. It acts as a lightweight bridge between your Flex app and a CS3 / CS4 application. If you're used to Flex, this makes it really simple to quickly put together an interface, make a plugin and automate complex tasks.

Of course, you still need to learn what API calls to make to talk to your document.

A brief overview of the setup:

  1. Your project must include the PatchPanel SWC as an imported library.
  2. To run / deliver your plugin, the compiled swf must be put in the correct location in the Adobe host application directory, as well as a special JavaScript file that loads the swf into the host application.

For more detailed information on how to get started, see PatchPanel - Adobe Labs

InDesign API - Miscellaneous Tips

I have been making a plugin for InDesign the last few months. There is some documentation out there, but not a huge amount. The API document often has poor descriptions of methods, so it can became a bit of a guessing game. Here are a few words of wisdom to get you started.

Setting the Dimensions

The install JavaScript file allows you to set the width and height of your plugin. It should match the dimensions in your Application.mxml file. At first I was unsure why you would want to set this; the plugin ends up being whatever size specified in the mxml anyway. But what happens is, it initially loads at the size given in the JavaScript file, and then half a second later it RESIZES to the mxml values.

There is always a small gap of light grey space between the edge of your application and the actual edge of the window, about 3 pixels. I found this frustrating but could not find a way to avoid it. Furthermore, I noticed the right and bottom edges were a dark blue/grey instead of light grey. This was even more frustrating.

Eventually i figured out these darker edges only appear if the width and height given in the JavaScript install file are DIFFERENT from the width and height in the application mxml. The dark color is actually just the Flex default application background color. So I have settled with ensuring the specified dimensions match each other, and making my background color of my application a matching light grey.

The Document

From anywhere in your application, you can access the current document with:

Speed

Some properties are considerably slower to access than others. For example:

is much faster than

The latter will recursively search the hierarchy of page items and return a flat Array. If you are going to be calling it multiple times or in a loop, you are better off calling it once and storing the result.

PageItems have a property 'associatedXMLElement'. You can use this property to find how items are tagged in the document. But using it is also relatively slow (e.g. if you are doing it 100 times, you will notice it).

Stroke

I wanted to dynamically set the stroke width of a rectangle to different values. Whenever I set it to 0, it was invisible as expected, but when I set it back to say '3', it would NOT appear again. For the longest time I could not figure out why. Turns out, when you set stroke to 0 InDesign automatically sets the stroke color to 'None' for you, but when you set the stroke back to a number bigger than 0, the color stays as 'None.' (I don't know why, because this isn't how InDesign behaves as an application). So my workaround was to 'remember' what color the stroke used to be, and set it back manually myself.

Events

There is very poor / limited documentation on how to listen to InDesign events. Apparently you can register callback functions for certain events, but I could not get it working. Hopefully with the formal release of PatchPanel, this will all be documented more thoroughly.

Conclusion

I found PatchPanel very easy to get going with and accomplish most tasks. Its pretty cool when you start to realize just how much power and control it gives you; however, the occasional, seemingly simple task can become frustratingly time-consuming to figure out. But there is a forum out there, and with time I assume there will be more useful documentation.

Comment

Programmatically creating bar or column charts in Flex

Creating Flex charts and series is easy if you lay them out in MXML.  But creating them programmatically can be a little trickier.  Here's an issue that's not too difficult to figure out but that I found wasn't documented in any other articles online.

Every chart object holds an array of series objects: LineSeries, AreaSeries, BarSeries, etc.  One day I wanted to create a chart that showed columns of data so I wrote what I thought would be a chart with ColumnSeries.

However, I was stumped when no series showed up on my chart.  Where did they go?

Turns out, all ColumnSeries have to be included in a ColumnSet, and the same for BarSeries in a BarSet.  The *Set objects in turn have another array of all the *Series they hold.  So a chart that correctly houses ColumnSeries would look like this:

Although the idea of having an array of series objects within an array called series on a chart seems a little difficult, it actually makes a lot of sense. The *Series are stored within an overall *Set object because they are grouped together and are able to be stacked. Using multiple *Sets on one chart allows these groupings to stay separate and stacked charts to stack correctly without being lumped together.

Comments