UIImage Crash on iPod Touch

While testing my app on an iPod Touch I started getting an out of memory crash. It turns out that when using imageNamed: iOS keeps the picture around in case it is needed later. It is supposed to remove it from memory when it needs more memory, but it is slow to do so and causes the app to crash. I replaced it with imageWithContentsOfFile: and the crashes went away.

VM Tracker.png


/ Put the picture on the screen. Most will be jpegs
    //NSString *pictFileName = [NSString stringWithFormat:@"%@.jpg",pictName];
    NSString *pictFile = [[NSBundle mainBundle] pathForResource:pictName ofType:@"jpg"];
    if (  [PICT_TYPE isEqualToString:@"png"] ) {
        //pictFileName = [NSString stringWithFormat:@"%@.png",pictName];
        pictFile = [[NSBundle mainBundle] pathForResource:pictName ofType:@"png"];
    }
    
    //self.imageToDisplay  = [UIImage imageNamed:pictFileName];
    self.imageToDisplay = [UIImage imageWithContentsOfFile:pictFile];
    

From the documentation for imageNamed:,

This method looks in the system caches for an image object with the specified name and returns that object if it exists…
If you have an image file that will only be displayed once and wish to ensure that it does not get added to the system’s cache, you should instead create your image using imageWithContentsOfFile:. This will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app.

So for all of my icons that remain on the screen, e.g. microphone, speaker, checkboxes, I use imageNamed:. They are small and reused so they belong in the cache. For the main image on the screen, which is large, there will most likely be lots of other images used before it is used again. The cache will be purged before the app gets around to using it again so there is no point to putting it there in the first place.

Non-Hackers as Founders

This is a continuation of my thoughts about founders that I started in the post on Women as Founders. There are literally thousands of startups out there, most of which you’ve never heard of—either because the solve a problem that you don’t have or because they never got the number of users required to be a sustainable business. I started at the beginning (2005) and looked through the list of startups funded by Y-Combinator. Looking through the list from the first few years, most of the startups solved problems that other hackers had. Part of this is no doubt due to the fact the Y-Combinator was founded by successful hackers. But part of it was not doubt due to the fact that the founders were solving a problem that they had. Most of the startups seem to be other solving technical problems, website design, secure payments, photo editing. Or they solve a communication problem, or social connection problem.

I’ve started several web-based companies. The ones that failed to get up and running did so because I was relying on other people to do the actual development. In 2001 my cousin was getting married and I thought it would be good to put up a website where people could share photos of the bride and groom, exchange anecdotes, and coordinate travel plans. There was even an obvious revenue model—link to hotels and gift-registeries and receive a commission on purchases. We could expand the site to other special events like reunions, golf-events, fund-raising walks, etc. The opportunities seemed wide open.

While I knew a little about programming a website, I didn’t know enough to do the whole thing. So I enlisted a partner to do the coding. The thing about coding is that even if you have a detailed specification, which we didn’t have, there are lots of decisions that get made on a regular basis that affect the final product. And every decision that the coder made was different from my vision. A lot of the things were things that just never occurred to the programmer. For example, if you have several pages on the site that start with a photo, they need to be in exactly the same place on every page. Otherwise when you move from page to page, the pages jump all over the place. And back then, most people were still using small monitors, so we couldn’t design a page that was wider than around 600 pixels or else people would have to scroll sideways to see it. Likewise, we needed to stick with a 65,536 color palette for most of the design. At the end I literally spent more time trying to persuade the coder to do things the way I wanted than they spent coding. I would have been better off spending the time learning how to code myself and then coding things the way they were supposed to be coded.

And I think that’s the difference between a coder and a hacker. The coder just wants to get the project done. The hacker wants to get it done right.

Since then, I have never let someone else be the coder on my projects. I will pay people to help me out when I am first learning a new language, but I do my own coding. And none of my projects have failed because they didn’t get built.

That’s not to say it couldn’t work. I can see how having a non-coding founder would be great for lots of startups, especially those that rely on face-to-face marketing or lots of back-end coordination with other businesses. But the kinds of startups that require a lot of coding seem to me to require hackers as founders.

Women as Founders

Paul Graham got a lot of flak recently for something he didn’t say about the ability of women to found startups.

We can’t make women look at the world through hacker eyes and start Facebook because they haven’t been hacking for the past 10 years.

As he explains, that didn’t sound like anything he’d say, and in fact is the opposite of what he thinks. The journalist neglected to put the quote in context and left our a crucial word. The actual quote was,

