Category: iOS Toggle Comment Threads | Keyboard Shortcuts

These posts are syndicated from my iOS Dev Diary over at pinkstone.co.uk.

The format is slightly different with more code snippets and less explanations. I had originally designed it as a notebook in iOS Development – now you can follow along if you’re interested.

  • Jay Versluis 2:17 pm on April 14, 2014 Permalink | Reply  
    Categories: iOS, Podcast ( 214 )

    Creating a Searchable Table View in iOS 

    Xcode_iconIn this 6-part series I’ll show you how to create a searchable UITableView in an iOS App. We’ll start with a standard single view application template in Xcode, create a table view with dummy data, and finally make it searchable.

    This course demonstrates how to do this with Xcode 5.1 and iOS 7.1. We’ll also make the app compatible to for in iOS 6.

    These are the first two parts which are available for free. The rest of the course is only viewable by members of my iOS Dev Diary at pinkstone.co.uk.

    You can get the source code and follow along here:

    Enjoy!

     

     
  • Jay Versluis 4:01 pm on December 31, 2013 Permalink | Reply  
    Categories: iOS ( 214 )

    How to display a “spinning wheel” indicator in the centre of your screen 

    Screen Shot 2013-12-31 at 15.58.02Sometimes you want to tell the user that something’s happening behind the scenes and that there’s no need to panic. While your process is happening you can display a “spinning gear” in the middle of your screen.

    One way of doing this is via a UIActivityIndicatorView.

    You can create them in Interface Builder, but it’s very easy to create one and show it if and when necessary. Here’s how:

    - (UIActivityIndicatorView *)indicator {
        if (!_indicator) {
            _indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
        }
        return _indicator;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.indicator.center = self.view.center;
        [self.view addSubview:self.indicator];
    }

    This creates it in the centre of your UI, but it’s invisible until switched on like so:

    // to start spinning
    [self.indicator startAnimating];
    
    // and to stop it again
    [self.indicator stopAnimating];

    The UIActivityIndicatorView has a property that automatically hides it when stopped, so all we have to worry about is starting and stopping it when necessary.

     
  • Jay Versluis 9:00 am on December 31, 2013 Permalink | Reply  
    Categories: iOS ( 214 )

    How to load a different storyboard depending on screen size in iOS 

    As much as I appreciate the idea of Auto Layout, I don’t think it likes me very much. In turn, I don’t like Auto Layout very much. The pain and hassle it takes to make several UI elements fit well on a 4 inch screen as well as a 3.5 inch screen regularly drives me crazy. On paper it’s a great idea – but in reality not fit for prime time.

    Screen Shot 2013-12-31 at 08.56.22

    It’s not a coincidence that we can choose completely different storyboards for iPads and iPhones. Let’s take the same approach when dealing with the two different iPhone screen sizes by loading different storyboards.

    Here’s how: First, finish one version of your storyboard. Next select it and head over to File – Duplicate. Give the second one an appropriate name, then tweak your UI elements so that they look nice on the other screen size.

    Now add this to your AppDelegate.m:

    - (UIStoryboard *)grabStoryboard {
    
        UIStoryboard *storyboard;
    
        // detect the height of our screen
        int height = [UIScreen mainScreen].bounds.size.height;
    
        if (height == 480) {
            storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
            // NSLog(@"Device has a 3.5inch Display.");
        } else {
            storyboard = [UIStoryboard storyboardWithName:@"Main-4in" bundle:nil];
            // NSLog(@"Device has a 4inch Display.");
        }
    
        return storyboard;
    }

    This method returns the following UIStoryboard file:

    • Main.storyboard on 3.5inch devices
    • Main-4in.storyboard on 4inch devices

    Now we need to make sure it gets loaded appropriately. We’ll take care of it in AppDelegate.m like so:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        UIStoryboard *storyboard = [self grabStoryboard];
    
        // show the storyboard
        self.window.rootViewController = [storyboard instantiateInitialViewController];
        [self.window makeKeyAndVisible];
    
        return YES;
    }

    This overrides the default storyboard that’s declared in your project settings. You can expand the above method by checking which iOS Version the device is running, and of course returning an iPad storyboard too.

    In your face, “Auto Layout”!

     
  • Jay Versluis 6:03 am on December 31, 2013 Permalink | Reply  
    Categories: iOS ( 214 )

    How to dismiss the iOS Keyboard when the done button is pressed 

    It has puzzled many generations how to get rid of the keyboard when the user is done entering text into an iOS text field. There doesn’t seem to be an obvious action we can attach to make this happen.

    iOS Simulator Screen shot 31 Dec 2013 05.45.27

    That’s because rather than looking at the keyboard itself, we need to look at what actually brought it up in the first place: the UITextField. Even though the text field can trigger an action, we don’t want to touch that for dismissing the keyboard. All we need to do is to implement the following method from its delegate protocol:

    - (BOOL)textFieldShouldReturn:(UITextField *)textField {
        
        // done button was pressed - dismiss keyboard
        [textField resignFirstResponder];
        return YES;
    }
    

    This method is called whenever the return button is pressed. We return YES to agree, and resign the text field’s first responder status which takes the user focus away from it.

    Since this is a protocol we *should* really conform to it formally by declaring it in the header file. It appears to work without this step, but let’s pal it by the rules here:

    @interface ViewController : UIViewController <UITextFieldDelegate>
    

    Note that you need to connect your text field’s delegate in Interface Builder to the class that’s implementing the above method (i.e. self), otherwise the keyboard won’t be dismissed. To do this, control-drag from the text field to the orange square at the bottom of your view controller and select “delegate”. You can verify this in the connections inspector:

    Screen Shot 2013-12-31 at 05.55.36

     
  • Jay Versluis 5:51 pm on December 30, 2013 Permalink | Reply  
    Categories: iOS ( 214 )

    Links to the latest Social Icons 

    InBug-60px-RFacebook, Twitter & Co. change their brandings every now and again, and every time I need them for a project I keep scrambling to find the official links. Well no more – here’s a list of them all:

     
  • Jay Versluis 12:21 pm on December 30, 2013 Permalink | Reply  
    Categories: iOS ( 214 )

    How to increase your Build Number automatically every time you build your Xcode Project 

    Xcode includes something rather magical called the Apple Generic Versioning Tool. With this tool you can increase your Build Number automatically every time you hit “Build and Run” in Xcode.

    Here’s how you can add it to your project. I’m using Xcode 5.1 here with a new Single View iOS project. But this will work just fine in other versions of Xcode.

    By default, Version and Build are set to 1.0 (in your app target, under the General tab). We want to leave Version alone and only increase Build.

    Screen Shot 2013-12-30 at 12.05.06

    Head over to the Build Settings tab and find the “Versioning” section. It’s easiest to just search for it. In here, set the Current Project Version field to your initial build – let’s say 1 for this example.

    Screen Shot 2013-12-30 at 12.10.10

    Now select the Build Phases tab. Click on the little plus icon in the top left corner and select New Run Script Build Phase. This will allow us to execute a small script every time we build.

    Screen Shot 2013-12-30 at 12.11.39

    Open the little triangle next to Run Script and underneath the Shell field, add this bit of code. You can even add multiple lines, it’s like a little text editor.

    "${DEVELOPER_BIN_DIR}/agvtool" next-version -all
    

    Here’s what it should look like:

    Screen Shot 2013-12-30 at 12.15.03

    And that’s it! Hit CMD+B a few times and head back to the General tab to see your Build Number magically increased. You can now retrieve this value from you main Bundle (explained in my previous article).

    Kudos to nekno who was kind enough to share this knowledge on Stackoverflow:

     
  • Jay Versluis 11:52 am on December 30, 2013 Permalink | Reply  
    Categories: iOS ( 214 )

    How to read you App Version and Build from the Main Bundle 

    The required Version and Build numbers you add to Xcode make it into your app’s Main Bundle. You can retrieve those values from the Main Bundle and use them in your app.

    Here’s how:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        // set version and build fields from bundle
        NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
        NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
        
        // display in your own labels
        self.versionLabel.text = version;
        self.buildLabel.text = build;
    
    }
    

    iTunes Connect reads both of these. Your “new version” is what’s displayed in the App Store, while the build is a more arbitrary thing you can set yourself.

    Note that both values are floats, and that you need to increase them with every version. If you decrease either of them, iTunes Connect will complain next time you submit a build.

     
  • Jay Versluis 10:12 am on December 30, 2013 Permalink | Reply  
    Categories: iOS ( 214 )

    What are the button indexes in a three-button UIAlertView 

    iOS Simulator Screen shot 30 Dec 2013 09.50.43

    The cancel button is always index 0, and all other buttons in the array start at index 1 counting up.

    For completion, here’s how to create it:

    - (IBAction)showAlert:(id)sender {
        
        // create an alert view with three buttons
        UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"Three Button Alert" message:@"This is an alert view with more than two buttons. Will it work?" delegate:self cancelButtonTitle:@"No Way (0)" otherButtonTitles:@"Perhaps (1)", @"Definitely! (2)", nil];
        [alertView show];
    }
    

    And here’s how to react to it:

    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
        
        switch (buttonIndex) {
            case 0:
                NSLog(@"That was button at index 0");
                break;
                
                case 1:
                NSLog(@"That was button at index 1");
                break;
                
                case 2:
                NSLog(@"That was button at index 2");
                break;
                
                case 3:
                NSLog(@"We don't have a fourth button");
                break;
                
            default:
                break;
        }
    }
    

    This is a delegate method, so the reacting class needs to conform to the UIAlertView Protocol like so:

    @interface ViewController : UIViewController <UIAlertViewDelegate>
    
     
  • Jay Versluis 10:05 am on December 30, 2013 Permalink | Reply  
    Categories: iOS ( 214 )

    How to restore your single In-App Purchase in iOS 

    This is an addition to my previous article. To allow uses to restore their In-App Purchases you can expand on the previous article and include the following method in your Shop class. This needs to be public so it can be called from your main class:

    - (BOOL)restoreThePurchase {
        
        // verify/refresh receipt here (even though Apple doesn't say how)
        
        // restore the purchase
        [[SKPaymentQueue defaultQueue]restoreCompletedTransactions];
        
        return YES;
    }
    

    Much like submitting a payment, this now submits a “restore request” to the app store, which in turn will get back to us via the observer delegate. Here’s the implementation from before (still in AppDelegate.m), with the addition of a fleshed out reaction to the restore:

    #pragma mark - StoreKit Observer
    
    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
        
        for (SKPaymentTransaction *transaction in transactions) {
            switch (transaction.transactionState) {
                case SKPaymentTransactionStatePurchased: {
                    // user has purchased
                    [self saveTransactionReceipt:transaction];
                    [self unlockFullVersion];
                    // download content here if necessary
                    [[SKPaymentQueue defaultQueue]finishTransaction:transaction];
                    break;
                }
                    
                case SKPaymentTransactionStateFailed: {
                    // transaction didn't work
                    [self displayAlertViewWithMessage:@"There was a problem with your purchase. Please try again later."];
                    break;
                }
                    
                case SKPaymentTransactionStateRestored: {
                    // purchase has been restored
                    [self displayAlertViewWithMessage:@"Successfully restored your purchase"];
                    [[SKPaymentQueue defaultQueue]finishTransaction:transaction];
                    break;
                }
                    
                    
                case SKPaymentTransactionStatePurchasing: {
                    // currently purchasing
                    break;
                }
                    
                default:
                    break;
            }
        }
    }
    

    We let the user know about a successful restore (or failure) via an alert view. Since I’m calling this multiple times it was easier to create a method for this:

    - (void)displayAlertViewWithMessage:(NSString *)message {
        
        UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:nil message:message delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alertView show];
    }
    

    Note that you should validate the purchase before restoring it. The Apple documentation goes on a bit about receipt validation without describing a way to actually do it.

     
  • Jay Versluis 10:05 am on December 30, 2013 Permalink | Reply  
    Categories: iOS ( 214 )

    How to restore your single In-App Purchase in iOS 

    This is an addition to my previous article. To allow uses to restore their In-App Purchases you can expand on the previous article and include the following method in your Shop class. This needs to be public so it can be called from your main class:

    - (BOOL)restoreThePurchase {
        
        // verify/refresh receipt here (even though Apple doesn't say how)
        
        // restore the purchase
        [[SKPaymentQueue defaultQueue]restoreCompletedTransactions];
        
        return YES;
    }
    

    Much like submitting a payment, this now submits a “restore request” to the app store, which in turn will get back to us via the observer delegate. Here’s the implementation from before (still in AppDelegate.m), with the addition of a fleshed out reaction to the restore:

    #pragma mark - StoreKit Observer
    
    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
        
        for (SKPaymentTransaction *transaction in transactions) {
            switch (transaction.transactionState) {
                case SKPaymentTransactionStatePurchased: {
                    // user has purchased
                    [self saveTransactionReceipt:transaction];
                    [self unlockFullVersion];
                    // download content here if necessary
                    [[SKPaymentQueue defaultQueue]finishTransaction:transaction];
                    break;
                }
                    
                case SKPaymentTransactionStateFailed: {
                    // transaction didn't work
                    [self displayAlertViewWithMessage:@"There was a problem with your purchase. Please try again later."];
                    break;
                }
                    
                case SKPaymentTransactionStateRestored: {
                    // purchase has been restored
                    [self displayAlertViewWithMessage:@"Successfully restored your purchase"];
                    [[SKPaymentQueue defaultQueue]finishTransaction:transaction];
                    break;
                }
                    
                    
                case SKPaymentTransactionStatePurchasing: {
                    // currently purchasing
                    break;
                }
                    
                default:
                    break;
            }
        }
    }
    

    We let the user know about a successful restore (or failure) via an alert view. Since I’m calling this multiple times it was easier to create a method for this:

    - (void)displayAlertViewWithMessage:(NSString *)message {
        
        UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:nil message:message delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alertView show];
    }
    

    Note that you should validate the purchase before restoring it. The Apple documentation goes on a bit about receipt validation without describing a way to actually do it.

     
c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
shift + esc
cancel
Google+