Website Links

Wednesday, 23 December 2015

Swift - Local Notifications

There are several sorts of notifications a user can receiver in iOS, these are:
  • Lock screen notifications
  • Banner notifications
  • Alerts
Lock screen and banner notifications are quite compact and can only have 2 associated actions. Whereas alert notifications are larger and can have up to 4 actions. You can choose whether you want to receive banner notifications or alert notifications for an app by going to Settings > Notifications > [App name]. This article is aimed at teaching you how to schedule and cancel local notifications.

Notification Settings

In the App.delegate you can configure the settings for your notifications, e.g. what actions there will be and whether the action will take place in the background or visibly. Firstly, we need to be aware of what type of notifications we can have:
  • UIUserNotificationType.None: The user sees nothing when the notification is received
  • UIUserNotificationType.Badge: The user will see a number on the app icon that represents a number of unhandled notifications
  • UIUserNotificationType.Sound: The user will hear a sound when the notification is received
  • UIUserNotificationType.Alert: A banner notification, lock screen notification or alert notification will be displayed

Here is how the code for setting up a notification would look, a good place to do this is the App.delegate:

  func application(application: UIApplication, 
    didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) 
    -> Bool {
        // Override point for customization after application launch.      
        let types = UIUserNotificationType([UIUserNotificationType.Alert, 
          UIUserNotificationType.Badge])
        
        let emailAction = UIMutableUserNotificationAction()
        emailAction.destructive = false
        emailAction.authenticationRequired = false
        emailAction.activationMode = UIUserNotificationActivationMode
          .Foreground
        emailAction.identifier = "EMAIL"
        emailAction.title = "Send Email"
        
        let textAction = UIMutableUserNotificationAction()
        textAction.destructive = false
        textAction.authenticationRequired = false
        textAction.activationMode = UIUserNotificationActivationMode
          .Foreground
        textAction.identifier = "TEXT"
        textAction.title = "Send Text"
        
        let noneCategory = UIMutableUserNotificationCategory()
        noneCategory.identifier = "NONE"
        noneCategory.setActions([], forContext: 
          UIUserNotificationActionContext.Default)
        noneCategory.setActions([], forContext: 
          UIUserNotificationActionContext.Minimal)

        let emailCategory = UIMutableUserNotificationCategory()
        emailCategory.identifier = "EMAIL"
        emailCategory.setActions([emailAction], forContext:
          UIUserNotificationActionContext.Default)
        emailCategory.setActions([emailAction], forContext:
          UIUserNotificationActionContext.Minimal)

        let textCategory = UIMutableUserNotificationCategory()
        textCategory.identifier = "TEXT"
        textCategory.setActions([textAction], forContext:
          UIUserNotificationActionContext.Default)
        textCategory.setActions([textAction], forContext:
          UIUserNotificationActionContext.Minimal)

        let bothCategory = UIMutableUserNotificationCategory()
        bothCategory.identifier = "BOTH"
        bothCategory.setActions([textAction, emailAction], 
          forContext: UIUserNotificationActionContext.Default)
        bothCategory.setActions([textAction, emailAction;], 
          forContext: UIUserNotificationActionContext.Minimal)
        
        let settings :UIUserNotificationSettings = 
          UIUserNotificationSettings(forTypes: types, 
          categories: [noneCategory, emailCategory, 
                       textCategory, bothCategory])
        UIApplication.sharedApplication()
          .registerUserNotificationSettings(settings)
        
        return true
    }

The UIMutableUserNoticationCategory is something you can use when scheduling a new notification to specify what actions are available to it. The context for the actions can either be Default (up to 4) or Minimal (up to 2).

Scheduling a Notification

Scheduling a notification is incredibly simple and can be done as follows:

  let notification = UILocalNotification()

  \\ When the notification will appear
  notification.fireDate = dueDate

  \\ What the notification will say
  notification.alertBody = "Hello world"

  \\ Links what actions the notification will have with what was 
  \\ specified in the App.delegate
  notification.category = "BOTH"

  \\ Additional info that we need when the app receives a user's 
  \\ interaction with the notification
  var userInfo = [String: String]()
  userInfo["notificationId"] = bookToSave.objectID.persistentStore?
    .identifier
  notification.userInfo = userInfo
  
  UIApplication.sharedApplication()
    .scheduleLocalNotification(notification)


Cancelling a notification

