Accessing TextField.text is slower than a bag of dried apricots

 

I always assumed accessing TextField.text would be slow, since we’re warned against TextField.text += String in the ASDocs, but I didn’t realize how slow. I switched to my test project for a quick verification. Lo and behold, it’s over 11 times slower than storing to a String variable and accessing that. Here are the results and test code:

TextField.text.................................454 (100000 iterations)
text............................................41 (100000 iterations)
bag of dried apricots..........................376 (100000 iterations)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package {
	import com.gskinner.utils.PerformanceTest;
 
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.utils.setTimeout;
 
	public class Test extends Sprite {
		public var p:PerformanceTest;
 
		public var textfield:TextField;
		public var text:String;
 
		public function Test() {
			p = PerformanceTest.getInstance();
 
			textfield = new TextField();
 
			textfield.text = 
				"Lorem Ipsum is simply dummy text of the printing and typesetting industry. " +
				"Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, " +
				"when an unknown printer took a galley of type and scrambled it to make a type " +
				"specimen book. It has survived not only five centuries, but also the leap into " +
				"electronic typesetting, remaining essentially unchanged. It was popularised in " +
				"the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, " +
				"and more recently with desktop publishing software like Aldus PageMaker " +
				"including versions of Lorem Ipsum.";
 
			text = textfield.text;
 
			setTimeout(run, 1000);
		}
 
		public function run():void {
			p.testFunction(testTextFieldText, 100000);
			p.testFunction(testText, 100000);
		}
 
		public function testTextFieldText():void {
			textfield.text;
		}
		public function testText():void {
			text;
		}
	}
}

ScreenCapture class, demo app and screencast

 

ScreenCaptureDemo

I felt like working on something new this past weekend, so I devoted a few hours to the new AIR 2.0 Beta. One feature that really caught my eye is the NativeProcess class, which allows developers to communicate with the system through an executable. This is a game-changer in the AIR world, opening more doors than you or I can ever imagine. I’ve always wanted screen capture support in AIR, so with this new class, I developed it myself.

Surprisingly, my efforts proved successful!—I had a working class, ScreenCapture, and application, ScreenCaptureDemo, up and running within a few hours. Tired of staring at the Spark components, I decided to add a touch of DT to the app by designing my own skin. This took far longer than the core of the app, but made a world of difference. Now that I think of it, this could be considered my first Flex app.

The downside of the NativeProcess class is it nulls the cross-platform benefit of AIR. The developer must compile a .dmg for Mac, a .exe for Windows, and the choice between a few for Linux. Since I only spent this weekend on the ScreenCapture class and I’m only familiar with the Mac command line, both the class and demo app are Mac-only. Also, the demo won’t work just yet for most of you. It requires a prerelease build of AIR 2.0, but things should be okay once the Beta 2 is out.

Download ScreenCaptureDemo (Mac-only, requires AIR 2.0 prerelease)

Along with adding the ScreenCapture class to DestroyFramework, I created a repository for the ScreenCaptureDemo source and installer on GitHub as well. Check them both out and enjoy!

[note] I’m not quite sure why Vimeo decided to cut out the right audio channel in the screencast…

DisplayObjectUtil class added to DestroyFramework

 

I’ve been sifting through my old framework, finding classes that are useful, but lacking in their current state—one of them being the fSprite class. This is easily my most-used class because it’s the base of every visual object. It has so much built-in and I now realize that isn’t exactly a good thing. Whenever I don’t need its layer management or motion methods, precious memory is lost. On top of that, there are visual objects that aren’t Sprites but could benefit from fSprite’s methods, such as the Shape class. After seeing Jackson Dunstan’s comparison of the two, I realized I could be saving a solid amount memory and instantiation speed by using Shape instead of Sprite where possible.

Because of these realizations, I decided to write a DisplayObjectUtil class. It starts with my layer management methods and will grow to include many others. In the following methods, if the object isn’t the child of a parent, it returns -1 instead of throwing an error.

The bringToFront method takes a DisplayObject and brings it to the front of the display list. It also includes an optional back parameter in the case you don’t want the object in the very front, you can send it back a few.

1
2
3
4
5
// DisplayObjectUtil.bringToFront(object:DisplayObject, back:int = 0):int
 
// consider sprite's index is 2 in a display list of 5 objects
DisplayObjectUtil.bringToFront(sprite); // returns new index of 4
DisplayObjectUtil.bringToFront(sprite, 1); // returns new index of 3

