Monthly Archives: September 2013

AVSpeechSynthesizer – iOS Text to Speech in iOS 7

texttospeechxcode

Apple added lots of new useful API’s in iOS 7, I am going to speak about one quickly today, AVSpeechSynthesizer.

In short, this is Text to Speech, a really simple way to have iOS read a piece of text out loud. There are a number of use cases for this, navigation, directions, visual impairments, introductions etc.

This framework is very easy to implement, the source code for this example is available on my GitHub .

Firstly you will need to include 2 Frameworks in your project (AudioToolbox.framework and AVFoundation.framework)

avfoundation

 

The simplest implementation of Text To Speech is only a few lines of code, in this example you could test this by adding the following code to your ViewDidLoad method, make sure that you have imported the AVFramework into your header file (#import <AVFoundation/AVFoundation.h>).

AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc]init];
    AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:@"Some random text that you want to be spoken"];
    [utterance setRate:1.1f];
    [synthesizer speakUtterance:utterance];

Easy isn’t it? :)

Find the full source code on GitHub , this will show you how to read from a text-box and also to increase and decrease the speed at which the text is spoken.

AVSpeechSynthesizer

MKMapView – Adding Pins to Map and Showing Annotations

JFMapViewExample

I am currently in the process of writing a revised version of my iOS application (Location+), the new version is going to be totally rewritten using the new toolset, Location+ was built in the days of release/retain and xib’s instead of storyboards so it was time for a revamp.

Firstly, the source code for this tutorial can be found at the following address: https://github.com/jfield44/JFMapViewExample

An important feature of any mapping application is the ability to the let us user interact with points on the map, for example drop a pin to find the address at that point. In iOS the primary way of doing this is to add an ‘Pin’ to the map. I am going to be recreating this functionality inside my new app shortly so I thought I would put together a simple tutorial that you can follow along with if you are new to iOS or MapKit.

This tutorial will cover:

  • Adding a MapView to your application
  • Adding a Pin to the map at the user’s touched location
  • Adding a Pin at the capital city of each country in the world (We will parse a JSON file for this)
  • Showing a ‘Callout Bubble’ containing the name of the country and its capital city

N.b: This tutorial will be written using xCode 5 and iOS 7

Firstly, create a new Project in xCode, for the purposes of this tutorial choose a Single View ApplicationScreen Shot 2013-09-14 at 09.19.52

 

Click next and name the project whatever you want to name it, also set an organisation name and company identifier, these will probably just be your name.

Screen Shot 2013-09-14 at 09.22.27

 

Click next and then save Project to a directory of your choice, personally I save mine to Dropbox.

Once you have saved the Project you should see a screen like this.

Screen Shot 2013-09-14 at 09.25.17

 

This is the main configuration page for the Project, we will be using the MapKit framework today so the next step is to add that framework to the Project, to do this we goto the ‘Build Phases’ section at the top of the screen. One the Build Phases screen, click ‘Link Binary with Libraries’ and then press the + icon. Then add the MapKit.framework to the Project by selecting it and pressing Add.

Screen Shot 2013-09-14 at 09.27.46

 

Now that we have the MapKit framework added, we can start creating our MapView that will act as the Canvas for us to add our Pins. In the left hand column of our Project click on the file ViewController.h , or if you have added a class prefix then (PREFIX)ViewController.h.

Objective-C frequently uses the Delegation Design Pattern, you can read more about this here , we need to implement a number of MKMapView delegate functions in order for us to achieve the functionality that we are looking for. In addition to this, you may wish you implement more MKMapView Delegate functions for example responding to the Map Starting to Load. For us to become an MKMapView Delegate we need to the following code into ViewController.h .

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface JFViewController : UIViewController <MKMapViewDelegate>

@property (weak, nonatomic) IBOutlet MKMapView *mapView;

- (IBAction)addCitiesToMap:(id)sender;

@end

The above code tells the MapView that we will confirm to the delegate protocol, we have also created an outlet view to the Map, you should connect this up by dragging a MapView object onto your Storyboard View. We have also created an IBAction which will allow us to add cities to the map later on. Add a Navigation Bar and Bar Button Item, after that you should link up the AddCitiesToMap function to the Bar Button Item.

Screen Shot 2013-09-14 at 15.37.06

 

Now that we have our MapView hooked up to our code, we need to explicitly tell the MapView that our ViewController will be the delegate. Add the following code to the ViewDidLoad method method inside of ViewController.m (.m not.h , we are now looking at the implementation).

#import "JFViewController.h"

