aodz

FrameworkQuest 2008 Part 4: IoC With Swiz

Posted on: January 16, 2009


FrameworkQuest Part 4 by Tony Hillerson
Find the original post here

FrameworkQuest 2008: Introduction
FrameworkQuest 2008 Part 2: Get Control with Cairngorm
FrameworkQuest 2008 Part 3: Agnostic Views with PureMVC
FrameworkQuest 2008 Part 4: IoC With Swiz
FrameworkQuest 2008 Part 5: Mate, the Pure MXML Framework
FrameworkQuest 2008 Part 6: The Exciting Conclusion

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, Baby

That’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}">

Logging In

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 Timeline

When 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.

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 Status

Just 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 Up

I’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 more from
Tony Hillerson
.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

I have moved to a different location

check out my new home Flexout

calendar

January 2009
M T W T F S S
« Dec   Feb »
 1234
567891011
12131415161718
19202122232425
262728293031  

Blog Stat

  • 83,676 Hop's so far!!!

follow me

Archives

Linkedin Blogger Twitter Youtube Orkut

Top Clicks

  • None

latest flickr photos

deep in the jungle

little umbrella

poor jumbo!

solitude

over the rice paddy!

More Photos

top rated

%d bloggers like this: