Home >
With a name like Swiz, it has to be good, right? Welcome back, friends, to part four of our ongoing effort to understand these four Flex frameworks. This time we’re going to look at Swiz, a relative newcomer, created by Chris Scott. Chris had a simple idea to use a powerful but underused Flex feature, Metadata, to implement a concept called Inversion of Control.
Sounds scary? Actually, the point of this effort is to make things easier for you. A big part of the frameworks we’ve looked at so far is not just some classes that you have to create, but some wiring you have to do. You have to make some framework classes, describe them to the framework, and make sure that the code describing them gets called. That overhead can feel like a drag on productivity and maintainability. That’s one thing that Inversion of Control is made to fix.
Here’s an example of what we’re talking about. Remember last week when we set up Mediators to work with the application view, LoginView, and MainView? We fired off a PureMVC command called ViewPrepCommand that reached in and got the reference to each view, created an ApplicationMediator, LoginViewMediator, MainViewMediator, and passed the views in to each. It doesn’t make any difference that we pushed that code into a Command to keep the view clean, we still had to write the code to take those steps. Same thing when we wrote the code to associate LoginEvent with LoginCommand in the TwitteRIAController in the Cairngorm example. We had to go one place to write the code for the event, another place to write the code for the command, and then another to say that we wanted the one to associate with the other. Wouldn’t it be nice if we could, with a minimum amount of code, ask the framework to do that for us?
Consider Flex Binding. Lovely, isn’t it? You mark a property as [Bindable], and then elsewhere you can use the curly brace notation to tell Flex that you want to wire that value up to another property and update that destination property whenever the other changes. This is a lot like Inversion of Control.
The control that we’re talking about here is actually a responsibility - responsibility to get the resources that a particular component needs in place. In the current paradigm we’ve been working with, the component, or a delegate that we create, is responsible for getting the component’s stuff together. IoC means to invert that responsibility up out of the component and into the framework. Instead of going to find and wire up what it wants, a component instead just lets the framework knows what it wants, and the framework does the rest. This requires the component to have knowledge of the framework, but not to have to know the details of where to get things.
We’ll get to see IoC in action with Swiz in a bit, but first let’s talk for a second, as we have with the other frameworks, about how the Swiz flow of events works.
Pretty simple, eh? The user interacts with the view and the view notifies the Controller. How that happens is up to you. You could use events and set the Controller up as an event listener, or you could call the Controller directly. If there’s service work to be done, the Controller will call a Delegate and the Delegate can call the service. Swiz makes it dead simple to wire up the Controller/Delegate communication - IF - the service is an AMF service that you can contact with a RemoteObject. If the service is not a RemoteObject you have to fend for yourself as I found out. More on that in a bit.
When the service call is over and the Controller gets notified, the controller can put some data on the model and act on the view as necessary. The Controller is free to wire up data from the Model to the view PureMVC style, or you can use Binding and let Flex do the work.
Again, pretty simple. But it’s no more than you need to get the job done. The app is separated into the three concerns, services are encapsulated, and the best part, which we’ll see next, is that Swiz takes care of wiring all this stuff together.
You Turn Me Right ‘Round, BabyThat’s an IoC joke, right there. Moving along let’s look in the root application to see some characteristic Swiz code.
twitteria_swiz/src/twitteria_swiz.mxml #20-22
[Bindable]
[Autowire(bean="model")]
public var model:TwitteRIAModel;
This is the reference to the model that the application uses to drive the ViewStack, as it does in the Cairngorm application. You’ve seen a [Bindable] tag before, but what’s that other tag underneath there? Autowire is a Swiz metadata tag. Flex has had metadata around for a while, but recently allowed a compiler option to keep custom metadata. The Swiz swc library adds two tags to the list of metadata that the Flex compiler will keep around, Autowire, and Mediate. We’ll look at Mediate in a bit, but Autowire is the first example of Swiz’s IoC at work. It’s essentially saying “When this view is constructed, go find a bean named ‘model’ and set this property, model, to point to it”. If you’ve come from Java-land to Flex, you know what we mean by bean, but others may not. Lots of talk about beans in Java-land, for those of you who don’t know, but all they mean is some sort of component. Don’t worry about it, and feel free to make as many jokes as you want. As far as I’m concerned, they’re all deserved. Beans! Come on. Don’t even get me started on POJOs.
In case you didn’t notice, this Autowire thing is sweet. We don’t have to worry about where this model comes from. We don’t have to think about if it’s a Singleton or not. All we know is that we want a model, and the framework will make sure we have one when we need it. One note of caution: the property has to be marked public or Swiz won’t be able to assign to it.
So where do these magical beans come from? Well, there is one bit of administrativa we need to take care of to get those beans jumping for us.
twitteria_swiz/src/twitteria_swiz.mxml #8, 24-26
preinitialize="loadBeans()"
...
private function loadBeans():void {
Swiz.loadBeans([Beans]);
}
On preinitialize, which is very early in the Flex bootstrapping process, we call loadBeans, which delegates up to Swiz and mentions where to find them. It’s important that this happen at preinitialize so that Swiz is all ready to go when views that use Swiz metadata are created, including the application itself. Now let’s look at the bean definition file.
twitteria_swiz/src/com/insideria/twitteria/Beans.mxml
<BeanLoader
xmlns="org.swizframework.util.*"
xmlns:api="twitter.api.*"
xmlns:delegates="com.insideria.twitteria.delegates.*"
xmlns:model="com.insideria.twitteria.model.*"
xmlns:controllers="com.insideria.twitteria.controllers.*">
<controllers:ApplicationController id="applicationController" />
<controllers:LoginViewController id="loginViewController" />
<controllers:MainViewController id="mainViewController" />
<model:TwitteRIAModel id="model" />
</BeanLoader>
This BeanLoader is just an MXML file with a tag for any class that you want to Autowire anywhere in the application. Inside we have all the controllers and the model. Notice that the call to loadBeans passes an array, so it’s possible to split up the bean definitions over multiple files for good housekeeping.
I decided to use the Flex binding way of wiring up the view to the model, so that instance that points at model is fair game, just as if we’d looked it up as a Singleton, a la Cairngorm, or gotten ahold of it some other way.
twitteria_swiz/src/twitteria_swiz.mxml #37 (formatted)
<mx:ViewStack selectedIndex="{model.mainViewIndex}">
Just as before, when pressing enter in the password field on LoginView, the login process is kicked off. Here’s what it looks like with Swiz.
twitteria_swiz/src/com/insideria/twitteria/view/LoginView.mxml
#9-14 (formatted)
public function login():void {
var e:DynamicEvent = new
DynamicEvent(LoginViewController.LOG_IN);
e.username = usernameText.text;
e.password = passwordText.text;
Swiz.dispatchEvent(e);
}
First thing we do is to created a DynamicEvent, which is a little used (as far as I know) Flex event that is a dynamic class. That means we can assign to whatever properties we want on it, just like ActionScript’s Object. Swiz doesn’t mandate the use of DynamicEvents, but it slyly suggests that we can use this class instead of the more time-consuming method of creating a new Event for each type of payload. Just remember if you use dynamic objects that the compiler won’t catcher errors for you if you misspell things, but that’s what unit tests are for, right?
Our payload this time is the username and password. Instead of dispatching an event the regular way, we dispatch events through Swiz if we want framework classes to get them. Notice that there’s no controller instance specified on the LoginView, nor does LoginViewController know anything about the view (although both could be true if the application needed it), but LoginViewController is still out there waiting for this LOG_IN event, because it was instantiated in the BeanLoader. How does the controller sign up to get events? Like this:
twitteria_swiz/src/com/insideria/twitteria/controllers/LoginViewController.as
#18-25
[Mediate(event="login", properties="username,password")]
public function login(username:String, password:String):void {
model.username = username;
model.password = password;
var e:Event = new Event(LOGIN_COMPLETE);
Swiz.dispatchEvent(e);
}
Here’s the other metadata tag we mentioned, Mediate. The Mediate tag goes on controller methods that you want called when a certain type of event is dispatched through Swiz. The event argument to the tag needs to match the string type of the event, but sadly it’s not possible to make this point to the same constant that defines that string at this point. Just keep an eye out that they’re the same.
The tag’s properties argument tells Swiz which properties of the incoming event it should grab and pass into the tagged method. The gain is that you don’t have to add an event listener somewhere else, you have the code right here annotating the method. Also, you don’t have to do the boilerplate event wrangling to get data you need out. You say what data you’re expecting and from what type of event, and the framework will get it out for you. That means you can just write regular functions, which has the added benefit of letting you call those functions from other code that doesn’t use events. I didn’t test it, so don’t quote me on it, but it’s also theoretically possible to have more than one Mediate tag per method, I suppose.
Inside the login method we set the username and password on the model, which is, of course, Autowired up on the controller as well.
twitteria_swiz/src/com/insideria/twitteria/controllers/LoginViewController.as
#15-16
[Autowire(bean="model")]
public var model:TwitteRIAModel;
After setting those properties on the model, it then dispatches an event saying that log in is complete. Notice that instead of a DynamicEvent, we’re using just a regular Flash Event here. Either one will work, and Event is fine when we don’t have to carry a payload.
The next step after logging in is loading the timeline, and we do that on the MainViewController.
Loading The TimelineWhen the MainViewController is instantiated from the BeanLoader, it registers to receive the log in event right away.
twitteria_swiz/src/com/insideria/twitteria/controllers/MainViewController.as
#22-24
public function MainViewController() {
Swiz.addEventListener(
LoginViewController.LOGIN_COMPLETE,
loginComplete
);
}
This is another way to listen for events sent through Swiz besides Mediate. Once the event is received, loginComplete is called.
twitteria_swiz/src/com/insideria/twitteria/controllers/MainViewController.as
#53-55
private function loginComplete(e:Event):void {
loadTweets();
}
twitteria_swiz/src/com/insideria/twitteria/controllers/MainViewController.as
#31-34
public function loadTweets():void {
var delegate:TwitterDelegate = new TwitterDelegate(this);
delegate.loadTimeline(username);
}
Now comes the point where we call the delegate to get the latest
timeline. Now, as I mentioned before this part is really easy if you’re using a
service that is wrapped by a RemoteObject.
Then all you’d do is call createCommand,
passing the delegate method to call, its arguments, and a result and fault
callback. As long as the delegate method returned an AsyncToken object, Swiz would then
take care of all the callbacks. That’s a nice set up, but unfortunately it
doesn’t work for us, because we’re not using an AMF service.
As I found out later, the above paragraph is not true. HTTPService and WebService do work with AsyncToken, so only in the case of code like our example project do you need to do any hacking around to work with Swiz.
What I did instead was hack together a more elaborate and depressing solution where I made an interface that I force any object calling the delegate to implement.
twitteria_swiz/src/com/insideria/twitteria/delegates/TwitterResponder.as
#3-10 (formatted)
public interface TwitterResponder {
function get username():String;
function get password():String;
function friendsTimelineResult(tweets:Array):void;
function setStatusResult():void;
}
Then I can make sure I know how the instance of the delegate should get the username and password, and that there’s a callback method for getting the timeline and status results. I’m sure there’s an easier way, but this occurred to me at the time. Some time in the future, I’d like to help Swiz out of this mess and make it just as easy to arbitrarily work with delegates that call any type of service. We’ll see if the time presents itself.
So now calling the delegate, which is the same old guy we’ve been using from project to project, will call back to friendsTimelineResult on the controller when the timeline is loaded, which sets the collection on the model.
twitteria_swiz/src/com/insideria/twitteria/controllers/MainViewController.as
#44-46
public function friendsTimelineResult(tweets:Array):void {
model.currentTweets = new ArrayCollection(tweets);
}
Binding takes over from there and the new list is shown in MainView.
Setting StatusJust as before, pressing enter in the status text field will kick off the chain of events to set status.
twitteria_swiz/src/com/insideria/twitteria/view/MainView.mxml
#15-18
private function setStatus():void {
controller.setStatus(statusText.text);
statusText.clear();
}
This time we again elected to call up to the controller.
twitteria_swiz/src/com/insideria/twitteria/controllers/MainViewController.as
#26-29
public function setStatus(statusMessage:String):void {
var delegate:TwitterDelegate = new TwitterDelegate(this);
delegate.setStatus(statusMessage);
}
The controller calls out to the delegate, and the delegate returns to say that the status is set, so we kick off a load timeline again to get the latest tweets.
twitteria_swiz/src/com/insideria/twitteria/controllers/MainViewController.as
#48-51
public function setStatusResult():void {
// reload tweets to get the newest
loadTweets();
}
And that’s the Swiz version, folks!
Next UpI’m supposed to be leaving the evaluations until the last article, but I will say right away that Swiz certainly delivers on its promise of cutting down boilerplate code. It’s a breeze to work with, and the only tough spot is if you’re not using an AMF service.
Next time we’re going to look at our last framework, Mate, and
see how it takes advantage of MXML to make a simple, declarative Flex
framework.
Read the rest of FrameworkQuest 2008:




