It's not worth doing unless it's worth overdoing

Tag: iOS Development Page 1 of 2

Running XCode projects on a device without a developer account in XCode 7

One of the announcements at WWDC 2015 was that developers would be able to test apps on devices without a paid Apple developer account in XCode 7. I was just about to drop $99 on a developer account so I could test a personal project on my devices. So, I decided to dig in and figure out how to do this.

IMPORTANT NOTES BEFORE YOU START:

  • You can’t do this if you have any developer accounts in XCode. This makes sense, really. If you have a developer account, then you can already test your projects on a device and you don’t need to do this.
  • If you follow the steps below, your accounts will change across ALL versions of XCode on your Mac. So, if you need to keep your developer accounts in XCode 6, do NOT follow these steps.

Now that you’ve been properly warned about the ramifications, let’s get started…

Step 1: Download XCode 7 beta. Please note that XCode  7 beta is still pretty rough and you may need to go back to XCode 6 for certain things.

Step 2: Remove any developer accounts in Xcode. Open XCode Preferences and go to the accounts tab. You can’t have any accounts in here that are connected to any Apple Developer accounts. This means that you can’t have a paid developer account, but it also means that your Apple ID can’t be part of any free developer accounts (like Safari development). If there are any developer accounts in here, you need to delete them. The easiest thing to do is simply delete ALL of the accounts listed in here, then add them back in later as needed.

Notice how the Apple ID I’m using says “Free” under the iOS and Mac headings:
xcode_acct_prefs

Step 3: Open an Xcode project and connect your device to your Mac.

Step 4: Check your project build settings. Choose your project target in your XCode project settings and go to the Build Settings tab. Make sure that your Code Signing is set to iOS Developer and your Provisioning Profile is set to automatic.
xcode_provisioning

Step 5:  set target device in XCode as shown:
xcode_set_device_target

Step 6: Run the app from Xcode

Step 7: Choose the account you want to use. If you deleted all of your accounts in step 2, you will be prompted to sign in with an Apple ID. Again, you must use an Apple ID that is not tied to a developer account.

Step 8: Apple may prompt you to fix issues with your certificate or provisioning profile. If this happens, click the “fix issue” button and let Xcode handle it for you.

If this process fails for any reason, here are some other things you can do:

  • Open Keychain Access on your Mac and delete any development certificates in here. I had some old, expired certificates in my keychain and deleting them cleared up some problems.
  • Go back to XCode preferences and check that the Apple ID you used is not connected to any developer accounts
  • Worst case scenario: remove all accounts from Xcode preferences and create a brand new Apple ID with a new email address. This should force XCode to use a free account.

Just like any normal Xcode provisioning, it sometimes takes a little fiddling around to get it working. If you find any other tips, leave them in the comments.

Good Luck!

iOS SpriteKit Memory Leaks

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.

SOLVED: Attributed Placeholder UITextField Bug in iOS7

I was creating some custom UI components for an iOS project the other day and I ran into a weird bug. I was subclassing UITextField so I could auto-style all the UITextViews throughout the app (Yes, I know that an iOS purist would tell me to create a UITextField category because overriding UI components is considered “bad,” but I don’t care). I was trying to change the color of the placeholder text in a UITextField using this code:

self.attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.placeholder attributes:@{ NSForegroundColorAttributeName : [UIColor whiteColor] }];

This was working fine for a while, then it randomly started throwing compiler errors. Sometimes, it would compile. Other times, it would not. I commented out the code and moved on, but it was bugging me. After Googling around a little, I found a suggestion to add a check for iOS6, since attributed placeholder text only works in iOS7:

if ([self respondsToSelector:@selector(setAttributedPlaceholder:)]) {
    self.attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.placeholder attributes:@{ NSForegroundColorAttributeName : [UIColor whiteColor] }];
} else {
    NSLog(@"Cannot set placeholder text's color, because deployment target is earlier than iOS 6.0");
    // TODO: Add fall-back code to set placeholder color.
}

My project target was iOS7 only, so this really shouldn’t have mattered, but it did. After adding the iOS6 check, the compiler errors stopped. I’m sure there is a logical explanation, like I’m allowing an old ARM architecture in my build settings or something.

The really strange part is that the code works perfectly – the placeholder text color gets set correctly every time in my iOS7 app. It just needs the version check for the compiler to play nice.

Image naming conventions for iOS and Android apps

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.

Page 1 of 2

Powered by WordPress & Theme by Anders Norén