JavaFX: Properties on Steroids

At the heart of JavaFX is its scenegraph, a structure that includes (perhaps many) nodes. The JavaFX rendering engine displays these nodes and ultimately what you see depends on the properties of these nodes.

Properties are oh-so-important. They make a Circle red or a Rectangle 50 pixels wide. They determine the gradient for a background color or whether or not some text includes reflection or a drop shadow effect. You manipulate nodes with layout components—which are themselves nodes—by setting properties such as spacing or alignment. When your application includes animation, JavaFX updates a node’s properties over time—perhaps a node’s position, its rotation, or its opacity.

Before we look at JavaFX properties in detail, let’s review JavaBean properties first. JavaBean properties support encapsulation and a well-defined naming convention. You can create read-write properties, read-only properties, and immutable properties.

For example, here is a simple Person JavaBean with property fullname. (In fact, once we write the instance variable fullname, an IDE can generate the getter and setter.) Because we provide both getter and setter for this String property, the property is read-write. A Person object is built with a default constructor.

public class Person {
    private String fullname = "";

    public String getFullname() {
        return fullname;
    }

    public void setFullname(String fullname) {
        this.fullname = fullname;
    }

    @Override
    public String toString() {
        return getFullname();
    }
}

We can use Person as follows.

    Person p = new Person();
    p.setFullname("Joe Smith");
    System.out.println(p);      // Joe Smith

Okay, so what are JavaFX properties and how are they different from regular JavaBean properties? JavaFX properties are JavaBean properties on steroids. That is, like JavaBean properties, they support encapsulation, a well-defined naming convention, as well as read-only, read-write, and immutable attributes. But there’s more. To see the difference, let’s create a Person POJO with a JavaFX property.

public class Person {
    private StringProperty fullname =
        new SimpleStringProperty(this, "fullname", "");

    public final StringProperty fullnameProperty() {
        return fullname;
    }

    public final String getFullname() {
        return fullname.get();
    }

    public final void setFullname(String fullname) {
        this.fullname.set(fullname);
    }

    @Override
    public String toString() {
        return getFullname();
    }
}

You’ll notice right away that JavaFX properties include additional implementation code. First, the instance variable type is no longer String, but StringProperty, a type that wraps a String value and provides enhanced JavaFX property behaviors and structure, as you will soon see.

Second, conforming to the JavaFX property naming convention, you access a JavaFX property exactly the same as a JavaBean property. This means client code doesn’t change.

    // unchanged from JavaBean property
    Person p = new Person();
    p.setFullname("Joe Smith");
    System.out.println(p);            // Joe Smith

Third, also confirming to the JavaFX property naming convention, you provide access to the Property itself with method propertynameProperty(). Here is method fullnameProperty() again.

    public final StringProperty fullnameProperty() {
        return fullname;
    }

Fourth, JavaFX properties store contextual information. Method getBean() returns a reference to the enclosing object and getName() returns the property’s name. Here, we initialize these values in the property’s constructor, along with an empty String to use as its initial value.

    private StringProperty fullname =
            new SimpleStringProperty(this, "fullname", "");

And, we can use these methods as follows.

    System.out.println(p.fullnameProperty().getBean());
    // returns p and prints 'Joe Smith'
    System.out.println(p.fullnameProperty().getName());
    // prints 'fullname'

As alluded to earlier, JavaFX properties support additional behaviors. JavaFX properties are observable, which means you can attach listeners and define event handlers when a property value changes or becomes invalid. JavaFX properties also support unidirectional and bidirectional binding and unbinding. Binding lets properties participate in dependencies with other property values. Unbinding removes any dependencies. These are powerful constructs that let JavaFX developers write code that easily synchronizes itself based on changing values. These behaviors are important for responsive UIs as well as animation.

Because all JavaFX nodes contain many JavaFX properties, the JavaFX API does not implement properties in the straightforward way I have described. Instead, JavaFX nodes use lazy evaluation for properties. Thus, for any given property, if a node object only gets and sets values, the overhead for that property is equivalent to a regular JavaBean property.

Our Person POJO with its JavaFX property could be re-implemented as follows. Now the actual JavaFX property is created only when the StringProperty object is accessed with fullnameProperty().

public class Person {
    private String _fullname = "";
    private StringProperty fullname;

    public final StringProperty fullnameProperty() {
        if (fullname == null) {
            fullname = new SimpleStringProperty(
                    this, "fullname", _fullname);
        }
        return fullname;
    }

    public final String getFullname() {
        if (fullname == null) {
            return _fullname;
        }
        else return fullname.get();
    }

    public final void setFullname(String fullname) {
        if (this.fullname == null) {
            _fullname = fullname;
        }
        else this.fullname.set(fullname);
    }

    @Override
    public String toString() {
        return getFullname();
    }
}

Note that our user code only inflates fullname (that is, invokes the SimpleStringProperty constructor) after the first call to p.fullnameProperty(), as shown here.

    Person p = new Person();
    p.setFullname("Joe Smith");
    System.out.println(p);

    // JavaFX Property fullname inflated here:
    System.out.println(p.fullnameProperty().getBean());
    // prints 'Joe Smith'
    System.out.println(p.fullnameProperty().getName());
    // prints 'fullname'

What about JavaFX properties with types other than String? JavaFX supports the following property types.

    BooleanProperty, DoubleProperty, FloatProperty,
    IntegerProperty, LongProperty, ObjectProperty<T>, 
    StringProperty

These are abstract types and are instantiated with SimpleBooleanProperty, SimpleDoubleProperty, and so forth.

We’ll explore examples with JavaFX properties that use binding next.

Posted in JavaFX | Tagged , , | 4 Comments

Adding Animation with JavaFX: Spicing Up a Clear

We return to the same drawing program we described in two previous posts, Sketch Pad: Custom Binding and JavaFX Sketch Pad: Version 2. In this third version, we’re going to spice up the Clear button by animating a fade. That is, when a user clicks Clear, the drawing elements fade out, one at a time in the reverse order in which they were drawn. So, in the following screenshot with a wonderful hand-drawn greeting (“Hi JavaFX!”) on a dark blue background, the exclamation point fades first, then the ‘X’, followed by the ‘F’, and so on. The last to fade are the dark blue background strokes.
Screenshot of Draw Program with Animation

