do } { while

I’ve been coding in coding in various languages since around 1983 and this is the first time I’ve had an occasion to use a do } { while loop.

Here’s the scenario. I have four different kinds of pictures: locomotives, boxcars, tankers, and cabooses. I have eleven versions of each, one for each of eleven colors. I want to display two items on the screen at the same time and ask the child to identify the color. Now if a red boxcar and a red caboose show up on the screen at the same time, both are correct so the child can’t choose the red one. So what I want to do is check to see if the colors are the same and then pick a different object if they are.

I’ve already picked my first object from the list and this is the code I use to pick the second. I always need to pick a second item, so the do { } while construction is perfect. It runs through the code and after the first pass evaluates the conditional. In this case, it checks to see if the color of the first object (leftItem) is the same as the color of the second object (rightItem). If they are equal, it does another iteration and picks another object. I have eleven colors so the loop repeats about 9% of the time, so it doesn’t have any impact on execution. If you only had two or three colors, you’d probably want to use a different method.

Note: The code is Objective C and I changed it a bit from the original to make the loop portion clearer.


  NSInteger randomWord2;
        do {
            // Get another random number between 0 and n-1 
            //and add it to the original number plus 1
            int randomNumber2 = (arc4random() % numItems);
            // If randomNumber2 is not zero then the two words will be different
            if (randomNumber2   == 0) randomNumber2 = self.scoreKeeper.currentScreen + 1;
            randomItem2 = (randomNumber2 + self.scoreKeeper.currentScreen) % numItems;
            self.rightItem = [self.wordList getWord:randomItem2];
        // If the two objects have the same color, look for another rightItem
        } while ( [self.rightItem.color isEqual:self.leftItem.color] );

Sound formats for iOS

This link is useful for understanding sound formats.

For all the sounds that I record, I use .caf format. For pre-recorded sounds I converted them all from .aiff to .m4a using afconvert—a developer tool from the command line. You can also use iTunes.

Here’s the script I use for afconvert. I adopted if from one I found on Sparrow.org. afconvert will convert to lots of formats, but the Apple Lossless makes the smallest file size for me.


#!/bin/bash
# http://www.sparrow-framework.org/2010/06/sound-on-ios-best-practices/
# Reset the field separator to : instead of space so all of the file will be converted
IFS=:
for i in ~/Sounds/*; do
  
  # creates sound.aifc (IMA4 compression, MONO)
  #afconvert -f AIFC -d ima4 -c 1 $i

  # creates sound.m4a (Apple Lossless compression)
  afconvert -f m4af -d aac -q 127 -c 1 $i
done

Copy a file to the Documents directory in iOS

This is a simple method that I use to copy a file from the app bundle to the Documents directory. You can’t modify files in the app bundle, but you can modify them if they are in the Documents directory.


- (void)createResultsDocument {
    
    NSString *documentsDirectory = [self applicationDocumentsDirectory];
    NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"HTML_header.html"];
    
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    NSString *todaysDate = [dateFormatter stringFromDate:[NSDate date]];
    NSString *resultsFileName = [NSString stringWithFormat:@"MPResults_%@.html",todaysDate];
    NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:resultsFileName];
    NSError *error;
    
    [[NSFileManager defaultManager] copyItemAtPath:sourcePath 
                                            toPath:destinationPath
                                             error:&error];
    NSLog(@"The copy error is: %@", error);
    
    // Check that it worked.
    NSURL *resultsURL = [NSURL fileURLWithPath:destinationPath];
    NSLog(@"The resultsURL is: %@", resultsURL);
}

Xcode Buttons

This is some code I used to put a reset button on the screen. It’s mostly self-documenting. First, create a rect. I’ve already defined the x and y coordinates—buttonX and distanceFromTop based on the screen width and other buttons on the screen. Likewise, I’ve already defined the width. The rest of the code is just assigning properties to the button. The action is a method in the file that changes the image to a ‘Selected’ image.


// Reset Button
    @synthesize resetButton = resetButton;
    ....

    CGRect resetButtonFrame = CGRectMake(buttonX, distanceFromTop,
                                         button_width, 25.0f);            
    self.resetButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    self.resetButton.titleLabel.font            = [UIFont systemFontOfSize: 16];
    self.resetButton.titleLabel.textColor       = [UIColor blueColor];
    self.resetButton.titleLabel.shadowOffset    = CGSizeMake (1.0, 0.0);
    [self.resetButton setTitle:@"Reset Scoring" forState:UIControlStateNormal];
    [self.resetButton setFrame:resetButtonFrame];
    [self.resetButton addTarget:self 
                             action:@selector(resetScorekeeper:) 
                   forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.resetButton];
    // This line makes the icons stay in the center of the screen when you rotate
    self.resetButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
    
    ....

- (IBAction)resetScorekeeper:(UIButton *)sender {
    
    [self resetResultsFile];
    [sender setImage:[UIImage imageNamed:@"ResetScoringSelected.png"] forState:UIControlStateNormal];
}

Making MySQL do what you want.

Just some miscellaneous code that I’ve been using to update fields in my database. Basically lots of trimming and concatenating. A little substring manipulating thrown in for good measure.


SELECT *  FROM `words_for_slps` WHERE `F` REGEXP 'z$' AND `pronunciation` REGEXP 'z$'

UPDATE`words_for_slps` SET `phonemes` = TRIM(TRAILING 's' FROM phonemes) WHERE `F` REGEXP 'z$' AND `phonemes` REGEXP 's$' AND `word` = 'Ares'

UPDATE`words_for_slps` SET `phonemes` = CONCAT(phonemes,'z') WHERE `F` REGEXP 'z$' AND `pronunciation` REGEXP 'z$'

UPDATE`words_for_slps` SET `phonemes` = TRIM(TRAILING 's hz' FROM phonemes) WHERE `F` REGEXP 'hz$' AND `phonemes` REGEXP 'hz$'

UPDATE`words_for_slps` SET `phonemes` = CONCAT(phonemes,'ʃ ɛ z') WHERE `F` REGEXP 'z$'

UPDATE`words_for_slps` SET `phonemes` = CONCAT(phonemes,'z') WHERE `F` REGEXP 'z$' AND `pronunciation` REGEXP 'z$'
UPDATE`words_for_slps` SET `phonemes` = CONCAT(phonemes,' ɛ s') WHERE `F` REGEXP 's' AND `phonemes` REGEXP 'n$'

UPDATE `words_for_slps` SET `phonemes` = TRIM(LEADING 'c' FROM phonemes) WHERE `word` REGEXP '^c' AND `I` LIKE 'c'
UPDATE `words_for_slps` SET `phonemes` = CONCAT('k',phonemes) WHERE `phonemes` REGEXP '^ ' AND `I` LIKE 'c'

UPDATE `words_for_slps` SET `phonemes` = TRIM(LEADING 'k' FROM phonemes) WHERE `word` REGEXP '^cy' AND `phonemes` REGEXP '^k'
UPDATE `words_for_slps` SET `phonemes` = CONCAT('s',phonemes) WHERE `word` REGEXP '^cy' AND `phonemes` REGEXP '^ '

UPDATE `words_for_slps` SET `phonemes` = REPLACE(phonemes, 't ɛ,i  d', 't ə d') WHERE `phonemes` REGEXP 't ɛ,i  d$' AND `pronunciation` REGEXP 't u d$'

UPDATE `words_for_slps` SET `phonemes` = REPLACE(phonemes, 'n z', 'nz') WHERE `pronunciation` REGEXP 'n z$' AND `phonemes`REGEXP 'n z$'

I used these select statements to look for words that need some manual cleanup.


SELECT *  FROM `words_for_slps` WHERE `F` <> SUBSTRING_INDEX(phonemes, ' ', -1)
SELECT *  FROM `words_for_slps` WHERE `word` REGEXP '^w' AND `pronunciation` NOT REGEXP '^w' AND `pronunciation` IS NOT NULL

This works when I want to update the fields in one table with values from fields in another table.


UPDATE words_for_slps, words_for_slpsBAK12
SET words_for_slps.grade = words_for_slpsBAK12.grade
WHERE words_for_slps.word_id = words_for_slpsBAK12.word_id;

Even though I’m only updating one table you’d think this should work, but it doesn’t.


UPDATE `words_for_slps` 
LEFT JOIN `words_for_slpsBAK12` ON `words_for_slps.word_id` = `words_for_slpsBAK12.word_id`
SET `words_for_slps.grade` = `words_for_slpsBAK12.grade`