@interface JFViewController ()

@end

@implementation JFViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.mapView setDelegate:self];
}

- (IBAction)addCitiesToMap:(id)sender{
    //Lets fill this in later
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

The next step for us is to add a Gesture Recogniser to the MapView, this will detect when the user touches the map and allow us to respond based on the nature of the interaction and the amount of time the map was touched for. To do this, create another method called AddGestureRecogniserToMapView in ViewController.h and then copy the code below into your ViewController.m. Your ViewController.m should now look like this.

//
//  JFViewController.m
//  JFMapViewExample
//
//  Created by Jonathan Field on 14/09/2013.
//  Copyright (c) 2013 Jonathan Field. All rights reserved.
//

#import "JFViewController.h"

@interface JFViewController ()

@end

@implementation JFViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.mapView setDelegate:self];
    [self addGestureRecogniserToMapView];
}

- (void)addGestureRecogniserToMapView{
    
    UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
                                          initWithTarget:self action:@selector(addPinToMap:)];
    lpgr.minimumPressDuration = 0.5; //
    [self.mapView addGestureRecognizer:lpgr];
    
}

- (void)addPinToMap:(UIGestureRecognizer *)gestureRecognizer
{
    
    if (gestureRecognizer.state != UIGestureRecognizerStateBegan)
        return;
    
    CGPoint touchPoint = [gestureRecognizer locationInView:self.mapView];
    CLLocationCoordinate2D touchMapCoordinate =
    [self.mapView convertPoint:touchPoint toCoordinateFromView:self.mapView];
    
    JFMapAnnotation *toAdd = [[JFMapAnnotation alloc]init];
    
    toAdd.coordinate = touchMapCoordinate;
    toAdd.subtitle = @"Subtitle";
    toAdd.title = @"Title";
    
    [self.mapView addAnnotation:toAdd];
    
}

- (IBAction)addCitiesToMap:(id)sender{
    //Lets fill this in later
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

If you run the simulator now, you will see that the MapView appears and you can also touch and hold the Map for a short while and a Pin will appear. This functionality is contained in our addPinToMap function. The Gesture Recogniser determines that a touch has been made for more than 0.5 seconds and then triggers a call to the addPinToMap function, this then calculates the coordinates for which the pin should be added based on the Touch Coordinates of the device. In order for us to add the Pin to the map, we had to create a new subclass of NSObject that confirms to the <MKAnnotation> protocol, the code for this is as follows.

New Class JFMapAnnotation.h

//
//  JFMapAnnotation.h
//  JFMapViewExample
//
//  Created by Jonathan Field on 14/09/2013.
//  Copyright (c) 2013 Jonathan Field. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface JFMapAnnotation : NSObject <MKAnnotation>{
    
    NSString *title;
    NSString *subtitle;
    NSString *note;
    CLLocationCoordinate2D coordinate;
}

@property (nonatomic, copy) NSString * title;
@property (nonatomic, copy) NSString * subtitle;
@property (nonatomic, assign)CLLocationCoordinate2D coordinate;

@end

New Class JFMapAnnotation.m

//
//  JFMapAnnotation.m
//  JFMapViewExample
//
//  Created by Jonathan Field on 14/09/2013.
//  Copyright (c) 2013 Jonathan Field. All rights reserved.
//

#import "JFMapAnnotation.h"

@implementation JFMapAnnotation

@synthesize title;
@synthesize subtitle;
@synthesize coordinate;

@end

Our next step will be to create the functionality in order for our application to add pin’s at capital cities across the world, we have a .json file that contains this data stored in the following format. We could have used a plist file but it is good practise to use a cross platform file format and it is the typical response that we would get if we were working with a web api.

{
    "Country":"Afghanistan",
    "Capital":"Kabul",
    "Latitude":34.52,
    "Longitude":69.18
  }

To Parse the JSON file and convert the raw JSON objects into Objective-C Foundation Objects, we will create another function that will be called from our addCitiesToMap: function. In addition to this, we will modify our addCitiesToMap: function to use both the Main and Background threads. While this is not necessary for parsing this small amount of data, it is good practise in order to prevent the GUI from being locked when doing lots of work on the Main thread.

/*
 On the background thread, retrieve the Array of Annotations from the JSON from the next function.
 On the main thread, add the annotations to the map.
 */
- (IBAction)addCitiesToMap:(id)sender{
    
    __block NSArray *annoations;
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        annoations = [self parseJSONCities];
        
        dispatch_async(dispatch_get_main_queue(), ^(void) {
            
            [self.mapView addAnnotations:annoations];
            
        });
    });
    
}