Here is the original Clear button event handler, which simply removes all of the Path nodes in Group lineGroup.

Button btnClear = new Button();
btnClear.setText("Clear");
btnClear.setOnAction(new EventHandler<ActionEvent>() {
    public void handle(ActionEvent event) {
        lineGroup.getChildren().removeAll(
              lineGroup.getChildren());
    }
});

In order to construct an animated fade, we’ll use JavaFX Transitions. Transitions are high-level animation constructs that build timelines, key frames, and key values for you. Transitions are defined to animate key JavaFX node properties. For example, the FadeTransition animates opacity, TranslateTransition animates translateX, translateY, and translateZ, FillTransition animates fill, and ScaleTransition animates the scaleX, scaleY, and scaleZ values.

Furthermore, JavaFX lets you group animations into parallel or sequential transitions. Parallel transitions manage a collection of animations that execute in parallel, while sequential transitions manage animations that execute one after the other. For our application, we’ll use a FadeTransition to fade the nodes and a sequential transition to fade the Path nodes one at a time.

// Class variable
private SequentialTransition seqtran = null;
. . .

Recall that Group lineGroup holds a collection of Path nodes. Each node contains one or more PathElements that form the drawing element. Let’s build a FadeTransition for each Path node. A FadeTransition animates a node’s opacityProperty. To fade out a node (have it disappear), set FadeTransition’s toValue to 0.0. To fade in a node (make it appear), set toValue to 1.0. If you don’t provide a value for fromValue, FadeTransition uses the node opacityProperty‘s current value.

So let’s see how our new Clear button event handler works with Transitions. First, if the drawing canvas is empty, we don’t do anything and just return. If the sequential transition (seqtran) isn’t null, then we’ll stop it. We instantiate a new SequentialTransition and go through the collection of nodes in Group lineGroup to construct a FadeTransition for each node. We specify its duration to be 1,000 milliseconds, set toValue to 0 (making the node fade out), and set interpolator to Interpolator.EASE_BOTH. The default interpolator is LINEAR, providing a constant rate of change for the animation. EASE_IN provides a slower rate of change at the onset of animation, whereas EASE_OUT is a slower rate of change at the end. EASE_BOTH provides slowing at both ends of the animation.

After configuring the FadeTransition, we add it to the beginning of the SequentialTransition’s collection of animations, providing the reverse ordering.

When everything is configured, we initiate the sequential animation with method playFromStart().

Button btnClear = new Button();
btnClear.setText("Clear");
btnClear.setOnAction(new EventHandler<ActionEvent>() {
    public void handle(ActionEvent event) {
        if (lineGroup.getChildren().size() == 0) {
            return;
        }
        if (seqtran != null) {
            seqtran.stop();
        }
        seqtran = new SequentialTransition();
        for (final Node node : lineGroup.getChildren()) {
            FadeTransition ft = new FadeTransition(
                     Duration.millis(1000), node);
            ft.setToValue(0.0);
            ft.setInterpolator(Interpolator.EASE_BOTH);
            // fade in reverse order
            seqtran.getChildren().add(0, ft);
        }

        // Code here to remove the nodes from Group lineGroup
        . . .
        seqtran.playFromStart();
    }
});

Ah, but we aren’t quite finished yet. We don’t want to just fade out the nodes, we also want to remove them from the scene graph. To do this, we must make sure the fade animation is finished. No problem. First, we’ll specify a timeline to handle the removal and add this timeline to the end of the sequential transition. We provide an onFinished function for the KeyFrame and put the code that removes the nodes in the onFinished function.

Here is the rest of the Clear button’s event handler. Note that the KeyFrame’s duration must not be zero, or the onFinished function does not get invoked. Also, here we specify the onFinished function as part of the KeyFrame constructor (which is why you don’t see onFinished in the configuration code).

// Class variable
private Timeline timeline = null;
. . .
// inside btnClear event handler
// Code here to remove the nodes from Group lineGroup
. . .
if (timeline != null) {
    timeline.stop();
}
timeline = new Timeline();
timeline.getKeyFrames().add(
        new KeyFrame(Duration.millis(1),
        new EventHandler<ActionEvent>() {
            public void handle(ActionEvent event) {
                lineGroup.getChildren().removeAll(
                    lineGroup.getChildren());
            }
        }));
seqtran.getChildren().add(timeline);

Download the Sketch Pad with Animated Clear JavaFX source code here.

Posted in JavaFX | Tagged , , , , , | 1 Comment

JavaFX Sketch Pad: Version 2

In our previous post we presented a JavaFX Sketch Pad example that uses three RGB sliders to manipulate a drawing line’s color. In this post, we’ll use a color picker made with all the JavaFX built-in colors. Since JavaFX colors are are static fields with familiar (and maybe not so familiar) names like BLUE, GREEN, and MINTCREAM, we can use them quite easily as follows.

     Rectangle rec = new Rectangle(5, 5, 60, 30);
     rec.setFill(Color.RED);

You can also build a Color object from a color name with Color static method web().

     rec.setFill(Color.web("TURQUOISE"));

Here’s a screenshot of the JavaFX Sketch Pad Version 2.
JavaFX Sketch Pad Version 2 Screenshot
Note that we’ve moved the drawing controls below the canvas. The sample line appears at the top. The Clear button and stroke width slider are at the bottom left. At the bottom right, you see 147 color rectangles. Clicking on any of the rectangles changes the drawing color to the selected color (and also changes the color of the sample line).

How should we implement this feature? One way is to create an array of Color objects initialized to each of the static fields in Color.

    private static final Color[] colors = { Color.ALICEBLUE,
        Color.ANTIQUEWHITE, Color.AQUA,
      . . .
    };

Then, we can build a small rectangle for each color and add it to a FlowPane to create a our Color picker.

That works, but too much typing for all the JavaFX colors. Instead, let’s get all the public static fields in Color and build a Color object with Color.web(color_name) for each rectangle. We can do this with Java reflection. Java stores all kinds of interesting information inside the class object. While reflection is not used that often in application code, it is quite common in development tools (providing code completion choices in Java editors, for example).

Here’s our color picker code. First, we instantiate a Label to hold the selected color’s name. We use a FlowPane layout component to hold the color rectangles. FlowPane arranges its children in a flow, filling each successive row, and wrapping (going to the next row) when needed. Properties vgap and hgap provide vertical and horizontal spacing for the rectangles. Property prefWrapLength tells FlowPane when to wrap to the next row. The default behavior is row-wise filling, but column-wise filling is also possible.

