Tuesday, October 27, 2009

Accessors and Memory Leaks

As my understanding of Cocoa memory management creeps forward, I occasionally discover new types of memory leaks in my own code. My latest find involves initializing instance variables using accessor methods.

Let's say I have a class MyViewController with a property theImage. In the interface file, I declare the variable and define it as a property:

UIImage *theImage;

...

@property (nonatomic, retain) UIImage *theImage;

In the implementation file, I use the synthesize directive to give me free accessor methods. Because I have the property set to retain the variable's object, I add a release to the dealloc method:

@synthesize theImage;
...

[theImage release];


At some point in one of the methods, I initialize theImage:


[self setTheImage: [[UIImage alloc] initWithContentsOfFile: filepath]];


Looks innocent enough, right? Trouble is, the image created by the alloc will never get deallocated.

The problem arises because each allocation of an object must be balanced by a release of that object. Likewise, each retain of an object must be countered by a release. In this case, a retain is being done when we set the property using setTheImage; that's because the property was declared with the retain option. No problem; that retain is countered by the release in the dealloc method. But the call to alloc isn't countered anywhere, which leaves us a UIImage instance that is never fully released.

There are several solutions:

1. Use temporary variables with alloc. The above code could be rewritten as:


UIImage *tempImage = [[UIImage alloc] initWithContentsOfFile: filepath];

[self setTheImage: tempImage];

[tempImage release];


Using tempImage gives us a way to balance the alloc with a release.

2. Use autorelease. Here's a less verbose way to plug the leak:


[self setTheImage: [[[UIImage alloc] initWithContentsOfFile: filepath]] autorelease];


The downside here is that autorelease relies on Cocoa's automatic memory management capabilities, which introduces a bit of overhead in the form of less efficient memory usage (because objects end up sticking around longer than they need to) and additional processing (because the cleanup process must run periodically when otherwise it wouldn't have to). Exactly how much this overhead ends up mattering is the subject of much debate.

3. Use a convenience method instead of alloc/init. In many cases, convenience methods are available that make your code even more streamlined while still preventing leaks:


[self setTheImage: [UIImage imageWithContentsOfFile: filepath]];


Behind the scenes, convenience methods allocate, initialize, and autorelease your object, so this code is effectively equivalent to the code in the autorelease example.

I have yet to decide my personal position on the use of autorelease, but I'm going to start making sure I use one of these three approaches when initializing properties.

Monday, October 26, 2009

Xcode: EXC_BAD_ACCESS

This Xcode console message is sometimes the only clue as to why an iPhone app just crashed:

Program received signal: “EXC_BAD_ACCESS”.


According to codza, this message indicates that a method on an object that no longer exists has been called. In my limited experience, it means my code has released something it didn't own. For example, I was recently getting this crash because I was releasing a UIImage property in the dealloc method but not taking ownership of the value back when I was setting the property.

The best advice I've seen for debugging this problem involves putting the executable in a mode that keeps around "zombie" copies of deallocated objects, thus allowing the debugger to display more information about what wrong. And it's easy to configure. Truly a huge time saver.

Thursday, October 22, 2009

UIScrollView for Data Entry Pages

My wine app has more fields on the data entry page than will fit on the iPhone's screen, so I decided to put the controls inside a UIScrollView. I had trouble finding good examples of such oversized data entry pages, so I mostly experimented in Interface Builder.

The first step is to increase the size of the main view so that it's large enough to accommodate full page. This can be done just by dragging the standard resize control on the lower right corner of the view window. As noted previously, this can't be done unless all the Simulated User Interface Elements (in the View Attributes) are set to "None".

The next step is to drag in a UIScrollView control from the Library. Make it the same size as the main view. Drag all labels, text fields, etc. to this scroll view; note that the controls appear under Scroll View in the main window when viewed hierarchically.

The next step is to resize the main view and the scroll view to the size of the iPhone screen. First shrink the scroll view to smallish box in the upper left corner of the main view. Then shrink the main window back to standard size; a fast way to do this is to turn back on one or more of the Simulated Interface Elements. Finally, expand the scroll view so that it fills the main view.

There is one more step that I finally figured out after banging my head against the wall for a few hours (I found the lead here). For some reason, the scroll view will not scroll unless it's explicitly told that its content -- the collection of fields and other controls -- is bigger than its visible area. This must be done in code.

First, add a UIScrollView property to the view controller class. As with other view properties, this means 4 lines of code:
1. Adding an instance variable of type UIScrollView to the header:

UIScrollView *scrollView;

2. Adding a property directive for that instance variable to the header:

@property (nonatomic, retain) IBOutlet UIScrollView *scrollView;

3. Adding a synthesize directive for the property to the implementation file:

@synthesize scrollView;

4. Adding a release of the property to the dealloc method's implementation.

[scrollView release];


Next use Interface Builder to map the scroll view property to the actual UIScrollView control. This means right clicking on the File Owner and dragging from the new property's little circle to the scroll view.

Now the scroll view object can be accessed in code by referencing the new property. What's left is to set the scroll view's contentSize property to the full size of the scroll view. I did this from the view controller's viewDidLoad event:

[scrollView setContentSize: CGSizeMake(320, 640)];


You might have to experiment to determine what size is best for your scroll view.



Thursday, October 08, 2009

Objective C "toString"

Through a little digging, I found that Objective C's equivalent to Java's Object.toString method is NSObject's description method. Of course, it can be called on any object that has NSObject as an ancestor, which is typically all objects.

Wednesday, October 07, 2009

Objective C Hello World, Part III

Completed the tutorial, and the app seems to work as expected. I only ran into one inexplicable quirk: when the app runs, the MyViewController view ends up rendering in the simulator at the upper bound of the screen, beneath the phone's status bar. Here's how the view window looks in Interface Builder:


Here's how it looks in the iPhone simulator:


The green band at the bottom is the background of the main view showing through.

The problem appears related to displaying the simulated status bar in IB. When Status Bar (in the View Attributes palette under "Simulated Interface Elements") is set to "Gray", the height (H on the View Size palette) is set to 460, and it's display-only. Changing Status Bar to "None" makes the height property field editable; changing it to 480 makes the view the full height of the screen. This gets rid of the green band, but leaves the edit field right up against the simulator's status bar. The only solution I can find here is to scoot the field down.

This sure seems like a bug with the simulator. Shouldn't the top edge of the view render just below the status bar? I'm betting this is how the app would behave on an actual device.

Tuesday, October 06, 2009

Objective C Hello World, Part II

I finally fixed the problem I was having with my nib file not getting found! Turns out the MyViewController.xib was set as a file type of "sourcecode.xib"; switching it to "file.xib" solved the problem. File type can viewed and updated by right-clicking the MyViewController.xib file anywhere in Xcode and selecting "Get Info".

I figured out this fix by examining the MoveMe sample app project -- which has been running just fine in the simulator -- and looking for differences with my HelloWorld project. I had already tried going through a similar but different HelloWorld tutorial, but ended up with the same error. I had also tried uninstalling and reinstalling the SDK.

One clue there was something wrong with the .xib itself: double-clicking MyViewController.xib in Xcode never opened the file in Interface Builder. Instead, the file's underlying XML would open, complete with color-coding. I could only get it opened in IB by selecting "Open With Finder" from the context menu, or using File > Open in IB. All of my self-made nibs behaved this way.

I have no idea why this happened. Maybe it's a bug in this Snow Leopard build or Xcode (version 3.2, SDK build 10a432)?

One other issue: I was getting a warning when I compiled MyViewController.xib about there being "no rule to process file". The warning went away when I moved the reference to MyViewController.xib out of Targets > HelloWorld > Compile Sources and into Targets > HelloWorld > Copy Bundle Resources. I don't know if this was important.

Friday, October 02, 2009

Objective C Hello World

This is frustrating. I'm carefully following the iPhone HelloWorld tutorial, but I still have run into a problem with the Adding a View Controller step. At the end of the section, I test the application in the simulator and it promptly crashes. Here's the error message in the console (Run > Console):

2009-10-02 14:01:04.641 HelloWorld[5358:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] was unable to load a nib named "MyViewController"'


This appears to be a reference to the following code in HelloWorldAppDelegate.m:

MyViewController *aViewController = [[MyViewController alloc]

initWithNibName:@"MyViewController" bundle:[NSBundle mainBundle]];


The implication is that the nib file MyViewController.xib can't be found. That file is in fact in my project; it's in the Classes folder, where is was automatically created. This must be user error, because I can't find a single other person via Google that's having the same problem. I tried using the source provided in the tutorial, but the application still crashes. Maybe it's something wrong with my environment?

I poked around, and thanks to a tip from a blog and the official documentation, I was able to get the application to work by using nil instead of specifying the nib file name:

MyViewController *aViewController = [[MyViewController alloc]

initWithNibName:nil bundle:[NSBundle mainBundle]];


Supposedly, specifying nil instead of the nib file name tells the view controller class to assume the nib file has the same name as the class, which in this case is "MyViewController". No idea why this should when hardcoding the name doesn't.

But it turns out this didn't fix the problem. I continued to the next section of the tutorial and changed the MyViewController view background color to lavendar, but the background still shows up white when I run the app. On a hunch, I changed the background of the MainWindow view to green. Now the background shows up green. So no view is getting loaded.



Objective C Method Syntax

The syntax for calling an Objective C method is quite novel in my experience with programming languages. It essentially involves mangling the name of the method, inserting argument expressions at placeholders specified in the method definition.

Let's say we're going to declare a method for a class Alien that moves the alien to a new position on the screen. The method declaration might look like this:

-(int) moveToX: (int) newX Y: (int) newY;

The hyphen indicates this is an instance method. The (int) indicates the method returns an integer (maybe some kind of status code indicating whether or not the move was successful). So far, so good. Now for the trick question: what's the name of the method? It's not "moveToX"; it's "moveToX:Y:". Huh?

The method declared above takes two arguments, the values of which can accessed from within the method using variables newX and newY. Both arguments are integers. Objective C provides for the labeling of method arguments, but it does it in a way that mingles what would normally be thought of as the method name ("moveTo") and the label of the first argument ("X"). The labels of subsequent arguments (like "Y") stand alone.

Argument labeling in method declarations is not required. What is required is a word followed by a list of colon-prefixed argument declarations. For example, here's a more minimalist declaration of the same method:

-(int) moveTo: (int) newX : (int) newY;

The two methods are functionally identical, but the official name of the second method is "moveTo::". This style of syntax, while slightly odd to someone coming from a Java or C++ background, is more consistent with the method-name-then-argument-list approach seen in many other languages.

While this second approach may seem less confusing, it is apparently frowned upon. Consider the syntax for calling this second method:

int n = [myAlien moveTo:10 :30];

This code creates integer variable n, calls the moveTo:: method of the myAlien object with the arguments 10 and 30, and places the result of the method call in n. By itself, this line of code doesn't provide many clues about what the values 10 and 30 are expected to represent. Consider instead a call to the moveToX:Y: method:

int n = [myAlien moveToX: 10 Y: 30];

Here, it's much more apparent what's expected of the provided arguments, thus the code is -- at least in principle -- more readable.

It's important to note, however, that Objective C's support for argument labeling ends here. Method calls must use the full method name. This means that, unlike with argument naming support in some other languages, all method argument labels used in the declaration must appear in the method call, and in the correct order.


References:

Saturday, September 26, 2009

Custom Classes In GI

A few notes about creating classes in General Interface:
  • Each class gets its own .js file. The name of the file (less the extension) is the name of the class.
  • Use a call to static method jsx3.lang.Class.defineClass to define a class. The first parameter is the name of the class as a string. It can include package-like qualification, but the qualification doesn't actually have to correspond to the location of the .js file. All that matters is that the unqualified name of the class matches the name of the .js file. The second parameter is a reference to the super class and the third parameter is an array of references to implemented interfaces; use the null keyword if either one of these parameters is irrelevant. The forth parameter is a function that declares the class.
  • The function that declares the class must receive two arguments. The first is an object to be used as a prefix when declaring static members in the body of the function; the second is for instance members.
  • Within the body of instance methods, use the this keyword to reference the instance. Use the unqualified name of the class to reference static members.
  • A method named init is required; this acts as the constructor, i.e. it is called for each instance at the time it is created. If there is a superclass (other than the default, jsx3.lang.Object), it's constructor must be called from within init. This can be accomplished by calling the standard jsxsuper() method of the instance, passing any arguments needed by the constructor.
  • Declare an instance of the class by using the new keyword followed by the fully-qualified name of the class, followed by arguments to the constructor wrapped in parentheses. For example:
var ratingControl = new gui.ImageButtonGroup();


Monday, September 14, 2009

Upgrade to Google App Engine 1.2.5

My primary interest in upgrading to the new release is a Windows version of Google App Engine Launcher, which has been available on the Mac side for a long time. Unfortunately, I got a message about the installation failing because of error 2908.

