Using an Encrypted Realm in a background or notification processes?

Note: This post's primary purpose is to help me think through this problem. I have no prescribed solution at the end of it. The conversation will continue on Stack Overflow. I will update this post once I have a final approach.

Realm has a great write up and sample code for encrypting your database. This documentation and sample work as intended, until you try to decrypt realm when:

  1. A user has a password on their phone
  2. The device is locked
  3. Your app is trying to do work with Realm when a remote notification comes in

This happens because we can't access the keychain to get (or create) the key to en/decrypt the Realm. The default kSecAttrAccessible value is kSecAttrAccessibleWhenUnlocked

There are a few options as I see them:

  1. Change kSecAttrAccessible to kSecAttrAccessibleAlways. I don't like this because it's a) too open and b) it was slated to be deprecated in iOS 9
  2. Change kSecAttrAccessible to kSecAttrAccessibleAfterFirstUnlock or kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. This is better but still feels too open to me, even though the docs state: This is recommended for items that need to be accessed by background applications
  3. Create a second, non-encrypted Realm to use as a staging database. Store notification data here, then when the app wakes up from user interaction (the device would be unlocked), move the data from the staging Realm into the encrypted real one. This doesn't feel right either, as we'll have data temporarily not encrypted
  4. Combine 2 and 3 and encrypt the staging Realm, and protect it's key with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
  5. ??

I'm currently trying to decide if #2, if #3 is worth putting the time into, or if I can come up with a #5

Testing UIViewController Transitions with Quick and Swift

The examples below are using the Quick test framework, but the principals we're going to talk about can be used in any setup.

We have some complicated logic further down our user registration flow. I want to make sure that the right UIViewControllers are appearing when they are supposed to. I've been reading a few different approaches on how to handle this. Below is where I've ended up, and I'm pretty happy with it.

For simplicity's sake, I'm going to show how to test if the user has tapped "Login" or "Register" on our opening screen. We can assume we have a LoadingViewController which represents the first screen. On this screens are two buttons, which correspond to these actions:

@IBAction func tapLogin(sender: AnyObject) {
    self.navigationController?.pushViewController(self.storyboard?.instantiateViewControllerWithIdentifier("loginview") as! LoginViewController, animated: true)
}

@IBAction func tapRegister(sender: AnyObject) {
    self.navigationController?.pushViewController(self.storyboard?.instantiateViewControllerWithIdentifier("registerview") as! RegisterViewController, animated: true)
}

We also have a UINavigationController taking care of the view hierarchy. I also want to use the transitions and IDs already set up in the Storyboard.

Let's start by referencing the UINavigationController and the UIViewController we're going to start with.

class LandingScreenUITests: QuickSpec {
    override func spec() {
        describe("Landing Screen") {

            var viewController: LoadingViewController!
            var navigationController: UINavigationController!


        }
    }
}

Next, we're going to instantiate the storyboard, both controllers, and push the VC onto the view hierarchy

beforeEach {
    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
    viewController = storyboard.instantiateViewControllerWithIdentifier("loadingview") as! LoadingViewController
    navigationController = storyboard.instantiateViewControllerWithIdentifier("navigationcontroller") as! UINavigationController

    navigationController.pushViewController(viewController, animated: false)

    let _ =  viewController.view
}

Two gotchas to watch out for here:

  1. Make sure Main.Storyboard is available in your Test target
  2. Make sure to use the self.dynamicType bundle above

Missing either of these may result in a weird casting error:

Could not cast value of type 'MyApp.LoadingViewController' (0x10b9f5e50) to MyAppUITests.LoadingViewController' (0x11f894370).

Finally, lets call the appropriate methods on our initial UIViewController, and test the type of the UIViewController that has been put on the top of the hierarchy. Note: I use toEventually here to wait for the transition animation

describe("User wants to log in") {
    it("taps Login") {
        viewController.tapLogin(self)
        expect(navigationController.visibleViewController).toEventually(beAKindOf(LoginViewController))
    }
}

describe("User wants to register") {
    it("taps Register") {
        viewController.tapRegister(self)
        expect(navigationController.visibleViewController).toEventually(beAKindOf(RegisterViewController))
    }
}

For reference, here is the whole test class together:

import Foundation
import Quick
import Nimble
@testable import MyApp