// Use a Label to hold the selected color name
final Label colorLabel = new Label("color: blue");
. . .
// Put all the color rectangles in a flow container
FlowPane flow = new FlowPane();

flow.setVgap(2);
flow.setHgap(2);
flow.setPrefWrapLength(400);

Next, we’ll use reflection to grab all of the public static fields for Color. It turns out that the only public static field we want to skip is TRANSPARENT, which creates a see-through color that is not useful with our drawing program. And, just in case the JavaFX development team slips in a public static field that is not a valid Color name, we use a try – catch block. Color throws an IllegalArgumentException if you attempt to make a Color with an unrecognizable String.

Once we have a Color, we build and configure the rectangle (we’ll show you the configuration code next), and add the rectangle to the FlowPane layout container.

// Get the declared fields for the Color class
Field[] colorFields = Color.class.getDeclaredFields();
for (Field fieldname : colorFields) {
    // get the field's modifiers so we can tell
    // if it's public and static
    int mods = fieldname.getModifiers();

    // Only use the field if it's
    // public, static, and NOT 'TRANSPARENT'
    if (Modifier.isPublic(mods) && Modifier.isStatic(mods)
            && !(fieldname.getName().equals("TRANSPARENT"))) {
        try {
            // create a color from the fieldname
            Color c = Color.web(fieldname.getName());
            // Make a rectangle with that field name's color
            final Rectangle r = new Rectangle(15, 15, c);
            // Configure the rectangle
           . . .
            // Add it to the flow container
            flow.getChildren().add(r);
        } catch (IllegalArgumentException e) {
            // just ignore it if for some reason we can't make
            // a color
        }
    }
}

To configure each color picker rectangle, we set its cursor to Cursor.HAND. We then build a tooltip. JavaFX provides a built-in Tooltip object that you can easily configure with any JavaFX Control. However, a Rectangle is not a Control (it’s just a Shape). In this case, use the Tooltip static method install() for the expected pop-up tooltip behavior. We convert the color to lower case because lower case letters are easier to read.

(Note: The standard JavaFX tooltip pops up quite slowly and stays visible for only a short time. There is currently no way to configure the animation properties of a tooltip. I’m hoping that changes in a future release.)

We also want to display the Color name next to the sample line, since it’s easier to remember a color’s name than just viewing it. So, we save the color name (actually, the tooltip’s text) in the rectangle’s userData property. Once saved, we can retrieve it when the user selects this color.

The final configuration specifies a mouse clicked event handler for each rectangle. Inside the handler, we set sampleLine‘s stroke property to the rectangle’s fill property and the colorLabel‘s text property to the text in the rectangle’s userData (the color name).

// Configure the rectangle
r.setCursor(Cursor.HAND);
// Create a tooltip
Tooltip t = new Tooltip(fieldname.getName().toLowerCase());
Tooltip.install(r, t);
// Save the color name in userData
r.setUserData(t.getText());

r.setOnMouseClicked(new EventHandler<MouseEvent>() {

    @Override
    public void handle(MouseEvent me) {
        sampleLine.setStroke(r.getFill());
        colorLabel.setText("color: " +
                ((String) r.getUserData()));
    }
});

Have fun sketching! Download the Sketch Pad (Version 2) JavaFX source code here.

We welcome comments and feedback!

Posted in JavaFX | Tagged , , , , | Leave a comment

JavaFX Sketch Pad: Custom Binding

Sketch pad programs are fun to build and fun to test. And writing a sketch pad program in JavaFX is no different, except that maybe it’s more fun. So, what constructs do we need to create a decent sketch pad program in JavaFX? At the minimum, we need to

  • Detect mouse events for mouse click, mouse drag, and mouse release
  • Draw line segments corresponding to where the user clicks and drags the mouse
  • Clear our sketch pad

It would also be nice to

  • Change the width of the line we’re drawing
  • Change the color of the line we’re drawing

So, let’s begin.

Sketch Pad Program Screenshot

Version 1 JavaFX Sketch Pad Screenshot

The Version 1 screenshot (including some test scribbles) has a Clear button, three RGB color sliders, a stroke width slider, and a sample line that shows both the current stroke width and color settings. The canvas is a rectangle with a light gray background.

You construct the lines (or scribbles) with the JavaFX Path class, a shape that holds path elements. Path elements include ArcTo, ClosePath, CubicCurveTo, HLineTo, LineTo, MoveTo, QuadCurveTo, and VLineTo. We’ll only need MoveTo (to position the cursor at the beginning of a drawing action) and LineTo (to draw the line corresponding to the mouse drag). As we build the path, we’ll add it to a Group called lineGroup.

First, let’s look at the JavaFX code that builds the lineGroup, sample line (a Line), and canvas (a Rectangle). Note that we set the canvas’ cursor to CROSSHAIR so a user knows when the drawing mouse is active. We set the canvas fill to LIGHTGRAY.

private Group lineGroup;       //  Class variable
. . .
// A group to hold all the drawn path elements
lineGroup = new Group();
// Build the sample line<
final Line sampleLine = new Line(0, 0, 140, 0);
// Build the canvas
final Rectangle canvas = new Rectangle(scene.getWidth() - 20,
            scene.getHeight() - 200);
canvas.setCursor(Cursor.CROSSHAIR);
canvas.setFill(Color.LIGHTGRAY);

Next, we build the path elements in the canvas’ mouse event handlers. Both the stroke width and stroke color are based on the values of the sample line. Let’s examine the mouse event handlers for mouse pressed, mouse released, and mouse dragged.

The mouse pressed handler defines a new path and makes it transparent to mouse clicks. This lets the user draw new lines on top of previously drawn lines. Since the path is “in front of” the rectangle, the path would otherwise consume mouse events. Next, we set the strokeWidth and stroke properties. We add the newly created path to lineGroup and add path element MoveTo as the first element of the path. The x and y coordinates of the MoveTo element are the scene coordinates passed to the mouse event handler.

