Archive

Archive for the ‘Mobile Apps’ Category

Kenny Login is Available Now!

February 12th, 2015

Kenny Login version 1.0.0 releasedAfter months of procrastination and delays, I’m proud to officially release Kenny Login – a fully responsive HTML5 theme for your WordPress Login page. Version 1.0.0 is available now as a free WordPress plugin. Simply install the plugin and activate it through your admin panel. Blam! Kenny Loggins all up in your login page! Click here to get the lowdown.

Log in to the Danger Zone!

iOS SpriteKit Memory Leaks

November 4th, 2014

I was building a SpriteKit game at work the other day and ran into a couple of annoying issues that were causing memory leaks in my app. The first one was created when I set up the GameScene (an SKScene subclass) in my view controller:

- (void)viewDidLoad {
    [super viewDidLoad];
    SKView * skView = (SKView *)self.view;
    
    // Create and present the scene.
    GameScene * scene = [GameScene sceneWithSize:skView.bounds.size];
    scene.scaleMode = SKSceneScaleModeAspectFill;
    [skView presentScene:scene];
}

There’s one big problem with the code above: the view bounds haven’t been set in viewDidLoad. So, the GameScene size will probably be wrong. No problem, we’ll just move it to where we know the view bounds have been set:

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    SKView * skView = (SKView *)self.view;
    
    // Create and present the scene.
    GameScene * scene = [GameScene sceneWithSize:skView.bounds.size];
    scene.scaleMode = SKSceneScaleModeAspectFill;
    [skView presentScene:scene];
}

…except for one thing. Now, the GameScene gets recreated every time you come to the ViewController. If you are doing everything inside SpriteKit, then this isn’t an issue, but my app had several ViewControllers. Each time I left the GameViewController and returned, it would run this code again, creating a new GameScene each time. The old scenes were not being destroyed, so this created a large memory leak on an iPad Mini with iOS7 (about 20% CPU increase each time the GameScene started) that would crash the app after a few games.

The solution is simple:

- (void) viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    SKView * skView = (SKView *)self.view;
    [skView presentScene:nil]; //remove everything from memory
}

This ensures that the GameScene is destroyed when you leave the GameViewController.

This solved most of my problems, but I still had a small memory leak. It wasn’t a big deal and I was tempted not to worry about it, but this game was going to be used in a tradeshow booth, which meant that it would be running for hours at a time. Under those conditions, even a small memory leak could be a big problem.

I was able to isolate the remaining issue to the fact that I set a protocol on my GameScene:

@protocol GameSceneDelegate 

@required
- (void) triggerGameOver;
@end

The parent GameViewController implemented the delegate to display a “Game Over” UIView. Even though I was destroying the GameScene, the delegate reference was still not being destroyed. It seems that SpriteKit classes are not reference counted in the same way as standard iOS classes (?). So, I replaced the protocol/delegate with an NSNotification that was sent by my SKScene and picked up by the parent ViewController. Decoupling the 2 classes fixed the memory leak and everything worked as expected.

Oddly, the memory leak only seemed to be an issue in iOS7. iOS8 worked fine. Maybe it was a bug that’s been fixed? As always, I hope maybe this helps prevent a bit of frustration for someone else.

iOS: Limiting the character count on UITextField

August 5th, 2014

For some reason, I couldn’t find this anywhere else on the web, so here it is. To set a maximum character count on a UITextField, simply implement this UITextFieldDelegate method:

-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    int maxLength = 64;
    //you only need this check if you have more than one textfield on the view:
    if (textField == self.nameTextField) {
        if (textField.text.length - range.length + string.length > maxLength) {
            if (string.length > 1) { // only show popup if cut-and-pasting:
                NSString *message = [NSString stringWithFormat:@"That name is too long. Keep it under %d characters.", maxLength];
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Oops!"
                                                                message:message
                                                               delegate:nil
                                                      cancelButtonTitle:@"OK"
                                                      otherButtonTitles:nil];
                [alert show];
            }
            return NO;
        }
    }
    return YES;
}