class LandingScreenUITests: QuickSpec {
    override func spec() {
        describe("Landing Screen") {

            var viewController: LoadingViewController!
            var navigationController: UINavigationController!

            beforeEach {
                let storyboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
                viewController = storyboard.instantiateViewControllerWithIdentifier("loadingview") as! LoadingViewController
                navigationController = storyboard.instantiateViewControllerWithIdentifier("navigationcontroller") as! UINavigationController

                navigationController.pushViewController(viewController, animated: false)

                let _ =  viewController.view
            }

            describe("User wants to log in") {
                it("taps Login") {
                    viewController.tapLogin(self)
                    expect(navigationController.visibleViewController).toEventually(beAKindOf(LoginViewController))
                }
            }

            describe("User wants to register") {
                it("taps Register") {
                    viewController.tapRegister(self)
                    expect(navigationController.visibleViewController).toEventually(beAKindOf(RegisterViewController))
                }
            }
        }
    }
}

Many thanks to the blog posts referenced at the top of this post

UITableViewCell Action Swiping in iOS8 and Swift

Mail.app in iOS7 brought swiping cells to the inbox. The iOS8 beta added a 3rd button to it.  Apple has also introduced an API to assist with creating this effect: UITableViewRowAction. Prior to this, I used SWTableViewCell.

Below is how to get the basic functionality working. Please note that you have to implement the 2nd function whether it has a body or not

class TIMUITableViewDelegate: NSObject, UITableViewDelegate {
    func tableView(tableView: UITableView!, editActionsForRowAtIndexPath indexPath: NSIndexPath!) -> [AnyObject]! {
        var shareAction = UITableViewRowAction(style: .Normal, title: "Share") { (action, indexPath) -> Void in
            tableView.editing = false
            println("shareAction")
        }
        shareAction.backgroundColor = UIColor.grayColor()

        var doneAction = UITableViewRowAction(style: .Default, title: "Done") { (action, indexPath) -> Void in
            tableView.editing = false
            println("readAction")
        }
        doneAction.backgroundColor = UIColor.greenColor()

        var deleteAction = UITableViewRowAction(style: .Default, title: "Delete") { (action, indexPath) -> Void in
            tableView.editing = false
            println("deleteAction")
        }

        return [deleteAction, doneAction, shareAction]
    }

    func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) {
    }

}

I can’t get the (-) delete indicator to appear when I put the table into edit mode though. Setting UITableViewCell.shouldIndentWhileEditing = NO is supposed to disable this effect. I’ve tried setting it in 3 places:

I’ve had to add some workarounds to deal with this for now.  I’ve filed rdar://17969970 against this. For now, this is how I’m handling by checking if I’m already in edit mode when I build out the actions array. This isn’t ideal at all. I don’t even want to be able to delete when I’m in edit mode, just reorder. Apologies for switching back to obj-c. The delegate I’m working in is older.

- (void) endEditing
{
    self.editMode = NO;
    self.editControlButton.title = @"Reorder";
    [self setEditing:NO animated:YES];
    //[self.tableView reloadData];
}

- (void) startEditing
{
    self.editMode = YES;
    self.editControlButton.title = @"Done";
    [self.tableView setEditing:YES animated:YES];
}

#pragma - mark UITableViewDelegate

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewCellEditingStyleDelete;
}

- (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"shouldIndentWhileEditingRowAtIndexPath");
    return NO;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    TCORead *item = [self.fetchedResultsControllerDataSource selectedItem];
    manager.currentRead = item;
}

- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"Delete" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
        [self.tableView setEditing:NO];
    }];

    //workaround, rdar://17969970
    //normally don't want to be able to get into this menu when reordering
    if (!self.editMode) {
        UITableViewRowAction *shareAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"Share" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
            [self.tableView setEditing:NO];
        }];
        shareAction.backgroundColor = [UIColor grayColor];

        UITableViewRowAction *doneAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"Done" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
            [self.tableView setEditing:NO];
        }];
        doneAction.backgroundColor = [UIColor greenColor];

        [self startEditing];
        return @[deleteAction, doneAction, shareAction];
    }

    return @[deleteAction];
}

- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self endEditing];
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    //empty on purpose
}

This post and the Radar helped me collect my thoughts to post on Stack. I’ve been afraid of backlash or Noob. Time to get over it.

Update 2014-09-11