We can’t make these women look at the world through hacker eyes and start Facebook because they haven’t been hacking for the past 10 years.

And the question was about why his startup company couldn’t accept more women into their startup class and train them to be hackers. So he was answering a question about why it would be impossible in three months to turn someone who wasn’t a hacker into one. It had nothing to do with the skills of women hackers or really anything at all to do with women. It really had more to do with what makes a successful founder of a startup.

A lot of small software companies (some of which become large later) are founded by people who are “scratching their own itch”. They run across a problem in what they are doing and solve it. If they had the problem, odds are good that others did too, so they publicize their solution. There is a long history in the open software movement of doing just that. Many of the tools that programmers use every day are the result of sharing their solution with others. The web runs on Linux and the GNU tools and both were started by people who wanted to solve a problem that they had, and it turns out that others had the same problem and were interested in cooperating to solve it.

This hacker mindset is not something that can be taught in three months. I’ll give an example of what I’m talking about on a small scale. My server guy got a new job about a year ago. I know a little about server administration, but had to learn a lot more to keep them running. I got a bit of practice setting up a server when we moved ours from a dedicated server to a VPS. And then I set up one for my nephew. And started maintaining one for someone else. Now logging into a server isn’t hard, you use the command ssh loginid@servername and then type in your password at the prompt. And for my server it wasn’t hard since the commands were usually stored a few lines up in my history and so I just had to use a few up arrows to avoid typing. But with four servers to log into (two of which used numbers—not domain names) I had a harder time finding the lines in history and remembering the passwords for each site. And that’s where the hacker mindset comes in. The command line interface that I use is called bash and it lets you write login scripts and aliases. You can get really complicated with scripts, but I just wanted a shortcut to log in to my servers.

So I wrote an alias to get into my server, ¯server=’ssh loginid@192.168.194.220′, then all I had to do was type server and I could get into my server. And then I wrote an alias for each of the servers that I work on.

But if there is an update that needs to be applied on each server, I want to make sure I do it for each one, so I wrote a simple one that listed all of the servers and then I’d type in the number of the one I wanted to use. My command line prompt looked like this.


loginid@My-MacMini: ~ $ connect
1) server
2) dave
3) don
4) purple
5) Quit
Select a server. 

Then I set up each of the servers to use secure authorization, so that I didn’t have to type a password, it used a public-key encryption method to verify that I was allowed in.

Now when you are working on lots of servers, you sometimes forget where you are. So I decided use a different color prompts for each server. One looked like this: loginid@server: ~ $

I copied the login script to each of the servers and tested it out. I decided to make some changes and so I had to copy it to each of the servers again. That’s not especially efficient, so I wrote a script that I run when I make changes and it automatically pushes the script to each of the servers.

Here’s the part non-hackers don’t get. In order to save myself 30 seconds of typing a few times a week, I read a 300 page book about bash. I spent probably three days in total working examples and rewriting my script. I’ll probably never save three days worth of time. But now I have a new tool in my toolbox, that I can use to automate some processes—in fact I’m going to automate the process of updating WordPress blogs when I finish this post. And that’s what can’t be taught in three months.

Injection attacks revisited.

I thought I’d share another injection attack defense that I use on my sites. You can buy my stuff from Gumroad and I have a page where I list all of the Mac titles and a page where I list all of the Windows titles. I use one php script for both and there are only two choices for the page variable, ‘Mac’ or ‘Win’. It should’t happen but I allow for no values as well.


// I get the data for the page from a database, and you need one if you use 
// mysql_real_escape_string() so it goes first.
require_once('db_my.inc');

if ( isset($_GET['page']) ) { 
    $platform  = mysql_real_escape_string($_GET['page']); 
    
    // Platform can only be Mac or Win, so make injection attacks go away
    if ( strlen($platform) > 3 ) {
        $url = $_SERVER['REQUEST_URI'];
        $ref = $_SERVER['HTTP_REFERER'];
        error_log("long string in CDs.php: URL is $url and referrer is $ref");
        header("HTTP/1.0 404 Not Found");
        die();
    }

// If there is no $platform, they probably want to buy a title that works on 
// the platform they are visiting the site with
}  else { 
    $user_agent = $_SERVER['HTTP_USER_AGENT']; 
    $platform = 'Win'; // Default to windows
    if (preg_match('/macintosh|mac os x/i', $user_agent)) {
        $platform = 'Mac';
    }
}

A Programmers Toolbox

I spend most of my time in Xcode working on iOS apps. I just finished updating them to iOS7 and thought it would be fun to log all of the different programs that I use in the next week or so.