private Path path;           // Class variable
. . .
canvas.setOnMousePressed(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent me) {
        path = new Path();
        path.setMouseTransparent(true);
        path.setStrokeWidth(sampleLine.getStrokeWidth());
        path.setStroke(sampleLine.getStroke());<
        lineGroup.getChildren().add(path);
        path.getElements().add(
              new MoveTo(me.getSceneX(), me.getSceneY()));
    }
});

A mouse dragged event is fired when the user drags the mouse. This can only happen after a mouse pressed event or a previous mouse dragged event. Here we check that the coordinates in the mouse event are within the canvas’ local coordinate space. If the coordinates are indeed within the canvas, we create a LineTo path element and add it to the path. This draws a line on the canvas from the previous mouse pressed or mouse dragged event location. The mouse dragged event handler is invoked multiple times as the user drags the mouse over the canvas.

canvas.setOnMouseDragged(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent me) {
        // keep lines within rectangle
        if (canvas.getBoundsInLocal().contains(
                             me.getX(), me.getY())) {
            path.getElements().add(
                 new LineTo(me.getSceneX(), me.getSceneY()));
        }
    }
});

When the user releases the mouse, the system invokes the mouse released event handler. Here, we simply set path to null. Now the user can optionally clear the canvas, change the stroke width, or change the stroke color.

canvas.setOnMouseReleased(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent me) {
        path = null;
    }
});

We clear the canvas with the Clear button. This event handler removes all the nodes contained in lineGroup.

Button btnClear = new Button();
btnClear.setText("Clear");
btnClear.setOnAction(new EventHandler<ActionEvent>() {
    public void handle(ActionEvent event) {
        lineGroup.getChildren().
             removeAll(lineGroup.getChildren());
    }
});

Recall that a slider controls the stroke width. Let’s see how this works. First, we define constants to set the slider’s minimum and maximum values (MINSTROKE and MAXSTROKE). Then, we set the starting stroke width to 3.0, which is a bit larger than the default of 1.0. We use these values to instantiate slider strokeSlider. As the user slides the handle right, the value increases up to the maximum. To track the changes, we bind the sampleLine‘s stroke width property to the value of the slider. This is straightforward, since both properties wrap Double values. As the user moves the slider, the sample line grows and shrinks to reflect its stroke width. Each time the user “draws” a line, the canvas’ mouse handler uses the new stroke width value.

private static final Double DEFAULTSTROKE = 3.0;
private static final Double MAXSTROKE = 30.0;
private static final Double MINSTROKE = 1.0;
. . .
Slider strokeSlider =<br
       new Slider(MINSTROKE, MAXSTROKE, DEFAULTSTROKE);
sampleLine.strokeWidthProperty().bind(
       strokeSlider.valueProperty());

Now let’s configure the line’s color. To control color, we use a triplet of sliders for the RGB color value. Each value is an integer from 0 to 255. Here are the three sliders and label controls.

private static final Integer DEFAULTRED = 0;
private static final Integer DEFAULTGREEN = 0;
private static final Integer DEFAULTBLUE = 255;
private static final Integer MAXRGB = 255;
private static final Integer MINRGB = 0;
. . .
// Build the RGB sliders and labels
final Slider redSlider =
        new Slider(MINRGB, MAXRGB, DEFAULTRED);
Label labelRed = new Label("R");
final Slider greenSlider =
        new Slider(MINRGB, MAXRGB, DEFAULTGREEN);
Label labelGreen = new Label("G");
final Slider blueSlider =
        new Slider(MINRGB, MAXRGB, DEFAULTBLUE);
Label labelBlue = new Label("B");

Here’s where things get a bit tricky. To set sampleLine‘s stroke property to a Color based on the combined values of the three RGB sliders, we use static Color method rgb(), as follows (which gets converted automatically to the required Paint object).

sampleLine.setStroke(Color.rgb(redSlider.valueProperty().intValue(),
                        greenSlider.valueProperty().intValue(),
                        blueSlider.valueProperty().intValue()));

However, just as we provided binding for sampleLine‘s stroke width property to the stroke width slider value, we also need to bind sampleLine‘s stroke property to the Color object made from the combined RGB slider values. When any of the three sliders change, sampleLine‘s stroke property must also change. In this case, there isn’t a built-in Paint property binding method that computes a new Paint object from an RGB triplet, so we’ll need to create our own custom binding object.

This ObjectBinding object will be built as an anonymous class. In the constructor we specify the properties that participate in the binding. This builds the necessary listeners that are notified when any of the slider’s value property changes. Next, we override method computeValue() to specify how a new Paint object is built from the three sliders. Once we build the custom binding object, we can specify the binding for sampleLine.

// Build a Binding object
// to compute a Paint object from the sliders
ObjectBinding<Paint> colorBinding = new ObjectBinding<Paint>() {
    {
        super.bind(redSlider.valueProperty(),
                greenSlider.valueProperty(),
                blueSlider.valueProperty());
    }
    @Override
    protected Paint computeValue() {
        return Color.rgb(redSlider.valueProperty().intValue(),
                greenSlider.valueProperty().intValue(),
                blueSlider.valueProperty().intValue());
    }
};
// Bind sampleLine to the Paint Binding object
sampleLine.strokeProperty().bind(colorBinding);

So there you have it. Download the Sketch Pad (Version 1) JavaFX source code here.

But, what about Version 2? Personally, manipulating three sliders to configure the draw color can be tedious. Version 2 of the Sketch Pad example uses a color picker instead of three sliders for the line color. Stay tuned.

Posted in JavaFX | Tagged , , , , , | 2 Comments

JavaFX Animation and Binding: Using the ProgressBar

Our previous post describes a JavaFX countdown timer. Let’s take that same program and add a progress bar control. As the timer counts down, the progress bar gradually fills in—as shown in the screenshot here. When the timer begins (at 15), the progress bar is empty (all gray) and when the timer reaches 0, the progress bar is filled in (all blue).

FXTimer with Progress Bar Screenshot

FXTimer with Progress Bar Screenshot

The progress bar includes progressProperty, a DoubleProperty with values that range between 0 (no progress or 0% complete) and 1 (progress complete or 100%). Half-way is 0.5.

Recall that in our previous post, we bind the numeric label timerLabel to the timer property (timeSeconds). Now to configure the progress bar, we bind its progressProperty to the timer as well. With binding, we don’t have to update progressProperty in the timeline’s event handler.

Here’s our first attempt.