After some Googling, I found a solution. First, I ran the installer again and selected the "remove" option. Second, I launched RegEdit (Start > Run... > regedit) and deleted this "key" (folder):

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\
Installer\UserData\S-1-5-21-1123561945-1935655697-1060284298-1003\
Components\AD95649F068525549B26938D7D18FEA7

Finally, I reinstalled GAE. No errors this time. But when I launched Google App Engine Launcher from the Start menu, I received a different error:




An uninstall using Add/Remove Programs followed by another install didn't help. I looked in the referenced log file and found this:

wxPython is not available
wxPython is not available
wxPython is not available
wxPython is not available
wxPython is not available

A little research suggested wxPython is a GUI library for Python upon which the GAE Launcher is built, so I downloaded and installed it (I selected the Win32 version for Python 2.5). But kept getting the same errors.

More research. MSVCP71.dll does not appear to be part of wxPython; instead it's a standard Microsoft C library, one that ships with many different pieces of software. It appears, though, that sometimes software developers forget to include it because it's almost always present on Windows machines.

I downloaded the DLL from DLL-Files.com and copied it to C:\Windows\system32. Ta da! Google App Engine Launcher is up and running! Maybe I didn't need to install wxPython after all?

Within a couple minutes I had added my application and was up and running.


Thursday, August 27, 2009

GI/GAE Deployment

I recently had a breakthrough in which I got a General Interface client to communicate successfully with a Google App Engine back-end via JSON. Not only was that success using Google's development server running on locally, but it was with the GI client running inside of the GI builder tool. My success tonight was getting the GI application successfully deployed on the GAE development server. Now I can run the application by navigating to a URL. This involved three main steps: tweaking GAE to support static files, copying the right GI files into the right GAE folders, and creating a GI launch page for my application.

Activating support for static files on GAE is fairly well documented. In my case, I decided to add a "static" folder under my GAE application folder ("winenotes"). I then modified my app.yaml file to look like this:

application: winenotes
version: 1
runtime: python
api_version: 1

handlers:
- url: /static
static_dir: static

- url: .*
script: winenotes.py

In this way, static files can be accessed by tacking their path and file name to the end of the URL, starting with the "static" directory.

The second piece is copying the GI files to the GAE server. I created a "gi" directory under "static", and copied both the JSX and JSXAPPS folders there (I removed everything from JSXAPPS except the folder for my application).

The final step is creating a launch page, as described in the GI Developer's Guide. From within the builder, I selected Project > Deployment Utility. I picked the "static" directory and named the file "launch.html". Clicking Create automatically generates a starter file with the specified name and location. The paths in the generated file required a bit of editing; I modified the script section to look like this:

<script type="text/javascript" src="gi/JSX/js/JSX30.js" jsxapppath="gi/JSXAPPS/wineLog/">
</script>

That's it. Once I started the Google App Engine server, I was able to launch my application by opening http://localhost:8080/static/launch.html. The only glitch is an error message that appears as the application is loading:


The application seems to load just fine after clicking OK. I need to investigate the error message further.

Tuesday, August 25, 2009

General Interface: Changing Scripts

Every time I change a script in General Interface it seems like I have to quit the builder and restart it before the change is noticed. Here's an easier way that seems just as reliable: right click on the script file in the Project Files palette and select Load/Reload. I don't understand exactly why it works -- shouldn't GI know to refresh the cached version of a script after it's changed? -- but it does.

Monday, August 24, 2009

Success! General Interface and Google App Engine

It's been painful, but I finally got a General Interface front end to display data from a custom Google App Engine service. I had previously gotten Google App Engine to return data in JSON format via an HTTP Get, and General Interface to read that data from a stub file and display it, but I hadn't been able to get GI to successfully source the data from the service. Until now.