Facebook Application Development
Great post - thanks - I've been following SWIZ for quite some time and love its simplicity and it IoC
So, upon further review, an HTTPService call does return an AsyncToken, so working with an HTTPService should work pretty smoothly with Swiz. Sorry for any confusion.
@Mansour - good to hear, thanks!
Nice, kinda like Spring for Flex. ^_^
if you want something even more like Spring for Flex, try Spring for Actionscript (Prana):
http://www.herrodius.com/blog/158
http://http://www.pranaframework.org/
Thanks for continuing in this Framework series, I like it a lot. Mike from the jump manual guide.
Hi,
This is great tutorial. First, I downloaded your code but there are things missing. Namely the window component. I was able to modify to work without the missing code, but now when I compile and run, nothing happens..no errors or anything. The grids appear on the browser of internet marketing but no data is displayed. Please bear in mind that I do not know anything on what I need to do to set up Livecycle. So, could you please email me of call me through internet phone the complete codeset and let me know if there's anyway you could help me diagnose my problem. As a sidenote, I noticed on a previous version of Flex (version 2), there is a Livecycle Data Services ES 2.5.1 comes up as an option when on my Programs launch bar. I'm trying to run version 3 of Flex on a different box, and it does not contain this. Could this be the problem?
Thanks
Frank
Indeed there is a lot of talk about beans in Java-land, for those of you who don’t know, but all they mean is some sort of component.
An I didn't know that the Swiz swc library adds two tags to the list of metadata that the Flex compiler will keep around, Autowire, and Mediate. We’ll look at Mediate in a bit, but Autowire is the first example of Swiz’s IoC at work.
Dave From grow taller for idiots