private static final Integer STARTTIME = 15;
private IntegerProperty timeSeconds =
        new SimpleIntegerProperty(STARTTIME);
. . .
// Instantiate progressbar and configure binding
ProgressBar progressBar = new ProgressBar();
progressBar.progressProperty().bind(
                timeSeconds.divide(STARTTIME*1.0));
. . .
// Add to vertical box layout component
vb.getChildren().addAll(button, timerLabel, progressBar);
. . .

This is a nice try, but not the result we want at all! We instantiate the progress bar in line 6 and specify its binding in lines 7-8. Recall that timeSeconds is an IntegerProperty, so we must use Property method divide() to make sure the binding is a Double whose range is between 0 and 1. Can you guess the outcome?

There are two problems here. First, because our timer updates once a second, the progress bar chunks through (in 15 evenly spaced chunks) instead of filling smoothly. Second, the progress bar begins filled and empties as the timer counts down (we want the opposite behavior). To fix these problems, we must do the following:

  • Make our timeline cycle faster. Although the label should only change once per second, the progress bar should be updated more often. We do this by making timeSeconds 1500 instead of 15. Then we divide by 100 when binding to timerLabel.
  • Correlate the starting value of the timer (15) to zero for the progress bar and the ending value of the timer (0) to 1.0 for the progress bar. This fills the progress bar as the timer counts down. (In other words, a little bit of math will help us!)

Here’s the updated code.

private static final Integer STARTTIME = 15;
private IntegerProperty timeSeconds =
        new SimpleIntegerProperty(STARTTIME*100);
. . .
// Bind the timerLabel textProperty
// to the timeSeconds property
timerLabel.textProperty().bind(
        timeSeconds.divide(100).asString());
. . .
// Bind the progressBar progressProperty
// to the timeSeconds property
ProgressBar progressBar = new ProgressBar();
progressBar.progressProperty().bind(
        timeSeconds.divide(STARTTIME*100.0)
        .subtract(1).multiply(-1));
