All posts by Arthur Street

My first HTML5 page

My plan is to put together a page that looks a little like the iPhone home screen, with a grid/table/gallery of icons and icon names. This is the first time I’ve written anything in HTML since the ’90s, so this may not be of interest to anyone but me.

  • This post nicely explains three different ways to do it, although it is a few years old and I suspect that now with HTML5 only the “div” approach is recommended.
  • This O’Reilly online book, “Building iPhone Apps with HTML, CSS, and JavaScript”, is a great starting point for how to make it look good.
  • This css-tricks post explains how to make an iPhone “springboard” webpage nicely.
  • This css-tricks post explains how to set gradients for the background instead of using an image, which could take longer to load.
  • I have also found some helpful code in Pro jQuery Mobile, a book by Brad Broulik, using class=”ui-grid-a” and “ui-block-a”. I thought this requires you to keep track of which column you’re up to (so the first column is ui-block-a, the second ui-block-b, etc), but in fact you can just always use the last column’s block (e.g. for a 4-column grid, use ui-block-d).  However, you must decide beforehand how many columns to use. I’d prefer not to have to do this: if the user is on a phone, 3 columns may be all that can fit, but on a desktop, you may want 8 columns.

Here is what I have come up with – it’s actually quite straightforward (once you know how).  This nicely has two columns when viewed on my phone, and more columns on my desktop.  The magic is css’s “float:left” command. In the html file:

<div class="gallery">
  <a href="#">
    <div class="icon">
      <img height=72 width=72 src="images/icon.png">
      <div class="caption" style="width:108px">My icon</div>
    </div>
  </a>
<!--more icons here -->
<p>  <!--finish with a p so the next thing is shown below - see the css -->
</div>

And in the css file:

.icon  {
  text-align: center;
  float: left;
  margin: 10px 10px;
}

.caption {
  vertical-align: top;
}

.gallery p {
  clear: both;
}

.gallery a, .gallery a:link, .gallery a:visited, .gallery a:hover, 
            .gallery a:active {
  text-decoration: none;
  font-style: normal;
  font-weight: normal; 
  text-shadow: none;
  color: black;
}

I had some trouble working out how to reset the “floating” behaviour once the grid (gallery) of icons is finished.  The css command “.gallery:after” should have done the trick, but doesn’t seem to work as expected.  So instead I came up with making <p> clear the behaviour through the css.  It means that you have to put a <p> at the end of the gallery though.

A caveat – I have only tested this on Safari and Chrome so far.

As an aside, I found it hard to include code snippets here – WordPress interpreted the html code even though it was between pre markers… I solved this by typing <pre>x</pre> using the HTML display, then typing the code itself into the visual display to replace the “x”.

Thoughts?

  

Indie life

Ray Wenderlich‘s monthly newsletter has been my friend this week, especially his links on Indie Game Development and in particular this post from Mode 7, which has a lot of advice and further links on topics from coding to finding people to help do art and animation, to business realities and marketing. The life of the Indie game developer is evidently not easy. Even a good-looking, critically acclaimed game that is featured on the App Store can still be a flop…

Now, was it sensible to spend the evening reading these things instead of developing my game (ummm – ok, I also need to prioritise among the games and non-games I have already started), befriending journalists who work for review sites, or working on my business plan?

Probably not.

  

Unit testing private functions in Xcode 4

I have found myself in the uncomfortable position of declaring private methods in my .h files so that I can run tests on them, and have been looking for ways around this.

I’ve found discussions about handling this in C++ which have me thinking it is bad programming style to need to test private functions: instead, complex private functions should be moved to a new class where they are public. I like the intellectual purity of this approach, but I have to think about how to apply it in my case.

In the meantime, I would like to have two types of unit tests, those on private functions and those on public functions.  Only the public functions define what the class does, of course, but unexpected failure of tests on the private functions can help me quickly find and debug problems.

Fortunately, another Stack Overflow post pointed me to a solution for Objective C.  I declared a new category (“Private”), put the private methods in the classname+Private.h header file, and deleted the classname+Private.m file.  I then import this .h file in classname.m, as well as the unit tests.