The trick is apparently in the rules file: it needs to have an input/request node. I added the following XML to the rules file right before the output node (I couldn't figure out how to add the node using the XML Mapping Utility):

<record jsxid="x37650" jsxtext="Input (request)" type="I" jsxopen="1"/>

Now when I open the rules file in the XML Mapping Utility it looks like this:


I got the idea for the input node from the the Yahoo Travel demo posted on the TIBCO Community site. The GI documentation is in bad shape to be missing such basic information. I hope developing with GI gets easier.

Note that I haven't deployed the GAE application yet; I'm just going against the local development server.

Friday, August 21, 2009

Google App Engine on Windows

I've been doing General Interface development in Windows under Parallels. I've been doing Google App Engine development directly in OS X. I haven't quite figured out how to get them talking to each other. In the meantime, I decided to install GAE on Windows so that the client and the server would be on the same "machine".

It was a pain figuring out how to start the GAE development server. The official documentation makes it sound simple, but in reality it seems very finicky about paths. Here's what is working:

C:\Python25\python "C:\Program Files\Google\google_appengine\dev_appserver.py" --datastore_path=Z:/Users/john_beretz/temp/datastore Z:\Users\john_beretz\Documents\briefcase\Projects\GoogleAppEngine\winenotes

Another quirk: according to the documentation, I should be able to stop the service with Ctrl-C. While that does seem to stop the service, it doesn't do it gracefully: the whole thing just locks up.

Sunday, August 16, 2009

General Interface: Buttons, Scripts, and Dynamic Properties

I'm now using the latest version of General Interface: 3.8. This is the first version to drop the "TIBCO" moniker, i.e. it is the first version released since General Interface was made open source.

I've been using the example application mentioned in the previous post to become familiar with some of the basics of GI. For instance, indicating which script should run when a button is clicked is simple, if you know where to look. The script is not referenced in a property of the button; instead, it is accessed through the Events Editor palette. While the button object is selected in the Component Hierarchy palette, several events are listed in the Events Editor palette; the value specified for "Execute" is the name of the script to run when the button is clicked.


Another feature that was at first confusing: dynamic properties. General Interface allows you to specify property values in the Properties editor palette either as hard coded literals or as references to name/value pairs stored in an XML file; the latter is referred to as a dynamic property. There's no special syntax to indicate whether the value you enter in the Properties Editor is static or dynamic; apparently GI just figures that it's dynamic if it matches one of the dynamic property names you've defined, and otherwise it's static. Once you've entered a reference to a dynamic property in the Properties Editor, GI displays the reference in gray followed by the current value in brackets.

I haven't tried creating my own dynamic properties file yet, but the one in the example above is named appLabels_ljss.xml and is stored in the project's jss folder (by the way, dynamic properties files are sometimes referred to a "jss" files).

Friday, August 14, 2009

TIBCO GI and JSON Services

Finally found what looks to be an example of how to get TIBCO GI working with a web service that returns JSON (see the May 19th post by Vic Patterson).

Wednesday, July 15, 2009

AVCHD and Picasa

Found this handy blog entry explaining how to get AVCHD video taken with our Panasonic Lumex ZS3 into Picasa. After installing the linked software (accepting all defaults), I was able to add video to the library by dragging folders containing .m2ts files into the Picasa file explorer. Importing off the camera went well, too, although the camera froze up the first time I tried it (the second time worked fine).

One significant advantage Picasa has over the bundled PHOTOfunSTUDIO is that importing to a network drive is supported.

Monday, July 13, 2009

IO Gear Print Server on pookaNet

I got the IO Gear Print Server running with the crappy old HP DeskJet 820Cse on pookaNet. This is the first time I've tried it in months. I think I now understand why I ran into so many inexplicable problems the first time: only computers wired to the network seem to be able to detect the printer. If you're on a computer connected to pookaNet wia WiFi, you're out of luck.

Need to work on this more in the future.

IP is 192.168.1.254.

Saturday, June 13, 2009

Amazon S3 for Offsite Backup

Sherry and I are enjoying our new Panasonic Lumix ZS3 digital camera with HD video capture; the only downside is that we're rapidly filling disk space with irreplacable image and video files. I've been researching options for using Amazon's S3 disk-space service as a repository for backups. I'm particularly interested in S3 because (1) it doesn't seem like anyone can beat the price and (2) I'm interested in getting my feet wet with S3. One possible Windows configuration:
  • S3 WebDAV wrapper. This would expose the S3 storage via a WebDAV API. s3DAV is an open source example.
  • WebDAV network drive wrapper. This layer introduces the ability to present a WebDAV source as a mapped drive. NetDrive is a freeware example.
  • Backup software. Two good open source backup utilities are SyncBack and Cobian Backup.
A variation on the above would be using Gladinet Cloud Desktop instead of the WebDAV and network drive wrappers.

Friday, April 03, 2009

Regular Expression Date Detector

The regular expression

[01]?[0-9]/[1-3]?[0-9]/(20)?0[0-9]

finds dates since 2000 in mm/dd/yyyy format. Granted, it also finds some invalid dates (like 00/0/2000) but it gets the job done 99% of the time if your just trying to find dates within a document, rather than validate dates.