Vanyas has a great sample application that addresses what I’m trying to do.  I was forcing the delete button on the right hand side myself.  Updating editingStyleForRowAtIndexPath to the below fixed my issue:

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //return UITableViewCellEditingStyleDelete;
    return tableView.isEditing ? UITableViewCellEditingStyleNone: UITableViewCellEditingStyleDelete;
}

Dismiss a Modal UIViewController created in Interface Builder

There are a number of posts on this subject on Stack. They involve re-instantiating (this seems slower to me) or yanking the view from a UIButton (this feels dirty).

I’d rather just update the UIBarButtonItem that I already have:

2014-07-27_1826

All I needed to do, was attach the appropriate target and action to the UIBarButtonItem:

class SettingsTableViewController : UITableViewController {

    @IBOutlet weak var doneBarButton: UIBarButtonItem!

    init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        doneBarButton.target = self
        doneBarButton.action = "donePressed:"
    }

    @IBAction func donePressed(b:UIBarButtonItem) {
        self.dismissViewControllerAnimated(true, completion: {})
    }
}

Using PonyDebugger on a device

PonyDebugger is awesome. I use it mostly for Core Data debugging. Most of the time, I find it easier then firing up SQLite Professional.

When using the simulator, hitting localhost:9000 is fine. On a device, not so much; you need to hit your machine. xip.ioto the rescue! What it is: xip.io is a magic domain name that provides wildcard DNS for any IP address. We use this heavily at work if the machine we’re on isn’t hooked up to a subdomain or [Vagrant Share](https://www.vagrantup.com/blog/feature- preview-vagrant-1-5-share.html).

We can use this wildcard to have our iPhone hit our laptop’s instance of PonyDebugger.

First, get your IP. I use this Alfred workflow. Take note of your local IP.

Start PonyDebugger listening on that IP:

bashponyd serve —listen-interface=192.168.1.10

For handy access, alias this command:

bashalias pony="ponyd serve --listen-interface=192.168.1.10"

Load Pony in your browser by appending your IP to the a xip.io URL: http://192.168.1.10.xip.io:9000/

To access via the simulator or a device:

swiftlet pony = PDDebugger.defaultInstance() pony.connectToURL(NSURL.URLWithString("ws://192.168.1.10.xip.io:9000/device")) pony.enableNetworkTrafficDebugging() pony.enableCoreDataDebugging()

UITapGestureRecognizer in Swift

I have a subclass of UIView that has a label:

class PlayerView : UIView {
    @IBOutlet weak var playLabel: UILabel!
}

I want to attach a Tap Gesture to it:

class PlayerView : UIView {
    @IBOutlet weak var playLabel: UILabel!
}

Creating a conforming delegate (UITableViewDelegate) in Swift

This tripped me up for a bit so I hope this helps someone.

I started out with this class, thinking I could just continue on my merry way. This errors in Xcode with: "class does not conform to NSObjectProtocol

class FastListUITableViewDelegate : UITableViewDelegate { }
 ```

Hmm ok, but much there yet, what did I miss? This should definitely be a
class; not a protocol (I have methods to implement), not a @class_protocol
(wrong use, based on the docs), hmm.

This obviously behaves different than in objective-c. What is inherent in the
obj-c version of this that would conform to NSObjectProtocol? NSObject. Every
class and C eventually rolls up to this…

This is working so far:

```swift 
class FastListUITableViewDelegate : NSObject, UITableViewDelegate { }

I’ll report back here if this solution changes

Looping through subviews and downcasting in Swift

I've been playing around with Auto-Layout. This snippet was helpful to see what constraints were set on what views in my View Hierarchy.

Getting the downcast right on the subviews Array took a few tries:

```swift func showAL(view: UIView) { println("!") println(view) println(view.constraints()) }

for view in self.subviews as [UIView] {
    showAL(view)
    for subview in view.subviews as [UIView] {
        showAL(subview)
    }
}
```

Functions or Read-Only Properties in Swift?

I’m not sure which is better.  If it's returning something that is directly tied to the class: a slice/dice of properties is already has, I'm leaning towards properties. Because of the many examples I feel like read-only properties are the way to do.  I’m not the only person [wondering](http://stackoverflow.com/questions/24035276/computed-read-only- property-vs-function-in-swift), so that’s validating.

Property:

extension String {
    var fullSentences: [String] {
        // stuff
    }
}

Function:

extension String {
    func fullSentences() -> [String] {
        // stuff
    }
}