Often, if a user has specified a due date for something and they edit it this you will need to cancel the existing notification and reschedule it. Finding the correct notification to cancel can sometimes be challenging and this is commonly where I rely on the userInfo I have passed to the notification:

  for notification in UIApplication.sharedApplication()
    .scheduledLocalNotifications! 
  {
    var userInfo = notification.userInfo as! [String : String]
    if (userInfo["notificationId"] == 
        bookToSave.objectID.persistentStore?.identifier) {
      UIApplication.sharedApplication()
        .cancelLocalNotification(notification)
    }
  }

It is also possible to cancel all notifications using UIApplication.sharedApplication().cancelAllLocalNotifications().

Handling actions of a notification

To handle receiving information from a notification, you will need to add the following function to your App.delegate:

  func application(application: UIApplication, 
    handleActionWithIdentifier identifier: String?, 
    forLocalNotification notification: UILocalNotification, 
    completionHandler: () -> Void)
  {
    if (identifier == "EMAIL") {
      NSNotificationCenter.defaultCenter()
        .postNotificationName("EmailPressed", object: nil)
    } else if (identifier == "TEXT") {
      NSNotificationCenter.defaultCenter()
        .postNotificationName("TextPressed", object: nil)
    }
        
    completionHandler()
  }

The method above is the first step, what it does is it gives you what action was pressed in the notification, along with the notification and a completion handler. You can then use the NSNotificationHandler to pass information to pass control to the view controller that will handle the actions. Here is an example of the notifications being handled in a view controller:

  override func viewDidLoad() {
    super.viewDidLoad()
    ...
        
    NSNotificationCenter.defaultCenter().addObserver(self, 
      selector: "sendEmail:", 
      name: "EmailPressed", 
      object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, 
      selector: "sendText:",
      name: "TextPressed",
      object: nil)
  }

  func sendEmail(notification : NSNotification) {
    ...
  }

  ...

The selector represents the method that will be called when the view controller received the event of the specified name. ':' after the method name represents that the method has a parameter.

Tuesday, 22 December 2015

Swift - Sending Emails and SMS from app

Opening up a pre-populated message composer in iOS which can be used to send an email or SMS is surprisingly easy. There is however, some issues you may encounter when testing this on a simulator where it lags and then crashes. So it is best to have a physical device available if you plan on testing this. I have also heard that having a singleton instance of your composer and showing this when required can help alleviate these issues. However, I needed to be able to send SMS/Emails based on a push notification, and on a physical device I didn't encounter these issues. Here's how I did it:

  import UIKit
  import MessageUI

  class MessageComposerViewController : UIViewController, 
    MFMailComposeViewControllerDelegate, 
    MFMessageComposeViewControllerDelegate {
    
    ...
    
    func sendEmail() {
      let emailVc = MFMailComposeViewController()
      emailVc.mailComposeDelegate = self
      emailVc.setSubject("Seasons Greetings!")
      emailVc.setMessageBody("<b>Merry Christmas!<br/>
        From Trip Wire</b>", isHTML: true)
      emailVc.setToRecipients(["hello@world.christmas"])
      presentViewController(emailVc, animated: true, 
        completion: nil)
    }

    func mailComposeController(
      controller: MFMailComposeViewController, 
      didFinishWithResult result: MFMailComposeResult, 
      error: NSError?) {
      dismissViewControllerAnimated(true, completion: nil)
    }

    func sendSms() {
      let smsVc = MFMessageComposeViewController()
      smsVc.body = "Seasons greetings! From the Trip Wire team";
      smsVc.recipients = ["5556789"]
      smsVc.messageComposeDelegate = self;
      presentViewController(smsVc, animated: true, 
        completion: nil)
    }

    func messageComposeViewController(
      controller: MFMessageComposeViewController, 
      didFinishWithResult result: MessageComposeResult) {
      dismissViewControllerAnimated(true, completion: nil)
    }

    ...

  }

Monday, 14 December 2015

Swift - Sorting NSManagedObjects (from Core Data)

Class to represent Core Data Table

You will need to add a class to represent your core data table:

  // My core data object only had the field name
  // it also had relationships but I didn't need to access 
  // these so they are excluded. 
  import CoreData

  @objc(Mode)
  class Mode: NSManagedObject {
    @NSManaged var name: String
  }

Following that you will need to ensure your core data table references the class or you'll get an error, you can do this in the same place you would add columns to the table:



Performing the sort

First you must load the data, ensure that you save it as an array of your object representation of the Core Data table.

  ...

  let modes : [Mode] = try context.executeFetchRequest(request)
    as! [Mode]

  // We must specify whether we want to sort in
  // ascending or descending order
  // $0 represents the first item, $1 represents the second
  // their fields can be access as normal 
  appState.modes = modes.sort({$0.name.compare($1.name) 
    == NSComparisonResult.OrderedAscending}) as [Mode]

  ...

Swift - try/catch

In Swift, when a func is marked with throws, it can throw an exception and your code should handle this. This can be done using do/try/catch statements as follows:

  // do contains all statements that should 
  //be executed only if the try succeeds
  do {
    // try comes before the func which is marked with throws
    let modes : [Mode] = try context.executeFetchRequest(request)
      as! [Mode]

    // tried func has succeeded, continue with workflow
    appState.modes = modes.sort({$0.name.compare($1.name) 
      == NSComparisonResult.OrderedAscending}) as [Mode]
  } catch {
    // handle error
    // can handle different types of exceptions separately by their name
  }

Sunday, 13 December 2015

Photoshop - Change colour of entirely black icon

  1. Create a new layer solidly filled with the colour you want to change the black to
  2. Go to Layer > Create Clipping Mask
  3. Your image should now be the colour selected of the layer you created a clipping mask for

Swift - My Resources

Sometimes there are articles that I find particularly useful. This page will hold them:

Friday, 11 December 2015

Swift - Creating a countdown timer

There are many situations where you may have the need to use a countdown timer. This article is aimed at helping you create one! Firstly, you will want to add a label to your storyboard and reference it through an @IBOutlet in the relevant view controller. This will display your countdown. Following that you will need the following code:

  class GameViewController: UIViewController {

    @IBOutlet var _timerLabel: UILabel!
    var _timer : NSTimer!
    ...

    override func viewDidLoad() {
      super.viewDidLoad()
      _timerLabel.text = "60"

      //the first argument is how long in seconds
      // target - where to look for the selector
      // selector - function name
      // userInfo - AnyObject, you can use this to store 
      // anything you need
      // repeats - whether or not the function should be 
      // repeatedly called
      _timer = NSTimer.scheduledTimerWithTimeInterval
       (1, target: self, selector: Selector("countDown"), 
       userInfo: nil, repeats: true)
    }

    // function called after time interval specified above
    // updates label, or stops timer and ends game if it 
    // has reached 0
    func countDown() {
      let currentCount = Int(_timerLabel.text!)
       
      if (currentCount == 0) {
        _timer.invalidate()
        gameOver()
      } else {
        _timerLabel.text = String(currentCount! - 1)
      }
    }

    ...

  }

For more information, view the reference page for NSTimer

Swift - Hide keyboard when clicking outside UITextField or return is tapped

Sometimes it can obscure the view when a user enters something in a UITextField and the keyboard stays open even after they have clicked outside the keyboard, or tapped return. The following code will help you close the keyboard when appropriate. However, first you need to set up your text field and make the appropriate view controller be its delegate, and implement UITextFieldDelegate:



The corresponding code is as follows:

  class GameViewController: UIViewController, UITextFieldDelegate {

    ...

    override func touchesBegan(touches: Set, 
      withEvent event: UIEvent?) {
      self.view.endEditing(true)
    }

    func textFieldShouldReturn(textField: UITextField) -> Bool {
      textField.resignFirstResponder()
      return true
    }

    ...

  }

Additionally, if you have any buttons with IBActions attached to them you may need to have the line self.view.endEditing(true) in these also.

Swift - Text to speech

  1. Add the following line to the class you want to use text to speech in "import AVFoundation"
  2. Create a speech synthesizer: let speechSynthesizer = AVSpeechSynthesizer()
  3. Create a speech utterance: let speechUtterance = AVSpeechUtterance(string: "Hello world!")
  4. 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.
  5. Use the speech synthesizer to speak the utterance: speechSynthesizer.speakUtterance(speechUtterance)

Swift - Turn off autocorrect/spelling correction on text feld

  1. Add a UITextField to your storyboard
  2. Add an IBOutlet that references the textfield in your view controller
  3. 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.

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:
  1. Setup the view controller code, and set it as the view controller class against a view controller in your storyboard



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



  3. 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:

  // 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

  1. Get the data you want into some format you can parse, e.g. XML, JSON or CSV.
  2. Create your project, ensure that you select to use Core Data.
  3. Copy your data file into your project
  4. 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.
  5. 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 {
                
        }
      }
    
    
  6. 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
      }
    
    
  7. Copy the files into your project from the directory output by the console, ensuring "Copy items if needed" is checked.
  8. 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:

Setting up

  1. 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):

  2. 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.

Friday, 8 May 2015

Quick Guide to Writing a Chrome Extension

manifest.json

The manifest file is where your extension and its details are defined. There are many different things you can add to it, but here are a few of the basic things:

  {
    "manifest_version": 2,

    "name": "My Chrome Extension",
    "description": "This extension allows you to do... Anthing!",
    "version": "1.1",

    "browser_action": {
      "default_icon": "icon.png",
      "default_popup": "popup.html"
    },

    "content_scripts": [
      {
        "matches": ["https://www.mysite.com/*"],
        "js": ["jquery.js", "SetupDefaults.js", "ChangeTemplate.js"]
      }
    ],

    "permissions": [
      "storage"
    ],

    "icons": { 
      "128": "icon.png" 
    }

  }


Here's a breakdown on the key things in this file:
  • The browser_action allows you to define an image and HTML file that will be used in a popup window when your extension is clicked on in the Chrome toolbar.
  • The content_scripts allows you to specify that when the URL matches https://www.mysite.com/* the scripts jquery.js, SetupDefaults.js and ChangeTemplate.js will be run.
  • The permissions allows you to specify any permissions you need, for example if you were using chrome.storage then you would need the "storage" permission.

It is important to note that the default_popup HTML file cannot have inline JavaScript in it, and this will need to be specified in the head of the HTML as so:

  <html>
    <head>
      <script src="popup.js"></script>
    </head>
    <body>
    </body>
  </html>


Installing Extension Locally

To install your extension locally you will need to go to Extensions (shown below):



Then make sure Developer Mode is checked, and then click Load Unpacked Directory and select the relevant directory.

Submitting your extension

If you would like to submit your Extension you will need to get a Chrome Web Store developer account. This costs approximate $5 (USD) and is a one-off fee. You can find out more about it on this web store getting started guide.

Core Data for Swift

Having core data enabled for an xCode project allows you to persist data between user sessions. There is an option you should tick when creating the project, and that is to use core data. However, if you have already created your project and made significant process without turning on this option, you can just create a new project and copy across the relevant code from AppDelegate.swift!

Defining Entities

xCode makes it excessively easy to define entities. First, you will need to open the .xcdatamodeld file and click "Add Entity", your new entity will appear under the list of entities and you can double click on it to rename it. Adding attributes can be done by pressing the "+" in the attributes section. Attributes need to start with a lowercase name, and some names are reserved such as "isDeleted". You can then select what data type that attribute will be stored as. Your finished entity should look something like this:



There is also a view which allows you to edit entities and add relationships in a UML style format. If you would prefer that change the "Editor Style" which is located in the bottom right.

Defining Relationships

You are also able to define relationships between entities. Once a relationship is created, you can view its details and set properties such as how deletes are handled. For example, when a scenario is deleted I want all stones linked to it to also be deleted, so I set the "Delete Rule" to cascade. Once you have finished defining your relationships you should should have something that looks like this:



The above diagram shows that a Stone entity has one Scenario entity, and a Scenario entity has many Stone entities.

Creating Entities


  func createScenario() {
    let appDelegate = UIApplication.sharedApplication().delegate 
         as! AppDelegate
    let context = appDelegate.managedObjectContext!
        
    //Getting entity description for entity named "Scenario"
    //and creating object to save from it     
    let scenarioEntityDescription =  NSEntityDescription
         .entityForName("Scenario", inManagedObjectContext: context)!
    var scenario =  NSManagedObject
                     (entity: scenarioEntityDescription,
                      insertIntoManagedObjectContext: context)
        
    //Setting entity's attributes.  
    scenario.setValue(nameTextField.text, forKey: "name")
    scenario.setValue(descriptionTextField.text, forKey: "scenario")
    scenario.setValue(tagTextField.text, forKey: "tag")

    //Adding stone for stones relationship.
    //Excluded setting of the "Stone" entity's attributes 
    //for brevity.
    //First step is to get a set for the "stones" 
    //relationship from the scenario.
    var stonesSet = scenario.mutableSetValueForKey("stones")
    let stoneEntityDescription = NSEntityDescription
         .entityForName("Stone", inManagedObjectContext: context)!
    var stoneEntity = NSManagedObject
                       (entity: stoneEntityDescription,
                        insertIntoManagedObjectContext: context)
    stonesSet.addObject(stoneEntity)

    //Setting the stones relationship for the scenario.
    //Saving, please note error handling was excluded.
    scenario.setValue(stonesSet, forKey: "stones")
    context.save(nil)
  }