. . .
// Inside the button event handler
// Make the timeline duration STARTTIME seconds
timeline.getKeyFrames().add(
        timeSeconds.set((STARTTIME+1)*100);
        timeline = new Timeline();
        timeline.getKeyFrames().add(

                new KeyFrame(Duration.seconds(STARTTIME+1),
                new KeyValue(timeSeconds, 0)));
        timeline.playFromStart();
. . .

This provides the behavior we want. Let’s review these changes.

  • IntegerProperty timeSeconds now starts off at 1500 instead of 15 (100 times the original initial value) (lines 2-3).
  • To compensate for this change to timeSeconds, we must divide timeSeconds by 100 to correctly configure the timerLabel binding (lines 7-8).
  • We divide timeSeconds by 1500 to calibrate the progress bar. The values now progress from 0% complete to 100% since we subtract one and multiply by -1 (lines 13-15).

Download the FXTimer with ProgressBar JavaFX source code here.

Posted in JavaFX | Tagged , , , , | 1 Comment

JavaFX Animation and Binding: Simple Countdown Timer

JavaFX has a powerful animation feature that’s flexible and easy to use. I’m going to build a simple countdown timer that uses animation to countdown a numeric display from 15 (for example) to zero. I can imagine such a timer in some sort of response game that limits the time you have to make a move (or answer a question). Our first version will not use binding, but since binding is such an important concept with JavaFX, I will also show you a version that includes binding. And, the approach that uses binding is the correct approach. But, first we’ll examine how to manually update the numeric display so we can concentrate on the timer code.

FXTimer Screenshot

FXTimer at Startup

Here is a screenshot of the application as it comes up. To start the timer, you click the Start Timer button. The numeric display then counts down—once per second—to zero. Anytime you click the Start Timer button, the timer resets to 15 and restarts the countdown. Listing 1 shows all of the code except the button’s event handler code (lines 46-51), which we’ll see later. Let’s look at the program structure and the graphical components first. JavaFX applications extend the Application class and override the start() method. The JavaFX runtime constructs the Application class instance and invokes your start() method. If you use the NetBeans IDE, the IDE will build a skeletal JavaFX application for you. You put your code inside method start(). (Of course, more involved applications will use additional classes defined in other Java files.) After the class declaration, we declare some class variables such as timeline (Timeline), timerLabel (Label), and timeSeconds (Integer). Inside method start(), we setup the scene graph. Defining the root node (a Group) and scene and setting the Stage’s title are part of the boilerplate code the NetBeans IDE provides. We then configure the Label (lines 38-41) and create and configure the Button (lines 43-51). Next, we use a vertical box layout component (VBox) so that the Label and Button are vertically aligned and we center the components horizontally (line 57). As you can see, you add nodes to the scene graph using grouping and layout components methods getChildren().add(node) (for adding a single child node) and getChildren().addAll(nodes) (for adding multiple children nodes). See lines 63 and 65 for examples of addAll() and add(). I’ve highlighted Line 39 to show you that we set the label’s text by converting the Integer timeSeconds to a String. We’ll then have to perform the same conversion to update the label’s text when the timer code decrements the counter.

package fxtimer;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;

public class FXTimer extends Application {

    // private class constant and some variables
    private static final Integer STARTTIME = 15;
    private Timeline timeline;
    private Label timerLabel = new Label();
    private Integer timeSeconds = STARTTIME;

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        // Setup the Stage and the Scene (the scene graph)
        primaryStage.setTitle("FX Timer");
        Group root = new Group();
        Scene scene = new Scene(root, 300, 250);

        // Configure the Label
        timerLabel.setText(timeSeconds.toString());
        timerLabel.setTextFill(Color.RED);
        timerLabel.setStyle("-fx-font-size: 4em;");

        // Create and configure the Button
        Button button = new Button();
        button.setText("Start Timer");
        button.setOnAction(new EventHandler() {

            public void handle(ActionEvent event) {
            // Button event handler code goes here . . .
            }
        });

        // Create and configure VBox
        // gap between components is 20
        VBox vb = new VBox(20);
        // center the components within VBox
        vb.setAlignment(Pos.CENTER);
        // Make it as wide as the application frame (scene)
        vb.setPrefWidth(scene.getWidth());
        // Move the VBox down a bit
        vb.setLayoutY(30);
        // Add the button and timerLabel to the VBox
        vb.getChildren().addAll(button, timerLabel);
        // Add the VBox to the root component
        root.getChildren().add(vb);

        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

Now for the animation part! Listing 2 shows the code for the Button’s event handler. When you press the Start Timer button, the runtime invokes the button’s handle() method. This handler sets up a timeline, which runs indefinitely and cycles once each second. Each time you press the button, the handler stops the timeline if it is active (lines 4-6). The button handler then resets the counter to its initial value (STARTTIME) (line 7), updates the numeric label to match the counter (line 10), and restarts the timeline (line 27). Okay, so what exactly is a timeline? A Timeline is a JavaFX object you use to define animations by specifying JavaFX object properties that change over time. So, if you want to move a Rectangle object horizontally, you specify different values for the Rectangle’s x-coordinate property at different times (in different keyframes). A timeline consists of one or more KeyFrames and timelines use these KeyFrame objects to represent the different time frames. Here, however, we’re defining a more specialized use case for a Timeline. After each cycle (when the KeyFrame time slot elapses), the KeyFrame’s own event handler is invoked. Now let’s look at the code that builds and initializes the Timeline object (lines 11-26). We want the timeline to run indefinitely until stopped (line 12). In this case, we create a single KeyFrame and give it a one second duration (Duration.seconds(1)). We then define an event handler for the KeyFrame, which is executed when the KeyFrame finishes. This means that after one second, the runtime invokes the code in the KeyFrame event handler (lines 17-25). So what does this KeyFrame event handler do? It decrements our counter. It updates the numeric label. And, if the counter is zero, it stops the timeline. (If the counter is not zero, the timeline restarts automatically because we told it to run indefinitely.)

button.setOnAction(new EventHandler() {  //Button event handler

    public void handle(ActionEvent event) {
        if (timeline != null) {
            timeline.stop();
        }
        timeSeconds = STARTTIME;

        // update timerLabel
        timerLabel.setText(timeSeconds.toString());
        timeline = new Timeline();
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.getKeyFrames().add(
                new KeyFrame(Duration.seconds(1),
                  new EventHandler() {
                    // KeyFrame event handler
                    public void handle(ActionEvent event) {
                        timeSeconds--;
                        // update timerLabel
                        timerLabel.setText(
                              timeSeconds.toString());
                        if (timeSeconds <= 0) {
                            timeline.stop();
                        }
                      }
                }));
        timeline.playFromStart();
    }
});

Implementing the Timer with Binding Note that to properly maintain the numeric label, we had to initialize the label (Listing 1, Line 39), reinitialize the label during the Start Button event handler (Listing 2, Line 10), and update the label in the KeyFrame’s event handler (Listing 2, Lines 20-21). A better approach is to formally declare that the label’s text property is dependent on variable timeSeconds. Whenever the value of timeSeconds changes, the timerLabel text also changes. This dependency is called binding. To implement binding, we change variable timeSeconds from Integer to IntegerProperty. Property types let you bind variables and are new with JavaFX 2.0. Here is the Property declaration for timeSeconds.

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
. . .

// Make timeSeconds a Property
private IntegerProperty timeSeconds =
        new SimpleIntegerProperty(STARTTIME);

Next, we bind the label’s text property to timeSeconds, as follows.

// Bind the timerLabel text property to the timeSeconds property
timerLabel.textProperty().bind(timeSeconds.asString());

This binding creates the desired dependency: the timerLabel label will now show the current value of timeSeconds. Note that we access the timerLabel text property with timerLabel.textProperty(). All JavaFX scene graph nodes use Property types to maintain property values. With binding in place, we can make several improvements. We remove the code that reinitializes and updates timerLabel. We also remove the KeyFrame’s event handler and instead animate timeSeconds directly. This means that we specify the ending value for timeSeconds (0) and the timeline will, over the duration of the keyframe, figure out the intermediate values and update timeSeconds accordingly. We no longer decrement timeSeconds manually and no longer play the timeline indefinitely. We make the duration 15 seconds. Here is the new, improved button event handler and timeline code. Since timeSeconds is now a Property type, we must use the setters and getters to access its value (line 7).

button.setOnAction(new EventHandler() {

    public void handle(ActionEvent event) {
        if (timeline != null) {
            timeline.stop();
        }
        timeSeconds.set(STARTTIME);
        timeline = new Timeline();
        timeline.getKeyFrames().add(
                new KeyFrame(Duration.seconds(STARTTIME+1),
                new KeyValue(timeSeconds, 0)));
        timeline.playFromStart();
    }
});

Download the FXTimer with Binding JavaFX source code here.

Thanks to Michael Heinrichs for his feedback on an earlier version of this post.

Posted in JavaFX | Tagged , , , | Leave a comment

The Return of JavaFX™

JavaFX LogoJavaFX™, the rich UI design system from Sun Microsystems and then Oracle, never really went away. But JavaFX Script 1.x has been replaced by JavaFX 2.x Java APIs. As a fan of JavaFX script (and co-author of Essential JavaFX—check out Mini Golf), I loved working with many of the unique features that JavaFX provided, such as easy animation, a declarative programming style, type inference, function and sequence types, and a powerful binding mechanism. With JavaFX you create a graphical UI by building a scene graph, a tree structure (or directed acyclic graph) consisting of container nodes and leaf nodes. Container nodes hold other nodes and are used for grouping and layout. Leaf nodes are graphical elements (such as images, lines, text, circles, and so on) that don’t contain other elements.

Oracle announced this new direction at JavaOne 2010. A year later and JavaFX 2.0 (the Java API system) has been released. Oracle also announced that JavaFX is open sourced. With approximately 50 talks at JavaOne 2011, Oracle sent the message, “We want you to look at this new JavaFX.” So I did look. I am looking.  I am looking and playing and testing. And with all this playing around, I have some mostly good news.

First, for people who have experience with JavaFX script (that is, JavaFX 1.x), many concepts remain the same. You still build a scene graph. You still work with the same familiar graphical objects. You have the same UI controls, but many more. Animation works the same in that you change the value of node properties along a timeline. As before, there are high-level animations, called transitions that simplify animation. By keeping the scene graph and many of the graphical components, JavaFX 2.0 feels familiar. And now I am programming in Java, not JavaFX script. For Java programmers that is very good.

What do I miss? Most of all I miss the easy binding mechanism and the declarative style that makes binding so natural. To be sure, JavaFX 2.0 includes a new Property Binding mechanism that lets you specify binding. It works great. But, it’s not so elegant. JavaFX 2.0 also includes “build” classes that let you create graphical objects using a more declarative style. (I’m not really sure if I’ll use these build classes.)

But back to the good news. Moving JavaFX to Java APIs lets Oracle standardize the system and bring in Java developers. Indeed, FXML lets you specify your scene graph using an XML-based language, which can then be manipulated by UI builder tools. JavaFX 2.0 has an improved event handling model, improved performance (using graphics hardware when available), improved cross-platform support, some 3-D support, and an improved thread model. I am ready to give JavaFX a go! Stay tuned for some example programs coming soon.

Note: To view many of the JavaFX talks presented at JavaOne 2011, see this link.

Posted in JavaFX | Tagged | Leave a comment

iOS Memory Management: Using Autorelease

In a previous post I discussed memory management in iPhone programming. Recall that the iPhone programming environment does not support garbage collection. You must pay attention to objects you create (and therefore own) and must consequently make sure that you properly relinquish ownership. This permits objects to be deleted from memory correctly. You must also recognize when you use objects that you do not own so that you don’t incorrectly release them.

When you develop for the iPhone (or iPad), you use Apple’s Cocoa Touch framework and you write code with Objective-C. Cocoa Touch supports a Model-View-Controller design and maintains (for you) an Autorelease Pool that temporarily holds objects in memory for later release. So, while it’s true that the iPhone environment does not support automatic garbage collection, the environment does provide some automatic memory management assistance. Understanding how the Autorelease Pool works is essential to fully understanding memory management in Objective-C and the Cocoa Touch environment.

iPhone applications run in an event loop, as shown in the diagram below. That is, when your iPhone application launches, the program enters the event loop and waits for a user touch event. When a touch event happens, the Cocoa Touch framework detects the event, creates an event object, and allocates and initializes an autorelease pool. Cocoa Touch then invokes your application event handler, making the event object available.

Event Loop Diagram

iPhone Application Event Loop


Your event handler may put objects in the autorelease pool or, perhaps more commonly, use objects that were put into the autorelease pool by other objects. (For example, the NSString convenience method, stringWithFormat, creates an autorelease object.)

When your event handler finishes execution, control returns to the Cocoa Touch framework. Cocoa Touch drains the autorelease pool, which sends a release message to each object in the pool. Those objects with a retain count of zero are deleted from memory. This means, of course, that just because an object is in an autorelease pool, doesn’t mean that object gets deleted when the pool is drained. Only objects whose retain counts reach zero are deleted.

Cocoa Touch then waits for the next touch event and the cycle begins anew.

So, when should you use autorelease in your code and what do you need to know about autorelease objects?

The most common reason for using autorelease is returning an object you’ve created (and therefore own) to a caller. You can’t release the object inside your method because then you’ll return an invalid object. On the other hand, if you don’t release the object, you’ll create a memory leak (breaking the basic rule that says you must release objects you own). The solution is to put the object in the autorelease pool. Its release is then delayed until the autorelease pool is drained. Let’s look at an example.

Suppose you have a method getLabel in your ViewController class that builds an NSString object for a UILabel component. An event handler calls this method each time the user taps a button. Here is a first attempt.

// Version 1 - Incorrect
- (NSString *)getLabel
{
    NSString * temp;
    if (numberTaps == 1) {
        temp = [[NSString alloc] initWithString:@"time"];
    } else {
        temp = [[NSString alloc] initWithString:@"times"];
    }

    NSString * myLabel = [[NSString alloc] initWithFormat:
			@"You have tapped the button %d %@",
			numberTaps, temp ];
    [temp release];
    // [myLabel release];   ??
    return myLabel;
    // [myLabel release];   ??
}

From our previous post you know that this method is incorrect. Method getLabel owns both temp and myLabel because we create them with alloc. We can release temp (just before the return statement), but what about myLabel? If you release myLabel before the return statement, you return an invalid object. However, if you put the release after the return then the release is never executed.

Our second version uses autorelease with myLabel and release with temp. Apple recommends that you use release instead of autorelease whenever possible to keep the size of the pool small.

// Version 2
- (NSString *)getLabel
{
    NSString * temp;
    if (numberTaps == 1) {
        temp = [[NSString alloc] initWithString:@"time"];
    } else {
        temp = [[NSString alloc] initWithString:@"times"];
    }

    NSString * myLabel = [[NSString alloc] initWithFormat:
			@"You have tapped the button %d %@",
			numberTaps, temp ];
    [temp release];           // delete now
    [myLabel autorelease];    // delete later
    return myLabel;
}

This works fine. However, if you nest the autorelease call with alloc, initWithFormat, and the return statement, the resulting code is cleaner and more readable. Here’s our final version. Note that in this version you must use autorelease with temp instead of release.

// Version 3
- (NSString *)getLabel
{
    NSString * temp;
    if (numberTaps == 1) {
        temp = [[NSString alloc] initWithString:@"time"];
    } else {
        temp = [[NSString alloc] initWithString:@"times"];
    }
    [temp autorelease];        // delete later

    return [[[NSString alloc] initWithFormat:
			@"You have tapped the button %d %@",
			numberTaps, temp ] autorelease];     // delete later
}

Let’s review what happens. The program launches and the Cocoa Touch framework waits for a touch event. The user touches a button (for example), and Cocoa Touch creates both the event and the autorelease pool. Cocoa Touch then invokes your application’s event handler. Inside the event handler, your code invokes method getLabel. Method getLabel creates two NSString objects, one (temp) is used to build the returned NSString and the other is returned to the caller. These NSString objects have a retain count of 1, since method getLabel creates them with alloc.

With method autorelease, these NSString objects go into the autorelease pool, still with a retain count of 1. Cocoa Touch updates the iPhone screen and drains the autorelease pool. Draining the pool sends a release message to our two NSString objects, which makes their retain counts zero. The NSString objects are deleted.

(Note that if you need to create many temporary objects you can create your own autorelease pool inside a program loop or method. This technique drains the local pool more often than the standard event loop pool provided by Cocoa Touch and keeps memory consumption low. In this case, all newly autoreleased objects now go into this new pool. You should always drain a local autorelease pool in the loop or method in which you allocate it.)

What happens when you obtain an object from an NSString convenience method or one of your own methods that use autorelease, but you want to keep the object around for more than one event cycle?

Good question! In this case, the caller needs to claim ownership of the object with method retain. With ownership, you must then make sure that you subsequently release the retained object. We’ll discuss the retain method in the next post.

Posted in iPhone/iPad Programming | Tagged , , , , | 3 Comments

iOS Memory Leaks? Program Crashes? Start Here!

So, you want to write applications for the iPhone and/or iPad? I do! And, with a background in software engineering, Java, C++ and yes, even plain old C, I thought I’d take the plunge. As I’ve learned about Apple’s software, I’ve come to appreciate its overall design, its use of patterns, and its maturity.

But, don’t think you can forget the nitty-gritty details of pointers, memory management, and good programming practices. Those of you out there with experience in Java and Java’s garbage collection: take heed. The iPhone programming environment does not support garbage collection. This means you must understand the iOS memory management model.

Thus, we begin our exploration of iOS with the iOS memory management scheme. The rules for correct handling of objects’ memory are clear, but often, individual cases can cause confusion. Let’s start with the basic rule:

If you own an object, you are responsible for relinquishing ownership when you’re done with it. And, if you don’t own an object, you better not relinquish ownership. (This is like selling a car that you don’t own—somebody is going to be very unhappy when they find out you don’t have the pink slip.)

How do you own an object and how do you relinquish ownership?

You own an object when you’ve created it with a method that begins with alloc, new, copy or mutableCopy.

You can also own an object by sending it the retain message.

You relinquish ownership by sending the object either the release or autorelease message. You use autorelease when you need to relinquish ownership, but you don’t want the object to be released from memory just yet. This will be discussed in another post.

Behind the scenes, all objects have reference counts (called retain counts in iOS). When you create an object, its retain count is 1. When you send an object the retain message, its retain count increments by 1. When you send an object the release message, its retain count decrements by 1. If an object’s retain count becomes zero, the system deletes the object from memory.

If you fail to relinquish ownership of an object you own, its retain count won’t ever reach zero and the object is never deleted from memory. This creates a memory leak. The problem becomes worse if the programming error is repeated because the object is created over and over again without a subsequent release.

If you relinquish an object that you don’t own and the object’s retain count becomes zero prematurely, your application may crash when you attempt to send a message to an object that has been deleted from memory.

Let’s look at some examples. Our first example creates a mutable array (using collection class NSMutableArray) and adds three NSString objects to it with message addObject. We print the contents of the array and then release ownership.

NSMutableArray *projects = [[NSMutableArray alloc] init];
[projects addObject:@"My Project"];
[projects addObject:@"Your Project"];
[projects addObject:@"Joe's Project"];

NSLog(@"Projects = %@", projects);        // display
[projects release];                // relinquish ownership

Note that we’ve taken ownership of collection projects because we created it with method alloc. We then relinquish ownership (as we must) by sending it message release. Here is the output.

Projects=(
    My Project,
    Your Project,
    Joe's Project
)

This is straightforward. Now let’s add the following code (highlighted below). We assign variable myProject to the projects object at index 0 and display this object.

    NSLog(@"Projects=%@", projects);
    NSString * myProject = [projects objectAtIndex:0];
    NSLog(@"my project = %@", myProject);
    [projects release];

Here is the updated output.

Projects=(
    My Project,
    Your Project,
    Joe's Project
)
my project = My Project

Should we relinquish ownership of object myProject? No, we must not. We do not own the object pointed to by myProject. If we were to relinquish ownership, we would incorrectly decrement the reference count for the simple reason that the caller here does not own the object.

Well then, who owns the object pointed to by myProject? The answer is the projects collection is the owner. When you add an object to a collection, the collection takes ownership of that object. Then, when a collection class is deallocated, it relinquishes ownership of each object it contains. Similarly, if you remove an object from a collection, the collection relinquishes ownership. Simply accessing an object from a collection, however, (for example with message objectAtIndex) does not constitute acquiring ownership by the caller.

Let’s look at another example. Here we build NSString objects in a loop and store each one in the projects collection.

NSMutableArray *projects = [[NSMutableArray alloc] init];

for (int i = 0; i < 3; i++)
{
    NSString * temp = [[NSString alloc]
               initWithFormat:@"Project%d", i];
    [projects addObject:temp];
}

NSLog(@"Projects=%@", projects);
[projects release];

Here is the output.

Projects=(
    Project0,
    Project1,
    Project2
)

Can you identify the problem here? Look at the for loop. We create an NSString object with message alloc, which means we have ownership of the object pointed to by temp. We then add the object to the collection. At this point, the object pointed to by temp has a retain count of 2—one because we created it using alloc and two because the collection claims ownership when we add the object to the collection.

When the collection is deallocated, the collection class sends a release message to each object in its collection. These objects will then all have a retain count of 1. But since we don’t ever (incorrectly) relinquish ownership, these objects are not properly released and the retain count never reaches zero. We have a memory leak!

The solution is to release each object after adding it to the collection.

for (int i = 0; i < 3; i++)
{
    NSString * temp = [[NSString alloc]
               initWithFormat:@"Project%d", i];     // ownership
    [projects addObject:temp];
    [temp release];               // relinquish
}

Here is a final example that uses a variation of this code.

NSMutableArray *projects = [[NSMutableArray alloc] init];

for (int i = 0; i < 3; i++)
{
    NSString * temp =
               [NSString stringWithFormat:@"Project %d", i];
    [projects addObject:temp];
}

NSLog(@"Projects=%@", projects);
[projects release];

This time we’ve left off the release of temp inside the for loop. Is this correct? Let’s return to the original rule, which says if we create an object with a message that starts with alloc, new, copy, or mutableCopy, then we must claim ownership. Here, we create each NSString object with message stringWithFormat. In this case, we must not claim ownership and therefore, must not relinquish ownership with message release. The above code is correct.

In the next post, I’ll discuss message autorelease. I’ll explain how NSString can (for example) correctly manage the memory of objects it creates using convenience methods such as stringWithFormat. I’ll also show you how you can use autorelease to correctly manage your own objects.

Posted in iPhone/iPad Programming | Tagged , , , , | 1 Comment

Welcome!

We are busy creating content for our new blog. Stay tuned and please check back soon!

Posted in Uncategorized | Leave a comment