/*
 Convert raw JSON to Objective-C Foundation Objects
 Iterate over each returned object and create a JFMapAnnotationObject from it
 Add each new Annotation to an Array and then return it.
 */
- (NSMutableArray *)parseJSONCities{
    
    NSMutableArray *retval = [[NSMutableArray alloc]init];
    NSString *jsonPath = [[NSBundle mainBundle] pathForResource:@"capitals"
                                                         ofType:@"json"];
    NSData *data = [NSData dataWithContentsOfFile:jsonPath];
    NSError *error = nil;
    NSArray *json = [NSJSONSerialization JSONObjectWithData:data
                                              options:kNilOptions
                                                error:&error];
    
    for (JFMapAnnotation *record in json) {
        
        JFMapAnnotation *temp = [[JFMapAnnotation alloc]init];
        [temp setTitle:[record valueForKey:@"Capital"]];
        [temp setSubtitle:[record valueForKey:@"Country"]];
        [temp setCoordinate:CLLocationCoordinate2DMake([[record valueForKey:@"Latitude"]floatValue], [[record valueForKey:@"Longitude"]floatValue])];
        [retval addObject:temp];
        
    }
    
    return retval;
}

Once you have implemented this, make sure to hook up your IBAction addCitiesToMap: to the Bar Button Item or any other button on your Storyboard. When you press that button, you should now see that a pin has been added at every capital city.

JFMapViewExampleIphone

I hope this serves a a simple introduction to MapKit and also reading and parsing JSON files.

The full project can be downloaded from https://github.com/jfield44/JFMapViewExample

To request more tutorials or ask questions visit http://jonathanfield.me

 

1Password

1Password by AgileBits

In this day and age we are all storing more and more important information online, everything from banking to social media, it all has a value. For that reason it is imperative that you secure access to this information as well as you can. There are many different ways to do this such as two factor authentication but one good practise that everyone should adopt is using ‘strong’ passwords.

A strong password is created by increasing the length of a password, not using a dictionary word and ensuring that many different letters, numbers and symbols are used.

Or to use the Wikipedia definition of Password Strength

“Password strength is a measure of the effectiveness of a password in resisting guessing and brute-force attacks. In its usual form, it estimates how many trials an attacker who does not have direct access to the password would need, on average, to guess it correctly. The strength of a password is a function of length, complexity, and unpredictability.”

Obviously creating a password that is 30+ characters long and contains various symbols and signs is very difficult to remember, especially when you consider that the best practise is to use a 50 character or the maximum permitted length password and also to use a new strong password for each site that you have an account with.

However, there is solution, a ‘Password Manager’ that will securely store your passwords and details, I will talk about my ‘Password Manager’ of choice, 1Password but there are a number of others available.

1Password allows you to generate a super secure password and store it for future use, you do not need to manually copy and paste the password each time you want to access a new page, you can simply use the 1Password browser plugin

1Password Secure Password Generation

1Password Secure Password Generation

1Password consists of a desktop application (Mac + PC) and a browser plugin, as you can see from the screenshot above, we have generated a super strong password. If we run the password through a website that checks for password strength you will see the results (n.b never put your real generate password into anything other that the site’s login page). In this example we will use the generated strong password Zh#h;(Lf@&yZ^#%;L9u>w$MfJ[z[,A3XV}=8,#X%ZwEF?XUQcH . As you can see, this is not something that people will be able to remember from looking over your shoulder and the complexity of the password makes it very difficult for people to crack it with standard hardware.

How Strong is your password

1Password also allows you to store ‘Secure Notes’ such as answers to security questions, top tip here is to make a note of what the security question is and then use another randomly generated string as the answer so that if someone has researched you, they will still not be able to access your account to reset the password etc. I find the ‘Secure Notes’ feature which is essentially a secure text editor very useful for storing the Bank Details that ask what is the 3rd letter of the second word.

You will probably be saying right so I have all of these long passwords, I can get 1Password web browser plugin to autocomplete the login details for me on my PC, but I also have mobile devices that I need to login with. Well the solution is the 1Password App for iOS and Android. The app when combined with the powerful syncing features (I recommend Dropbox sync) will ensure that your password data is always available to you on whatever device you have with you.

1Password is available here , it is  £32 / $49.99  but it does come with a 30 day free trial. It is an investment but it is well worth the additional peace of mind knowing that your passwords are strong and stored securely. I highly recommend that you pick up a copy.