[Note the first time I read that post, I misinterpreted it, and created a .h and a .m file for the new category, and tried to implement the private functions in this new .m file.  This approach doesn't solve the original problem at all.]

Using a “Private” category feels like a nice solution, since I could have declared those private functions in a class extension at the top of the classname.m file anyway.  Adding the Private category just allows the unit tests to access them too.

Nonetheless, I’d appreciate any comments on the benefits are of the purer approach of moving complex private functions into a new class…

  

My first Mac app

I decided to take a break from programming iOS apps, and wrote my first Mac OS X app today.  It was surprisingly simple.  It is based on the NSDocument class, and there is an Xcode template for this.  This template has all the menus, including cutting and pasting, formatting, etc, already built in and function. The main additions to the template were putting an NSScrollView in the window in the Document.xib file so I could edit some text, and adding some code to save and read files.

Of course, there were a few hiccups, which I mostly overcame:

  • The Document.h header file does not care about the NSScrollView; you need to hook it up to the NSTextView instead.  The formatted text sits within the text view, and can be accessed via the textStorage method. This has class NSTextStorage, which is a subclass of NSAttributedString.
  • The vaguely named dataOfType:error: method is for saving data, and the readFromData:ofType:error: method for reading data.
  • I posted the approach I used for reading and writing at Stack Overflow here, because I suspect the way I came up with is not guaranteed to work.
  • You should not set the text in the text view in the reading routine, because it may not exist yet.  Save it to an instance variable.  Set the text to this ivar in the windowControllerDidLoadNib: method.
  • I saved two icons, icon_128x128.png and docIcon_128x128.png, into my project.  In my <app name>-Info.plist I set the icon file to the first file name (including the .png), and under Document types, the Icon File Name to the second file name.  This associates those pictures with my app in some places (e.g. the about box, and within Xcode), but it does not ultimately set my app’s icon in the Finder.  How do I do this?
  • It was surprisingly hard to get the compiled program out of the Xcode environment and into a finished app that appears in the Finder on my Mac. The trick is to archive it, then press “Distribute…” (of course!).  You can choose to distribute it directly, and ad-hoc, and export as “Application”.
  

Compressing data

I had occasion today to compress some data (in the form of an NSData object).  Thanks to many people who have gone before me, this is fairly easy to do:

  1. Add “libz.dylib” to your project’s frameworks.
  2. Unfortunately this library only comes with some low-level functions, e.g.inflateInit2 and deflate.  However, the good people at CocoaDev have created a category on NSData which hides all this.  I only copied the two short methods gzipInflate and gzipDeflate. I can’t work out their formatting – I copied the text from the View Source page, and had to go through it afterwards to re-insert asterisks and take out square brackets.
  3. These two functions work!  I wrote out the data to a file using two path extensions, my original one and “gzip”, and this seems to work; the Finder recognises these files as compressed and does the right thing by them.
  

Dismissing the keyboard

I dragged a UITextField onto my xib file, and hooked up the “Editing did end” action to my view controller, and put some code in there. When I ran it, touching in the text field brings up a keyboard… but the keyboard does nothing, and pressing return does not dismiss it.

The solution is straightforward, but not obvious. You need to set up a delegate which follows the UITextFieldDelegate protocol, and add the following method to it:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange: 
            (NSRange)range replacementString:(NSString *)string {
    if ([string isEqualToString:@"n"]) {
        [textField resignFirstResponder];
        return NO;
    }
    return YES;
}

Note if you are adding a UITextView though, the process is a little more subtle. First up, you probably want to allow carriage returns in the text, so you need to hook up a Done button somewhere else which resigns the first responder. You also need to set yourself up as a delegate for the UITextView, and then implement:

# pragma mark - UITextViewDelegate notifications

- (void)textViewDidBeginEditing:(UITextView *)textView {
    self.activeView = textView;
}

- (void)textViewDidEndEditing:(UITextView *)textView {
    self.activeView = nil;
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range 
                replacementText:(NSString *)text {
    // do anything you need, e.g. resize in response to a return key
    return YES;
}

Also, it’s recommended you do this inside a UIScrollView so you can scroll the field out from under the keyboard if needed – see Apple’s docs for more.

  

Animating UIViews

I’ve been searching around for the best way to animate a button so that it would pulse continuously, and then how to stop it animating – without using the deprecated “commit” animation style.  It took some searching, so to save time next time, here is the way I settled on. The tricks are: there are options you can pass that keep the animation repeating, and autoreversing. There is also an option you need to pass if you want the button to still be pressable. And finally, to cancel the animation, just start a short new one which takes it back to its original size, which you must have saved somewhere beforehand. (Do not use an empty final animation though, as that doesn’t seem to stop the old one.)

[UIView animateWithDuration:0.3 delay:0
   options:(UIViewAnimationOptionCurveEaseInOut |
            UIViewAnimationOptionRepeat |
            UIViewAnimationOptionAutoreverse |
            UIViewAnimationOptionAllowUserInteraction)
   animations:^{
      CGFloat inset = -self.myButton.frame.size.width * .1;
      self.myButton.frame = CGRectInset(self.myButton.frame, inset, inset);
   }
   completion:NULL
];
[UIView animateWithDuration:0.15 delay:0
   options:(UIViewAnimationOptionBeginFromCurrentState |
            UIViewAnimationOptionCurveEaseInOut)
   animations:^{self.myButton.frame = self.origFrame;}
   completion:NULL];

One pitfall – I found if the button has an image, and it is already showing at full size, then the above code will not do anything – the image cannot be made larger than full size.

  

Using Gimp

I mentioned before I’d downloaded Gimp, a free paint-style program, to help make graphics for my apps.  I’ve struggled to use it for anything much though, but last night I was able to make a simple tab-bar icon.

To make a tab-bar icon in Gimp:

  • Choose File -> New an make a new 60×60 (for retina) image.
  • Choose Layer -> New Layer and choose layer fill type “Transparency”.
  • Delete the original background layer over in the “Histogram” window: drag the old layer from its position about halfway down the window to the tiny garbage bin in the bottom right corner (on my Mac this is half covered by the window-resizer).
  • Now paint into this layer with black where you want the image.  You should only use one colour.  I tried using black and white, and only union of the two shows up in the tab bar.
  • File -> Export the picture.

To take an existing image and set a background colour:

  • Use the magic wand tool, which selects regions by colour.
  • Select the coloured region you want to make transparent.
  • Choose Layer -> Transparency -> Add Alpha Channel (if you can).
  • Choose Edit -> Clear.

I expect you can use this directly as a tab bar icon now – just the remaining colour information will be ignored.  But I have yet to test this.

  

Reloading table data in a UITableView

Work.

I have been using a UITableView and had quite a bit of trouble getting its entries to update.  Just calling the table view’s reloadData method didn’t seem change anything on-screen.  In the end I found it works fine to manually call tableView:cellForRowAtIndexPath: for each entry you want to update; the following sample code (placed in the relevant view controller) works for a table with only one section in it. myTableView is an IBOutlet.

-(void) entriesUpdated:(NSNotification*) notification {
    int numRows = [self.myTableView numberOfRowsInSection:0];
    [self.myTableView reloadData];
    for (int i=0; i < numRows; i++) {
        [self tableView:self.myTableView cellForRowAtIndexPath:
              [NSIndexPath indexPathForRow:i inSection:0]];
    }
    [self.myTableView reloadSections:
          [NSIndexSet indexSetWithIndex:0] withRowAnimation:
          UITableViewRowAnimationNone];
}

Note this code has (at least) one drawback – it can call tableView:cellForRowAtIndexPath: with a row beyond the table’s size, if rows have been deleted. As a result, that code must explicitly check that the row is valid.

Surely this is not the way you’re meant to do it though? Has anyone else had this problem, and can you point me to a cleaner solution?

  

Bits and pieces

Work.

Discovered a helpful hint for converting iPhone storyboards to iPad storyboards and vice versa: view the storyboard as Source Code, and simply copy and paste from one to the other.  The only change that needs to be made is on one line, change iOS.CocoaTouch to iOS.CocoaTouch.iPad or vice versa.

Files that your app saves when running in the simulator can be found on the filesystem under /Users/<username>/Library/Application Support/.  Note though that the Library directory is hidden in the Finder under Lion – but you can access it by holding down Option and clicking on the Finder’s “Go” menu.