Along with bringToFront, I wrote bringForward, which moves the object up in the display list the set number of times. If the new index exceeds the highest index, it limits itself to that instead of throwing an error.

1
2
3
4
5
6
7
8
// DisplayObjectUtil.bringForward(object:DisplayObject, steps:int = 1):int
 
// consider sprite's index is 2 in a display list of 5 objects
DisplayObjectUtil.bringForward(sprite); // returns new index of 3
 
// consider sprite's index is 1 in a display list of 5 objects
DisplayObjectUtil.bringForward(sprite, 2); // returns new index of 3
DisplayObjectUtil.bringForward(sprite, 9); // returns new index of 4

On the reverse, I wrote methods sendToBack and sendBackward. Both work exactly the same as the methods above, but in the reverse direction.

1
2
3
4
5
// DisplayObjectUtil.sendToBack(object:DisplayObject, forward:int = 0):int
 
// consider sprite's index is 2 in a display list of 5 objects
DisplayObjectUtil.sendToBack(sprite); // returns new index of 0
DisplayObjectUtil.sendToBack(sprite, 1); // returns new index of 1
1
2
3
4
5
6
7
8
// DisplayObjectUtil.sendBackward(object:DisplayObject, steps:int = 1):int
 
// consider sprite's index is 2 in a display list of 5 objects
DisplayObjectUtil.sendBackward(sprite); // returns new index of 1
 
// consider sprite's index is 3 in a display list of 5 objects
DisplayObjectUtil.sendBackward(sprite, 2); // returns new index of 1
DisplayObjectUtil.sendBackward(sprite, 9); // returns new index of 0

I hope this class lends a hand and proves useful. Feel free to suggest any other methods DisplayObjectUtil should have.

Using code to problem-solve everyday issues

 

If I spend a third of my life sleeping, I spend another third programming. Most of the code I write is for an application or framework, but lately I find myself using code for everyday problem solving. In the last post, regarding the width of DT, I wrote a 3-line script to find sizes with 3:2 ratios, without decimals. Here’s the code:

1
2
3
for (var w:uint= 576; w < 650; ++w) {
	if (w / 1.5 == int(w / 1.5)) trace(w, "x", w / 1.5);
}

Sure, it’s not the prettiest code, but it gets the job done—and in less than a minute. Without these three lines, I could have spent a good 15 minutes with the calculator widget.

Another scenario where code came in handy happened a month ago. I visited my sister, Lizzy, in Philly and we decided to play Scattegories. Unfortunately, she didn’t have the die to pick the letter for each round. Luckily, I had my laptop with me, so I wrote this snippet:

1
trace("abcdefghijklmnopqrstuvwxyz".substr(int(Math.random() * 26), 1));

In less than a minute, we had a pseudo-random letter and a fun time. There are dozens of moments each day where code is the quick solution, but I don’t always think code-first. Of course, code isn’t always the fastest solution to all problems, but it certainly comes in handy. Next time you have an issue, try using code. Heck, you can even write a 1-line 8-ball script if you have trouble making decisions.

645 576 is the new 450: a wider Destroy Today

 

wider

After working with 450 for the past how many years, I decided to widen things a bit. The main reason for this change is code snippets—just about any code I posted would require a horizontal scroll and that’s not cool. I also plan to get away from the computer more and get back into photography—the wider the better!

On a similar note, if you haven’t noticed, I added a search and archive on the left. Use them!—there’s a solid number of posts from the past.

[update] — I got greedy and increased the width even more, to 645.

NumberUtil added to DestroyFramework

 

Continuing with my nightly work towards the DestroyFramework, I started a NumberUtil class. For now, it includes three methods: confine, pad, and insertCommas.

The confine method is like bumper bowling—you provide it with a number, a minimum, and a maximum. It then returns the number within the minimum and maximum:

1
2
3
4
// NumberUtil.confine(value, min, max);
NumberUtil.confine(5, 0, 10); // returns 5
NumberUtil.confine(-5, 0, 10); // returns 0
NumberUtil.confine(15, 0, 10); // returns 10

The pad method fills a number with zeros based on the set number of digits before and after the point:

1
2
3
4
// NumberUtil.pad(value, beforePoint, afterPoint);
NumberUtil.pad(.4, 1, 2); // returns "0.40"
NumberUtil.pad(3.85, 3, 3); // returns "003.850"
NumberUtil.pad(67, 2, 2); // returns "67.00"