Remember, this is a delegate method, so you have to specify that your UIViewController implements it:

@interface SomeViewController () <UITextFieldDelegate>

…and you have to set the delegate for the textfield:

self.nameTextField.delegate = self;

This can also be done for a UITextView with its delegate method:

-(BOOL) textView:(UITextField *)textView shouldChangeTextInRange:(NSRange)range replacementString:(NSString *)text {
    int maxLength = 64;
    //you only need this check if you have more than one textview on the view:
    if (textView == self.descriptionTextView) {
        if (textView.text.length - range.length + text.length > maxLength) {
            if (text.length > 1) { // only show popup if cut-and-pasting:
                NSString *message = [NSString stringWithFormat:@"That description is too long. Keep it under %d characters.", maxLength];
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Oops!"
                                                                message:message
                                                               delegate:nil
                                                      cancelButtonTitle:@"OK"
                                                      otherButtonTitles:nil];
                [alert show];
            }
            return NO;
        }
    }
    return YES;
}

Image naming conventions for iOS and Android apps

May 26th, 2014

Having a basic naming convention for the images in your mobile app can make your asset library a lot easier to manage. After working on some iOS and Android apps, I’ve come up with a method I think works pretty well. The basic rules are pretty simple:

  1. All image names should use only lowercase letters, numbers and underscores, like this:
    some_image_name.png
    another_one.png

    Do not use uppercase letters or special characters (Android doesn’t allow them anyway). The obvious exception here is that iOS retina display images will be have “@2x” appended to the name:

    basic_icon.png
    basic_icon@2x.png
  2. Do not put images in subfolders. If you use iOS xcasset libraries, use only ONE xcasset library for images. There are several reasons for this:
    • In Android, subfolders aren’t allowed for images
    • All of your images can be found in a single location, so nothing is hiding
    • It prevents accidentally giving the same name to 2 different images, which can cause all sorts of problems.
  3. Name all images by category like this:
    category_subcategory_imagename.png

    or you might think of it like this:

    folder_subfolder_imagename.png

    You still get the organization of folders without needing to use folders (which isn’t allowed in Android anyway). The other benefit is that images are grouped together alphabetically:

    home_header.png
    home_next_arrow.png
    home_prev_arrow.png
    login_label_user.png

    which is especially handy when using XCode’s Interface Builder for your layouts in iOS. The dropdown menu for images can get pretty long, so having them organized alphabetically by section makes it a lot easier to deal with.
    I tend to make the first word in the image name match the name of the app section (home, login). In cases where I need an image in multiple places, I create general category names like this:

    button_back.png
    button_next.png
    icon_check.png
    icon_trash.png

    Note that this also prevents creating multiple versions of the same basic icons. When I need an icon, it’s easy for me to see whether or not it already exists in the assets.

  4. Create a category for images that you want to delete later. I often use screenshots of design layouts to help me layout my views in Android Studio or XCode’s Interface Builder. I name them:
    comp_home.png
    comp_login.png
    comp_registration_1.png
    comp_registration_2.png

    Later, when I’m packaging my app for release, I know that I can trash anything in the “comp” category and it won’t break the app (well, it SHOULDN’T break the app).

  5. Give placeholder assets their proper, final names and correct dimensions (when possible), but make the image obviously wrong. Some people like to add red “FPO” lettering to these images. I personally like to add magenta backgrounds to image assets that I need to replace. Either way, it’s a glaring visual reminder that says “FIX ME PLEASE!!!” Giving a placeholder image the correct name and dimensions makes it easy to drop in a new file to replace the placeholder without combing through the files to rename or resize anything.

Of course, the key to this system is making sure that all of the other developers on the project are also using these rules. If everyone does it, managing your assets can be a lot less painful.

Top