I’ll start by backtracking a bit. When proofing one app, a blank spot appeared where a picture should be. The most likely cause of that would be a mis-named picture or one that was completely missing. The names of the pictures are read from a database so I needed to check the names in the database with the names of the pictures. The database is on my server so I could open phpMyAdmin and check the names there, but in case the problem was in the PHP script that I used to create the app database, I decided to open Firefox and use the SQLite Manager plugin to look at the file that I actually use in the app. It turns out that one of the pictures was missing. I had an extra picture in my app so the total number was correct. I swapped the picture and the sounds and the app worked correctly.

We put a frame around the drawings that show up on the screen in the apps. Most of the drawings are floating in space, so the size of the frame doesn’t matter. Sometimes the drawing comes to the edge of the frame and the size of the frame is slightly different than the size of the picture. There is a couple of pixel wide band of whitespace that is out of place. We decided to extend the drawing to get rid of the white space between the picture and the frame. Our drawings are done in Adobe Flash and exported as .png’s. We usually have hundreds of drawings in our apps, so we reduce the size of them by using ImageOptim. I processed the new drawings and added them to the game.

I had a minor issue in the app that I thought might be related to a change I had made earlier. I use Git for version control, so in Xcode I checked previous versions of the file to see if that was where the problem occurred.

Once everything was proofed and submitted to Apple for review, I opened GitX to commit any files that Xcode missed. Xcode often misses deleted files. Then I opened Terminal and ran the git push command to synchronize my copy of the apps with the copy on the server.

I use Apple’s iTunes Connect website to manage my apps and check on daily sales. I checked to make sure all of the apps were waiting for review and I hadn’t missed any uploads. App Annie lets me track revenue by product and over arbitrary time periods. I spent a couple of hours reviewing my sales and checking reviews.

Checking the App Annie website doesn’t require a lot of concentration so I decided to listen to some music. I’ve been copying some of my LPs to disk so I can listen to them on my iPod or stream them with iTunes on my AirTunes network. I have a turntable hooked up to my Mac Mini using an old Roland UA-30 USB interface. I opened Felt Tip’s Sound Studio and recorded a few LPs. Sound Studio is great for recording and cleaning up voice recordings and we use it all the time. It doesn’t have filters for cleaning pops on LPs, so I opened Audacity to get rid of the pops and noise. Audacity is a good recording tool, but its workflow is arranged around projects and doesn’t work well for cutting hundreds of sounds out of a recording session and saving them as .aiff’s. Sound Studio works well for our process. It’s also great for marking and exporting songs from an LP.

I often help other people with their websites and today I got a request to update some data in an SQL file on another persons server. I usually use phpMyAdmin to work with MySQL files, but they don’t have it installed on their server, so I needed to either work on the command line or find another way to work with the database. I can work on the command line, but I really don’t like to. Oracle now owns MySQL so I went to their website and downloaded MySQLWorkbench. It took a while to figure out how to use it but it works fine. The person giving me the data didn’t know how to get it out of his spreadsheet and into a flat file, so I opened the spreadsheet in LibreOffice and exported the worksheets as comma-delimited text. The format of the data wasn’t the same as the format in the database so I used BBEdit to clean up the data. BBEdit has a search and replace feature that uses grep and it only took a few minutes to rearrange the file into something that could be imported into MySQL. I documented that process in a previous post. Since I hadn’t used MySQLWorkbench before, I opened a database on a Digital Ocean droplet that my nephew is using for learning web development. That way if I did something really dumb to the database, it wouldn’t affect a production server. Once I got the update working properly—the handoff had some issues that needed to be fixed was ready to update the database. I always make a copy of every table before I update it and phpMyAdmin has a button to push to do that. I couldn’t find a menu item or button in MySQLWorkbench, so I duplicated my test table on the Digital Ocean server using phpMyAdmin and looked for the sql code that it used.


CREATE TABLE  `Customer1`.`values_Air_Temp_BAK` (
`id` INT( 8 ) NOT NULL AUTO_INCREMENT ,
 `datetime` DATETIME DEFAULT NULL ,
 `value` FLOAT DEFAULT NULL ,
 `source_type_id` INT( 11 ) DEFAULT NULL ,
PRIMARY KEY (  `id` ) ,
UNIQUE KEY  `datetime` (  `datetime` )
) ENGINE = MYISAM DEFAULT CHARSET = utf8;

SET SQL_MODE =  'NO_AUTO_VALUE_ON_ZERO';

