- Add the following line to the class you want to use text to speech in "import AVFoundation"
- Create a speech synthesizer: let speechSynthesizer = AVSpeechSynthesizer()
- Create a speech utterance: let speechUtterance = AVSpeechUtterance(string: "Hello world!")
- Apply your desired properties to the speech utterance, e.g:
- speechUtterance.rate : how fast or slow the string will be spoken, acceptable values are between 0.0 and 1.0
- speechUtterance.volume : how loudly the string will be spoken, acceptable values are between 0.0 and 1.0
- More properties can be found on the AVSpeechUtterance reference page.
- Use the speech synthesizer to speak the utterance: speechSynthesizer.speakUtterance(speechUtterance)
Friday, 11 December 2015
Swift - Text to speech
Swift - Turn off autocorrect/spelling correction on text feld
- Add a UITextField to your storyboard
- Add an IBOutlet that references the textfield in your view controller
- Set the autocorrection type off in the view controller: _wordTextField.autocorrectionType = UITextAutocorrectionType.No
Thursday, 10 December 2015
Swift - Table views in a view controller
UITableView is a common way of displaying lists of information, this article will take you through the basics of setting one up.
You will then want to select the tableview again, hold down control and drag up to this button:
And choose to make your view controller both the datasource and delegate.
Storyboard
Add a UITable view to your view controller in the storyboard, then select the button which looks like a venn diagram in the top right corner of your screen to display your code alongside the storyboard. Select the UITableView and hold down control while clicking and dragging towards the code, this will allow you to insert an IBOutlet into your view controller which can be used to reference the table view:
You will then want to select the tableview again, hold down control and drag up to this button:
And choose to make your view controller both the datasource and delegate.
View Controller
The next step is implementing UITableViewDataSource and UITableViewDelegate in your view controller:
class SpellingListsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet var _spellingModesTableView: UITableView!
var modes : NSMutableArray!
...
// number of rows that will be in the table
func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
if (modes == nil) {
return 0
}
return modes.count
}
// deleting from core data and removing from table view
// on delete action on cell
func tableView(tableView: UITableView, commitEditingStyle
editingStyle: UITableViewCellEditingStyle,
forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
var appDelegate : AppDelegate = UIApplication
.sharedApplication().delegate as! AppDelegate
var context : NSManagedObjectContext =
appDelegate.managedObjectContext!
context.deleteObject(modes[indexPath.row]
as! NSManagedObject)
context.save(nil)
modes.removeObjectAtIndex(indexPath.row)
_spellingModesTableView.reloadData()
}
}
//should use dequeueReusableCellWithIdentifier
func tableView(tableView: UITableView, cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell(
style: UITableViewCellStyle.Subtitle,
reuseIdentifier: "mode")
var mode = modes[indexPath.row] as! NSManagedObject
cell.textLabel?.text = mode.valueForKey("name") as? String
cell.detailTextLabel?.text = mode.valueForKey("description")
as? String
cell.accessoryType =
UITableViewCellAccessoryType.DisclosureIndicator
return cell
}
// do something with the selected row, e.g show detail
func tableView(tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath) {
...
}
}
Swift - Switching Views Programmatically
Sometimes you may want to do custom navigation, in this case you will want to know how to switch views programmatically. To do this you need to follow the following steps:
- Setup the view controller code, and set it as the view controller class against a view controller in your storyboard

- Set the storyboard id, this is how you will load the view from your storyboard