Lastly, the insertCommas method places commas every three digits in the integer of the provided number:

1
2
3
4
// NumberUtil.insertCommas(value);
NumberUtil.insertCommas(4815162342); // returns "4,815,162,342"
NumberUtil.insertCommas(274); // returns "274"
NumberUtil.insertCommas(5931.85); // returns "5,931.85"

I hope these are helpful to everyone. Be sure to let me know if you get some use out of them or if you have any suggestions for other methods.

StringUtil class added to DestroyFramework

 

Last night, I started on a new class, StringUtil. There’s already a StringUtil class in the mx.util package, but it lacks a few methods that I use regularly. The two methods I developed last night are truncate and addSlashes.

The truncate method shortens the supplied String and appends an ellipsis (…) if the length is greater than the set length.

1
2
3
var truncatedString:String = StringUtil.truncate("How can you work on a weekend?", 10);
 
trace(truncatedString); // outputs: How can yo...

The addSlashes method is very powerful. I come from a PHP background, so I deeply missed addSlashes in AS3. I took it one step farther though, adding the ability to specify which characters to slash. By default, it slashes quotes, but you can also have it slash single quotes or special regex characters like hyphens, brackets, periods, and question marks.

1
2
3
var slashedString:String = StringUtil.addSlashes("What's up with the name \"DestroyTwitter\"?", "'\"?");
 
trace(slashedString); // outputs: What\'s up with the name \"DestroyTwitter\"\?

I’m having a blast writing these scripts. Expect many additions over the next few weeks.

Use Capabilities.isDebugger to avoid the startAtLogin error in ADL

 

In DestroyTwitter, I make use of the NativeApplication.nativeApplication.startAtLogin property. It allows the app to automatically open whenever the user turns on his computer. It’s a great feature that’s as easy as setting the property to true, though it has a downside. When using ADL (AIR Debug Launcher), if you try to change this property, an error is thrown:

Error: Error #2014: Feature is not available at this time.
	at flash.desktop::NativeApplication/set startAtLogin()

This wouldn’t be a big deal if the developer only experienced the error, but some Linux users run builds that requires AIR apps to launch with ADL. Even though this pertains to only one DestroyTwitter user that I know of, every user deserves the same experience—especially if they do all that fancy command line code. Prior to today, I used the following code to avoid the error:

1
2
3
4
5
6
7
8
9
10
11
12
13
protected var adl:Boolean;
 
public function set openAtStartup(value:Boolean):void {
	if (adl) return;
 
	try {
		adl = false;
 
		NativeApplication.nativeApplication.startAtLogin = value;
	} catch (error:*) {
		adl = true;
	}
}

This works, but I cringe every time I need to use try/catch. While searching the depths of the flash package, looking for a solution, I came across the Capabilities.isDebugger property. It’s exactly what I was looking for, but for some reason, I never knew about it. Here’s the new implementation:

1
2
3
4
5
public function set openAtStartup(value:Boolean):void {
	if (!Capabilities.isDebugger) {
		NativeApplication.nativeApplication.startAtLogin = value;
	}
}

It’s as easy as pie and enables me to remove one more try/catch from my code and another angel gets his wings.

DestroyFramework on GitHub

 

After signing up with GitHub, I was anxious to use it, so I created the DestroyFramework repository—the product of my late night coding. So far, it only includes TextFieldPlus and ScreenMonitor, but I plan to build it over time.

TextFieldPlus is the beginning of my fText rewrite. At the moment, it includes methods to fix the TextField’s autoSize kerning and autoSize scrolling bugs. It’s a work in progress, so expect some additions in the future.

ScreenMonitor is an incredibly useful class for AIR apps. Since AIR doesn’t have any events for connecting and disconnecting displays, if a user disconnects a display while an AIR window is on that screen, it’s lost forever—for Mac, at least. The ScreenMonitor class periodically checks for a change in screen count and dispatches an event when one occurs. It also lets you check manually at any time.

Check it out and keep a close eye. I’m really starting to get the hang of Git.

I’m on the Git to the Hub

 

GitHub

I decided to finally sign up with GitHub. It looks like a terrific community of developers and there are some incredible useful classes hosted on it. Check it out and let me know what you think. And, since GitHub is considered another “social network,” I’ll need to add it to my list of icons on the left—so many things to do!