INSERT INTO  `Customer1`.`values_Air_Temp_176_BAK` 
SELECT * 
FROM  `Customer1`.`values_Air_Temp_176` ;

I pasted this code into MySQLWorkbench on the production server and had my backup.

I updated the data in the backup and had the user check it for egregious errors. Once it was validated I again used the test server to get the code to rename the backup.


RENAME TABLE  `Customer1 `.`values_Air_Temp` TO  `Customer1 `.`values_Air_Temp_OLD`;
RENAME TABLE  `Customer1 `.`values_Air_Temp_BAK` TO  `Customer1 `.`values_Air_Temp`;

I had the user double check that everything looked right and I was done with that task.

By the way, this blog is hosted on my server using WordPress. I host several blogs and they need updated from time to time. I can never remember the exact steps to do it (I should write a bash script to update them) so I keep the instructions and code in a wiki on our server. Trac is good for keeping notes on procedures and processes and we use it for bug reports when we are testing the software.

I’m managing four servers now and I’ve been meaning to automate some of the process. Since I had some down time, I decided to refresh my bash skills and write some scripts. I especially wanted to automate the login process to different servers and color code the prompts so it was clear where I was. I’ve also been trying out iTerm2 as a terminal.

I just got a call from my nephew about his server. He’s been playing with PHP, CSS, and JavaScript and messed up a couple of files. I have the originals on my machine, so I opened Cyberduck and uploaded them to his server. Cyberduck is an OSX only program, so he uses Filezilla on his Ubuntu Linux machine. It works on OSX, but the Cyberduck interface is more “Mac like”. I showed him how to use the W3C validator tools to check his code for errors. It’s a lot easier to figure out why your HTML and CSS isn’t doing what you want if you don’t have any errors in it.

After I wrote the script to log me in to all the machines I use, I set up SSH authorized keys so that I don’t have to type the password each time. I’m not sure that I would do this with a laptop that I carry around, but I’m using a Mac Mini and it rarely leaves the house. I need to copy my public key to a file called authorized_keys in my .ssh directory on each machine. I could use Cyberduck, but the scp command works better.


scp ~/.ssh/RSA_KEY.pub me@192.168.102.113:/home/me/.ssh/authorized_keys

I updated my .bash_config script so that I have a function that copies my config files to all the machines I use. It uses the same scp command, except that it copies the file from my mini to all of the servers. Since I just updated all of them to use secure authorization, no passwords are required for it to work.


id=$(who am i | cut -d\  -f 1)
server='192.168.194.220'
dave='192.168.201.11'
don='192.168.102.113'
purple='purple.someserver.com'

# Update the list of servers if you add one. It is used on connect and scp functions
servers=(server dave don purple)

# Share .bash_config. Requires . ~/.bash_config in .bash_profile
share() {
    
    # This works if you want to list out each server
    # But if you add new servers, you need to remember to update this list
    # scp .bash_config ${id}@${server}:.bash_config
    # scp .bash_config ${id}@${dave}:.bash_config
    # scp .bash_config ${id}@${don}:.bash_config
    
    # This is better because the list of servers isn’t hard coded in the script 
    for serv in "${servers[@]}"; do
        echo "Connecting to $serv"
        scp .bash_config ${id}@${!serv}:.bash_config
    done
}

Every morning, I open my php_error.log file with BBEdit to see if I have any php or MySQL errors. I started getting lots of weird errors a while ago and it turns out they are MySQL injection attacks. I fixed the code and tracked the attempts for a while, but since it seems to be working now, I no longer log them.

I just took some pictures of unusual cloud formations, and posted them on a flying blog that I run. I like to use Image Capture to grab the images from the camera and then crop and resize them in Acorn. Though it’s not related to work right now, we often we often use the same process to get images for apps. Some of the members of the team use Adobe PhotoShop to fix the images, but my version doesn’t run on OSX Mavericks, so I only use it when I’m using my laptop.

I also use some apps that are not directly related to programming. I just got a couple of orders for CDs so I opened the FileMaker Pro database on my laptop to process the order. This is a really old version of FileMaker that won’t run on Mavericks. But it still works fine and I don’t need any of the newer features. We used to use FileMaker more for developing the wordlists and text for our games, but we moved most of that to the web using PHP, MySQL, and a bit of JavaScript. That way people can work on the database without having to use sneaker-net to get the correct database. One of my goals for the year is to update the database so that it runs in LibreOffice. I use Square on my iPod to process credit cards and Stripe to process cards from international sales.

Our CD burning robot is also very old and runs on a PPC Mac Mini using PTPublisher.

So that’s about it for a fairly normal week.