- Use the following code to change views (code styling is due to lack of space):
... let vc = self.storyboard! .instantiateViewControllerWithIdentifier ("SpellingListsViewController") as! SpellingListsViewController self.presentViewController(vc, animated: true, completion: nil) ...
Wednesday, 9 December 2015
Swift casting - as! or as?
Today, I'm going to explain the different between "as!" and "as?"
"as!" is appropriate where you know that the underlying type of the object you are trying to cast matches what you are casting to. It will throw an error if it is not the type it expects which may help you avoid overlooking a setup issue or something similar. Whereas "as?" will try to cast it to the type, but if it is not the type it expected then it will return nil. Here's a quick code example:
"as!" is appropriate where you know that the underlying type of the object you are trying to cast matches what you are casting to. It will throw an error if it is not the type it expects which may help you avoid overlooking a setup issue or something similar. Whereas "as?" will try to cast it to the type, but if it is not the type it expected then it will return nil. Here's a quick code example:
// returns an object of type UIImageView? // this can be useful in if statements, for if cast is not nil // do something with the variable let optionalImageView = touches.first?.view! as? UIImageView // returns an object of type UIImageView // will throw an error if the object is not the expected type let optionalImageView = touches.first?.view! as! UIImageView
Monday, 7 December 2015
iOS - Using a preloaded database
Hi all, this tutorial will be on using a preloaded database in Swift. There are several reasons you may want to do this, one being that you may have data that won't change that you want to be available to the user. You could load this up at runtime, but that could be slow if you have a lot of records to import. This method ensures that the application runs quickly, upon being opened for the first time... And let's be honest, the first impression counts!
Creating the database
- Get the data you want into some format you can parse, e.g. XML, JSON or CSV.
- Create your project, ensure that you select to use Core Data.
- Copy your data file into your project
- Setup your core data schema. I will assume core data familiarity in this article so if you are unfamiliar you should read this article on core data.
- Write code to parse the file mentioned in step 1, and then save the data. My parser was as follows, and was located in my AppDelegate:
func loadData () { // path to csv file you are loading data for let path = NSBundle.mainBundle() .URLForResource("wordlist", withExtension: "csv") do { let content = try String( contentsOfURL: path!, encoding: NSUTF8StringEncoding) let lines = content .componentsSeparatedByCharactersInSet( NSCharacterSet.newlineCharacterSet()) as [String] for line in lines { var values = line .componentsSeparatedByString(",") let mode = NSEntityDescription .insertNewObjectForEntityForName("Mode", inManagedObjectContext: managedObjectContext) mode.setValue(values[0], forKey: "name") let word = NSEntityDescription .insertNewObjectForEntityForName("Word", inManagedObjectContext: managedObjectContext) word.setValue(values[1], forKey: "word") } do { try managedObjectContext.save() } catch { } } catch { } } - Run your application and ensure that you have the following print statement and the call to your parsing method somewhere in the code that will be executed, e.g.:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // where to get the preloaded database from print(applicationDocumentsDirectory.path) loadData() return true } - Copy the files into your project from the directory output by the console, ensuring "Copy items if needed" is checked.
- Make the necessary code changes (below) to reference your preloaded database. I have highlighted the additional code in yellow.
Code Changes to Access Your Preloaded Database
lazy var persistentStoreCoordinator:
NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(
managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory
.URLByAppendingPathComponent("SpellingBee.sqlite")
if !NSFileManager.defaultManager()
.fileExistsAtPath(url.path!) {
let sourceSqliteURLs = [
NSBundle.mainBundle().URLForResource("SpellingBee",
withExtension: "sqlite")!,
NSBundle.mainBundle().URLForResource("SpellingBee",
withExtension: "sqlite-wal")!,
NSBundle.mainBundle().URLForResource("SpellingBee",
withExtension: "sqlite-shm")!
]
let destSqliteURLs = [
self.applicationDocumentsDirectory
.URLByAppendingPathComponent("SpellingBee.sqlite"),
self.applicationDocumentsDirectory
.URLByAppendingPathComponent("SpellingBee.sqlite-wal"),
self.applicationDocumentsDirectory
.URLByAppendingPathComponent("SpellingBee.sqlite-shm")
]
var error:NSError? = nil
for var index = 0; index < sourceSqliteURLs.count; index++ {
do {
try NSFileManager.defaultManager()
.copyItemAtURL(sourceSqliteURLs[index],
toURL: destSqliteURLs[index])
} catch {
}
}
}
var failureReason = "..."
do {
try coordinator.addPersistentStoreWithType(
NSSQLiteStoreType, configuration: nil,
URL: url, options: nil)
} catch {
...
}
}()
Basically, this new code copies the database from your project files to the directory where the databases are stored. If the copy is not performed, a new database will be created if no databases exist in the directory. Please note, if you are getting nil when unwrapping the value returned by "NSBundle.mainBundle().URLForResource("SpellingBee", withExtension: "sqlite")". Then you may need to go to your build phases and ensure all 3 sqlite files are added to the "Copy Bundle Resources" section. Good luck and happy programming!
Thursday, 3 December 2015
Basic CloudKit Setup
As with a lot of their recent products, Apple has made iCloud quite easy to setup. The following post will show you how to setup basic iCloud storage for an app:
The above code handles loading, creating and updating highscores. I have put this in its own class as I believe this avoids it complicating game logic. There were also some minor adjustments required in the GameViewController, I will only show the code I added:
The above code is all you need to identify whether iCloud is currently available, and it updates every time you exit or enter the application.
Setting up
- Go to Xcode and go to the capabilities section under your app's settings. You should set it up to look like this (most of which will automatically be done by Apple when you turn CloudKit on):

- Go to your CloudKit dashboard and set up how you want your data to be stored by adding records. You can also add data to your public/private databases!
The Code
Surprisingly, there is also minimal code. Working with our previous records that we created in the CloudKit dashboard. This is the only code we require to fetch and update highscores (excuse the poor layout, I'm working with limited space):// CloudKitManager.swift // Angle Reader // // Created by Chelsea Farley on 7/02/15. // Copyright (c) 2015 Trip Wire. All rights reserved. // import CloudKit class CloudKitManager { var container : CKContainer! var isICloudAvailable : Bool = false var highscore : CKRecord! init() { // container which is used to access private // and public databases container = CKContainer.defaultContainer() } func fetchRecord(mode: String) { if (self.isICloudAvailable) { let predicate = NSPredicate(format: "Mode = %@", mode) let query = CKQuery(recordType: "Highscores", predicate: predicate) // load the highscore record with the matching mode container.privateCloudDatabase.performQuery(query, inZoneWithID: nil, completionHandler: ({results, error in var length = results!.count if (error == nil && results!.count > 0) { self.highscore = results[0] as! CKRecord } else { // create a highscore record if none exists var record = CKRecord(recordType: "Highscores") record.setObject(mode as CKRecordValue, forKey: "Mode") record.setObject(0 as CKRecordValue, forKey: "Highscore") self.container.privateCloudDatabase.saveRecord( record, completionHandler: ({result, error in if (error == nil) { self.highscore = result } })) } })) } } func updateHighscore(score: Int) -> Int { if (self.isICloudAvailable) { if (highscore != nil ) { var highscoreValue = highscore .valueForKey("Highscore") as! Int if (highscoreValue < score) { highscore.setObject(score as CKRecordValue, forKey: "Highscore") self.container.privateCloudDatabase.saveRecord (highscore, completionHandler: nil) } return highscoreValue } } return 0 } }
The above code handles loading, creating and updating highscores. I have put this in its own class as I believe this avoids it complicating game logic. There were also some minor adjustments required in the GameViewController, I will only show the code I added:
// GameViewController.swift // Angle Reader // // Created by Chelsea Farley on 7/02/15. // Copyright (c) 2015 Trip Wire. All rights reserved. // import UIKit import CloudKit import SpriteKit class GameViewController : UIViewController { var ckManager : CloudKitManager! override func viewDidLoad() { // Standard code represented by ... ... ckManager = CloudKitManager() NSNotificationCenter.defaultCenter().addObserver(self, selector: "applicationBecameActive:", name: UIApplicationDidBecomeActiveNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: "applicationBecameInactive:", name: UIApplicationWillResignActiveNotification, object: nil) } func handleIdentityChanged(notification: NSNotification){ let fileManager = NSFileManager() if let token = fileManager.ubiquityIdentityToken{ ckManager.isICloudAvailable = true } else { ckManager.isICloudAvailable = false } } func applicationBecameActive(notification: NSNotification){ NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleIdentityChanged:", name: NSUbiquityIdentityDidChangeNotification, object: nil) } func applicationBecameInactive(notification: NSNotification){ NSNotificationCenter.defaultCenter().removeObserver(self, name: NSUbiquityIdentityDidChangeNotification, object: nil) } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) ckManager.container.accountStatusWithCompletionHandler{ [weak self] (status: CKAccountStatus, error: NSError!) in // Be careful, we might be on a different thread // so make sure that your UI operations go // on the main thread dispatch_async(dispatch_get_main_queue(), { if error == nil{ self!.ckManager.isICloudAvailable = status == .Available } }) } } }
The above code is all you need to identify whether iCloud is currently available, and it updates every time you exit or enter the application.
Subscribe to:
Posts (Atom)