Fetching Entities


  //Returns an NSArray of all "Scenario" entities.
  //If you want to modify this array (add/remove) then you will need
  //a NSMutableArray using scenarios.mutableCopy() as! NSMutableArray.
  func fetchScenarios() -> NSArray {
    let appDelegate = UIApplication.sharedApplication().delegate 
         as! AppDelegate
    let context = appDelegate.managedObjectContext!
        
    //Setting up request for entity named "Scenario"
    //You can also specify search constraints.     
    var request = NSFetchRequest(entityName: "Scenario")
    request.returnsObjectsAsFaults = false
        
    //Fetching all "Scenario" entities.
    //It will also load all "Stone" entities linked
    //with a "Scenario" entity by "stones" relationship.
    return context.executeFetchRequest(request, error: nil)!
  }


Updating Entities


  //Update the "tag" attribute of a given "Scenario" entity.
  func changeScenarioTag(scenario: NSManagedObject, newTag: String) {
    let appDelegate = UIApplication.sharedApplication().delegate 
         as! AppDelegate
    let context = appDelegate.managedObjectContext!
    
    //Making change to the "Scenario" entity's "tag" attribute.
    //Committing the change.
    scenario.setValue(newTag, forKey: "tag")
    context.save(nil)
  }


Deleting Entities


  func deleteScenario(scenario: NSManagedObject) {
    let appDelegate = UIApplication.sharedApplication().delegate 
         as! AppDelegate
    let context = appDelegate.managedObjectContext!
    
    //Telling context we want to delete the scenario object.
    //As we specified a cascade delete in our relationship "stones"
    //the "Stone" entities linked with the "Scenario will be deleted also.
    context.deleteObject(scenario)

    //Commiting delete.
    context.save(nil)
  }


Tuesday, 5 May 2015

Swift Constructors

If you are interested in creating your own subclass of one of Swift's built in objects, you may often want to pass in additional arguments to the constructor. However, it isn't immediately obvious how to do this. The following code shows you how:

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    convenience init(color: UIColor, bounds: CGRect) {
        self.init(frame: bounds)
        self.color = color
    }


    // will give you an error if you try to compile without this
    // after adding the above constructors
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }



To explain this a bit further, when you implement a custom constructor you will get an error if you don't implement the required constructor. The constructor you define must be prefixed with convenience and should make a call to the parent class constructor. However, you cannot make the call to the parent class constructor directly from your convenience constructor. The first constructor overrides and then calls the parent constructor so that you can make a call to it.

Friday, 1 May 2015

Preventing Backwards Navigation from a Bar Button Item in Swift

Hello there, sometimes you wish to return to the root view controller when you click on a bar button item in the navigation bar of an app with a navigation controller. For example, you may save something that you don't want the user to be able to go back to. Fortunately, there is away to do this and it is by using a segue with an identifier.
  1. Create a segue from your Bar Button Item
  2. Click on your segue and give it an identifier
  3. Implement the following function in the view controller which has the bar button you added a segue for:

    override func shouldPerformSegueWithIdentifier(identifier: 
        String?, sender: AnyObject?) -> Bool {
        
        if (identifier == "save") {
            saveBoard()
        }
        
        self.navigationController?
            .popToRootViewControllerAnimated(true)
        
        return false
    }


The above handles 2 different segues in my project, one is cancel in which case I want to return to the root view controller without having the ability to go back to my board that I decided I no longer wanted to save. The other is save, when my saving segue is called I want to call my function which saves the board and then goes back to the root view controller. The boolean returned by the function specifies whether the segue was cancelled or not... I returned false as I wanted to handle the navigation back to the root view controller by myself in all cases. The function shouldPerformSegueWithIdentifier could also be useful to implement if you wanted to validate the data a user entered before navigation.

iAd Advertisements Not Showing

iAd advertisements can take a while to show up even if your app has the status Live Ads and has been processed for the App Store. If your app has only been approved in the past week I wouldn't worry about whether your iAd integration worked or not (unless you have your fill rate set to 100% in the simulator and cannot see ads)! Here is a list of how long ads have taken to show up in our apps:

App Ad Type Time to show
iou free Banner ads 7 days
Angle Reader free Interstitial ads 3 days

Thursday, 16 April 2015

Integrating with iAd

This is pretty simple... Firstly go to iTunes and then to the Agreements, Tax and Banking section. Select and agree to the iAd App Network contract. Once you have done that, go ahead and open your Xcode project. Go to your project, and in the General section go down to Linked Frameworks and Libraries, hit the '+'and find iAd.framework. The iAd framework comes installed so you don't even need to go and download it first!

iAd BannerView

Go to your view controller where you want to display ads, import iAd and set self.canDisplayBannerAds to true. This will automatically handle the adding of a banner view to your view and resize your view depending on the availability of ads. It will also hide the banner view when no ads can be fetched.

iAd Interstitials

This is a little bit more complicated than banner views but works well when you don't want to make space for banner views, and are commonly used in games. Once again, go to the view controller you want to have show interstitial views and import iAd. You will also need to make it implement ADInterstitialAdDelegate, and add the following code:


    var interstitialAd : ADInterstitialAd!
    var interstitialAdView : UIView!
    var closeButton : UIButton!
    
    override func viewDidLoad() 
    {
        super.viewDidLoad()

        // any viewDidLoad logic you have
        
        closeButton = UIButton.buttonWithType(UIButtonType.System)
                      as! UIButton
        closeButton.frame = CGRectMake(self.view.frame.width - 42,
                                       10, 32, 32)
        closeButton.layer.cornerRadius = 16

        // Note: I have an image asset named "Close"
        // You will need to add one for this to work
        var closeImage = UIImage(named: "Close")
        closeButton.backgroundColor = UIColor.whiteColor()
        closeButton.tintColor = UIColor.blackColor()
        closeButton.setImage(closeImage, 
                             forState: UIControlState.Normal)
        closeButton.addTarget(self, action: "closeAd:", 
                              forControlEvents: .TouchDown)
    }
    
    func closeAd(sender: UIButton) 
    {
        closeButton.removeFromSuperview()
        if ((interstitialAdView) != nil) {
            interstitialAdView.removeFromSuperview()
        }
    }
    
    // call whenever you want to show an ad
    func showAd() 
    {
        interstitialAd = ADInterstitialAd()
        interstitialAd.delegate = self
    }
    
    func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) 
    {
        interstitialAdView = UIView()
        interstitialAdView.frame = self.view.bounds
        self.view.addSubview(interstitialAdView)
        
        interstitialAd.presentInView(interstitialAdView)
        UIViewController.prepareInterstitialAds()
        
        interstitialAdView.addSubview(closeButton)
    }
    
    func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!)
    {
        closeAd(closeButton)
    }
    
    // can do things with the error if you want to... I chose not to
    func interstitialAd(interstitialAd: ADInterstitialAd!,
                        didFailWithError error: NSError!) 
    {
        closeAd(closeButton)
    }




Alternatively, it may be worthwhile implementing this in another view controller that all your view controllers that show interstitial ads will extend.

Friday, 20 February 2015

Euler Angles

Euler angles allow you to specify any 3D rotation with just 3 values, these values are as follows:

Pitch

Up and down (i.e. looking up and down)

Yaw

Side to side (i.e. looking left and right)

Roll

Tilting (i.e. tilting your head from side to side)

References

Math for Game Developers - Mouse Control (Euler Angles) Video on YouTube

Wednesday, 18 February 2015

App Icons and iTunes Icons for iOS Apps

You can change what App Icon your iOS App is going to have through the assets catalog. You will need to create quite a few different sizes and I've found the best way to do this is to make the biggest one and resize it accordingly, but where do all these different sizes go? First you will need to enable all the sizes you need, by clicking on the AppIcon asset and finding the following pane:



You can enable/disable these as appropriate for your app, and you should end up with an asset catalog that looks like this:



The above image should tell you what image sizes you will need for your App icons, and where they need to be placed in the catalog.

References

Apple Developer