Jim Kubicek

Octo-Impressive

Creating a Swift Collection

Let’s say you’d like to create your own collection class. In this example, it’s going to be a collection of books that only allow the addition of a new book if it’s written by a select list of your favorite authors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typealias Book = (title: String, author: String)

struct MyCollection {

    private let validAuthors = ["Tom Robbins", "Jim Davis"]
    private var books: [Book] = []

    mutating func addBook(book: Book) -> Bool {
        if (find(validAuthors, book.author) != nil) {
            books.append(book)
            return true
        } else {
            return false
        }
    }
}

So good so far. Now we need to add some accessors. It would be nice to know how many books are in the collection. Indexed access to the books would be great. The ability to iterate over our books in a for x in y block would be fantastic. Let’s go about adding that behavior.

In order to enable using our collection in a for loop, we’ve got to adopt the CollectionType protocol. Let’s add that to our MyCollection declaration.

1
class MyCollection: CollectionType {

Let’s read the definition of the CollectionType protocol.

1
2
3
protocol CollectionType : _CollectionType, SequenceType {
    subscript (position: Self.Index) -> Self.Generator.Element { get }
}

Well then. That looks simple, except what is Self.Index and Self.Generator.Element? Let’s read the definition of _CollectionType and SequenceType.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
protocol _CollectionType : _SequenceType {

    /// A type that represents a valid position in the collection.
    ///
    /// Valid indices consist of the position of every element and a
    /// "past the end" position that's not valid for use as a subscript.
    typealias Index : ForwardIndexType

    /// The position of the first element in a non-empty collection.
    ///
    /// Identical to `endIndex` in an empty collection.
    var startIndex: Index { get }

    /// The collection's "past the end" position.
    ///
    /// `endIndex` is not a valid argument to `subscript`, and is always
    /// reachable from `startIndex` by zero or more applications of
    /// `successor()`.
    var endIndex: Index { get }
    typealias _Element
    subscript (_i: Index) -> _Element { get }
}

protocol SequenceType : _Sequence_Type {

    /// A type that provides the *sequence*\ 's iteration interface and
    /// encapsulates its iteration state.
    typealias Generator : GeneratorType

    /// Return a *generator* over the elements of this *sequence*.
    ///
    /// Complexity: O(1)
    func generate() -> Generator
}

Informative. Now we need to know what _SequenceType, ForwardIndexType _Sequence_Type, and GeneratorType do.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
protocol _SequenceType {
}

protocol ForwardIndexType : _ForwardIndexType {
}

protocol _Sequence_Type : _SequenceType {

    /// A type whose instances can produce the elements of this
    /// sequence, in order.
    typealias Generator : GeneratorType

    /// Return a *generator* over the elements of this *sequence*.  The
    /// *generator*\ 's next element is the first element of the
    /// sequence.
    ///
    /// Complexity: O(1)
    func generate() -> Generator
}

protocol GeneratorType {

    /// The type of element generated by `self`.
    typealias Element

    /// Advance to the next element and return it, or `nil` if no next
    /// element exists.
    ///
    /// Requires: `next()` has not been applied to a copy of `self`
    /// since the copy was made, and no preceding call to `self.next()`
    /// has returned `nil`.  Specific implementations of this protocol
    /// are encouraged to respond to violations of this requirement by
    /// calling `preconditionFailure("...")`.
    mutating func next() -> Element?
}

Whew. I think we’ve exhausted that rabbit hole. Now we can start building up our collection class. First, let’s create a book generator. Since the specifics of this type only need to be known to MyCollection, we’re free to create it as a private inner struct.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private struct BookGenerator: GeneratorType {
  typealias Element = Book
  
  private var books: [Book]
  private var idx = 0
  
  init(_ books: [Book]) {
      self.books = books
  }
  
  mutating func next() -> Element? {
      if idx == books.endIndex {
          return nil;
      } else {
          let obj = books[idx];
          idx++
          return obj
      }
  }
}

Fantastic. Now let’s take a look at how we’re going to adopt the _SequenceType protocol.

1
2
3
4
5
typealias Generator = GeneratorOf<Book>

func generate() -> Generator {
  return GeneratorOf(BookGenerator(books))
}

This is a bit of trickery. The GeneratorOf<Book> type is a type-erasing generator. GeneratorOf is a GeneratorType that takes a Generator on initialization. Using GeneratorOf as our generator type allows us to declare a public generate() method that returns a known type (GeneratorOf) without exposing to the world the actual Generator type we’re using.

Now, how are we going to adopt _CollectionType?

1
2
3
4
5
typealias Index = Array<Book>.Index
typealias _Element = Book
var startIndex: Index {get { return books.startIndex }}
var endIndex: Index {get { return books.endIndex }}
subscript(_i: Index) -> _Element {get { return books[_i] }}

We’re looking great! Let’s test it out.

1
2
3
4
5
6
7
var mine = MyCollection()
mine.addBook(("Wild Ducks Flying Backwards", "Tom Robbins"))
mine.addBook(("A Garfield Treasury, Vol 14", "Jim Davis"))

for book in mine {
    println(book)
}

Works great! For completeness, here’s all the code from my test playground:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import Cocoa

typealias Book = (title: String, author: String)

struct MyCollection: CollectionType {

    typealias Generator = GeneratorOf<Book>
    typealias Index = Array<Book>.Index
    typealias _Element = Book

    private let validAuthors = ["Tom Robbins", "Jim Davis"]
    private var books: [Book] = []

    var startIndex: Index {get { return books.startIndex }}
    var endIndex: Index {get { return books.endIndex }}

    private struct BookGenerator: GeneratorType {
        typealias Element = Book

        private var books: [Book]
        private var idx = 0

        init(_ books: [Book]) {
            self.books = books
        }

        mutating func next() -> Element? {
            if idx == books.endIndex {
                return nil;
            } else {
                let obj = books[idx];
                idx++
                return obj
            }
        }
    }

    mutating func addBook(book: Book) -> Bool {
        if (find(validAuthors, book.author) != nil) {
            books.append(book)
            return true
        } else {
            return false
        }
    }

    func generate() -> Generator {
        return GeneratorOf(BookGenerator(books))
    }

    subscript(_i: Index) -> _Element {get { return books[_i] }}
}

var mine = MyCollection()
mine.addBook(("Wild Ducks Flying Backwards", "Tom Robbins"))
mine.addBook(("A Garfield Treasury, Vol 14", "Jim Davis"))

for book in mine {
    println(book)
}

Creating a Homebrew Formula for a Python Project

I just finished writing a homebrew formula for a python script I wrote, I’m going to walk through how I did it. Hopefully this helps anyone else who is thinking about distributing their code.

Why did I use Homebrew and not Pip? Two reasons: first, my code requires some Java .jar files. The front end is python, but a big chuck of the code is Java, so I didn’t have any particular allegiance to Pip. Second, I think Homebrew is the most common package distribution method on OS X. Not everyone will have Pip installed, but anyone who can use my script, will have Homebrew installed (It is the easiest way to install Keybase, which I require).

As an example, I’m going to write a Formula to install my python script Switters.

First, you should push your package to Github. This will give you both a place to host your downloads and a homepage URL that you will need to add to your Formula. Homebrew requires that you version your project, so make sure your commit is tagged with a version.

You’ll need to find the download link for your repo. Checkout the Releases page on github for the download URL. It should look something like https://github.com/jkubicek/Switters/archive/0.1.2.tar.gz.

Now, run the command to create your formula.

1
brew create https://github.com/jkubicek/Switters/archive/0.1.1.tar.gz

This creates a formula at $HOMEBREW_REPOSITORY/Library/Formula/switters.rb and opens it in your text editor. If you get a warning, “Version cannot be determined from URL”, add the correct version to the formula with version '0.1.1'. You’ll also need to add your homepage. It’s fine to use the project’s Github page here.

Homebrew recomends that you explicitly add your python dependancies. For dependancies hosted on PyPI that means you’ll need to browse PyPI to find the download URL for your resource. Here’s an example resource entry for Tweetpony:

1
2
3
4
resource "tweetpony" do
  url "https://pypi.python.org/packages/source/T/TweetPony/tweetpony-1.5.0.tar.gz"
  sha1 "c6e217f2676e9980a5ad01d0da125f0e1914398a"
end

The URL is straight from the PyPI page. PyPI only gives you the MD5 hash, which is no longer recommended for Homebrew. To get the sha1 hash, use shasum.

1
2
curl -O https://pypi.python.org/packages/source/T/TweetPony/tweetpony-1.5.0.tar.gz
shasum tweetpony-1.5.0.tar.gz

Copy the resultant SHA into your forumla.

Now you’ll need to check the build system. Don’t bother with Homebrew’s interactive installation. It doesn’t run your install method, so it doesn’t let you debug the installation steps. Instead, run a regular install command with a few helpful flags. The results of the --verbose flag are obvious. The --debug flag will stop the installation on errors and give you an interactive prompt. From here you may print a stack trace or open up an IRB session. Very helpful.

1
brew install --verbose --debug switters

Take note of the SHA that Homebrew reports, you should add this to your Formula.

If everything goes well, the script should have run successfully and… nothing should have been installed. You’ve got to add the installation method.

First, let me explain the structure of my Switters project. I’ve got an executable at the top level of my project. There are two local python modules, switterslib and zxing and two Java .jars located in zxing_java. In order for everything to work, I’ve got to make sure my imports from PyPI are installed correctly and that the local resources are put in the correct spot. First, lets get our remote resources setup.

1
2
3
4
5
6
ENV.prepend_create_path "PYTHONPATH", libexec/"vendor/lib/python2.7/site-packages"
%w[tweetpony qrcode requests].each do |r|
  resource(r).stage do
  system "python", *Language::Python.setup_install_args(libexec/"vendor")
  end
end

What does this do? First, we append HOMEBREW_PREFIX+"Cellar"+name+version+"libexec/vendor/lib/python2.7/site-packages onto the PYTHONPATH environment variable. This ensures that Python will be aware of this directory and look here for the necessary modules. We’ll see how that works in a bit. Next, we iterate through our resources, create a stage environment, and call a special Homebrew python command that installs our dependancies into libexec/vendor. After installation, the actual location of these libraries will be libexec/vendor/lib/python2.7/site-packages, hence the environment variable we set as our first step.

1
2
3
4
ENV.prepend_create_path "PYTHONPATH", libexec
libexec.install Dir["switterslib"]
libexec.install Dir["zxing"]
libexec.install Dir["zxing_java"]

Here, we append the raw libexec path onto PYTHONPATH and copy the switterslib, zxing and zxing_java directories into it. This ensures that when our formula is installed, our python script can find these packages.

1
2
bin.install "switters"
bin.env_script_all_files(libexec/"bin", :PYTHONPATH => ENV["PYTHONPATH"])

Finally, we install our script into the bin directory and run the env_script_all_files command on everything in the bin directory. This creates a shell script that sets up our python environment (hence having to add specific directories into PYTHONPATH) and calls each script in the bin directory. This script is located in the HOMEBREW_PREFIX+"Cellar"+name+version+"/bin" dir. Everything in this directory is then symlinked into /usr/local/bin/ which is (hopefully) in your PATH and now you’ll be able to call the script from anywhere!

I’m Learning Android Dev

It’s about time I took a look and saw how the other half lived. I’m learning Android development. I bought the BNR Android book and have started working my way through the chapters. Keeping in mind I’ve only been doing this for two or three days, here are my thoughts:

  • Big Nerd Ranch writes exceptional books.
  • The Android Emulator is slow. It’s like DMV slow.
  • I’ve spent a surprising amount of time cleaning builds and restarting Eclipse and the emulator. I wouldn’t expect to get into that kind of debugging so quickly, especially on such a simple project. And while I’m complaining about Eclipse, non of their image assets are Retina. Since this is the only non-retina app I’ve used in a while, the appearance is strikingly bad.
  • String handling in Android is much better than in iOS. Has anyone written anything similar for iOS? Checking the googles…
  • I haven’t used Java since 2006 or 2007. It was surprisingly easy to pick back up.

I realize that my complaints about Eclipse and the emulator can be fixed by switching to a different IDE and using alternate emulators, but I’m making a conscious effort to learn the official way to develop Android apps before I strike out on my own and customize my own environment.

Waterfield Designs Staad Backback

Just a few weeks ago Waterfield Designs released their first pack, the Staad Backback. Strangely enough, every review I’ve seen is just a regurgitation of the press release and the product page, so I thought I’d give a little write-up after actually handling the pack.

First, my current backpack is the Tom Bihn Smart Alec. This is the best backpack I have ever owned. It’s comfortable, it’s durable, it’s sufficiently waterproof to ride my bike to work in a downpour. It has the most usable pocket system I’ve ever seen in a backpack. It’s also a bit big for what I need day-to-day, so I’ve been casually browsing around for a something smaller to get me back and forth to work.

After seeing my at the Staad, I decided to go with the waxed canvas, chocolate leather slim version of the bag. I went back and forth on the sizing, but I currently have a 13” laptop and a bag big enough to haul groceries in, so if I’m going to buy a new bag I might as well go with the smallest bag that’s useful.

First Impressions

As I write this, I have just recived the pack, so I don’t have any real usage notes to report. Here are my first impressions; things that I was wondering about, I’ve seen people ask about or details that surprise me.

The buckle is not vintage. Every review I’ve read mentions the “vintage” buckle. I think what they mean is it is a “vintage style” buckle. The buckle itself is brand-new and plastic. That being said, it’s an interesting buckle. If you watch Gary’s video notice how smoothly he opens the flap. It really is that smooth. The video glosses over the closing action a bit and makes it hard to see the exact mechanism for closing the bag. When you want to close the bag, you push the main tab down, then manipulate the small plastic bit through the slot. On a brand new Staad this is easy, as the stiffness of the webbing and the leather tab keeps everything in place and ready to close. I’m interested to see how this changes as the bag ages and everything breaks in.

Here are some animations illustrating the opening and closing action:

opening the clasp closing the clasp

This clasp is fun to operate. It is one of the most satisfying closures I’ve used, rivaling the feeling you get when you rip open the fly on old broken-in button fly jeans.

The outside pockets are small, best suited to thin objects. I’ve got medium sized hands, the pockets are almost the exact size of my hands. Too small for a Moleskine, just right for Field Notes. You aren’t going be fitting a water bottle in here. These pockets are best suited for small items, earbuds, wallets, notebooks, gum, etc. Because of the stiffness of the waxed canvas, the pockets don’t stretch or deform, so you aren’t going to be able to cram a lot of stuff in there even if you wanted to.

I didn’t notice this in any images or descriptions, but the laptop and iPad pockets have a very nice fleece lining. The iPod pocket is thin, just big enough for a bare iPad (I couldn’t put my iPad mini + cover in the pocket without the cover sliding off).

I had two bottles of wine in the house. Both fit into the main compartment easily and I think I could have fit a third in there. This assumes that none of the other pockets have anything bulky in them. The pocket tapers towards the top, so putting the wine in requires unzipping the zipper. Once zipped it is fairly secure and the wine doesn’t fall out even when the bag is inverted. There’s no way you could fit a six-pack without taking the bottles out of the carrier.

The main compartment won’t fit anything much bigger than a long-sleeved t-shirt. Pack light.

The underside of the flap is black leather.

Zipper pulls are generic plastic pulls. They’re fine, same pulls my Tom Bihn bag uses. I wish bag makers like Waterfield Designs and Tom Bihn would use something a little nicer, though.

Laptop sleeve ends about 2 inches above the bottom of the bag. You’d have to set the bag down very hard to have the laptop bump.

The interior pockets close with Velcro, but it’s a nice Velcro. The loop part is tight, the hook part is not rough or scratchy; it’s almost smooth. The pockets are not deep. A Field Notes notebook sticks up enough that the velcro closure cannot close.

This is probably obvious to everyone considering this bag, but it’s worth being explicit: this bag is going to get a worn look very quickly. The leather flap already has scratches on it from me opening and closing the clasp. The waxed canvas has some scuffs. Anyone considering buying this bag probably desires the broken-in look, but if you like your gear to keep looking pristine, this is likely not the bag for you.

Amend Files to Previous Commit

I run into this frequently when doing big a big refactor. I’m carefully committing my changes in nice bisectable units, but then Woah! there’s a change that should be included in a previous commit. Here’s how you fix this up in Git.

Disclaimer: We are modifying Git history. Do not do this if you have already pushed these changes.

$ git log --oneline

39e1678 Removed allowsAirPlayVideo method
6c750a1 Removed UILineBreak enums
ce2c34f Removed all UITextAlignment enums
a5c04ad Remove dispatch_release() calls
8681487 Removed Refresh Header

There we go. My current changes should be included in commit 8681487, “Removed Refresh Header”. Fixing this is easy. Add your changes to the staging area, then run:

git commit --fixup=8681487
git rebase --interactive --autosquash 8681487~1

The first command commits your changes, but modifies the commit message to be the same as 8681487 with “fixup!” appended in front. Running rebase in interactive mode with “autosquash” turned on will move our previous commit right after the commit we’d like to modify and update that commit with our new changes.

Easy as pie!

Debugging Smashed Memory in Obj-C

We were getting a crash inside a button. Calling po self wasn’t helpful.

(lldb) po self
$1 = 0x0ce854d0 [no Objective-C description available]

Well.. That’s weird. I wonder what’s at that memory location?

(lldb) memory read 0x0ce854d0
0x0ce854d0: 00 00 00 b0 93 6a ce a0 0e 00 00 00 00 00 00 00  .....j..........
0x0ce854e0: 10 c7 e7 0c 00 00 00 00 00 00 00 00 00 00 00 00  ................

That… doesn’t look right. Let’s turn on some debugging tools and see if that helps. Open the ‘Edit Scheme’ window and navigate to the Diagnostics tab. You’ll want to turn on “Enable Scribble” and “Malloc Stack”. You can read more about these methods here, but in short, “Enabled Scribble” will cause the allocator to write 0xAA to newly allocated memory and write 0x55 to deallocated memory. “Malloc Stack” will log the allocation and free history of your memory.

debugging settings

Let’s get our app to crash again and see if that helped.

(lldb) po self
$1 = 0x0cdcd2d0 [no Objective-C description available]
(lldb) memory read 0x0cdcd2d0
0x0cdcd2d0: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55  UUUUUUUUUUUUUUUU
0x0cdcd2e0: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55  UUUUUUUUUUUUUUUU

Well, there we go. Obviously someone else is freeing self while we’re in the middle of a method. Let’s grab the PID of our crashing process. Easiest way to get this from an iOS app is to check out any log statements in the terminal.

2013-04-22 10:59:38.194 Sing![14105:2203] Loggin'
                           PID^^^^^

Mosey on over to your trusty terminal and let’s see what’s happening at that memory address.

$ malloc_history 14105 0x0cdcd2d0

This is going to fill your screen with a massive spew of text. You’ll probably want to pipe the results to your text editor of choice. The important bits are right there at the top, though. Check it out:

ALLOC ... 
----
FREE  0xcdcd2d0-0xcdcd3a7 ... CFRunLoopTimerInvalidate | _timerRelease | ... -[SongPreviewButton dealloc] ... free 

About 100 lines of junk omitted. But there you go. We’ve got a timer that’s holding on to a button, preventing it from being freed when it should be, then all of a sudden the timer lets go and everything falls apart. Simple!

List Rake Tasks by Default

I add this to all my Rakefiles.

1
2
3
task :default do
  system "rake --tasks"
end

It prints a list of Rake tasks when you run Rake without a command. Not only does it help you remember what options are available in the current project, but it keeps you from accidentally performing some task if you fat-finger the rake command.

Unit Testing Parse Cloud Code

Like many people, I was thrilled when Parse announced their cloud code product. I’ve just started a little iOS project that required both persistent cloud storage and pulling data from a 3rd party API. Since the API had a great JavaScript library, but no built-in Obj-C support, moving the code onto the server had some big benefits: greatly simplified networking in iOS, allowed me to reuse the 3rd party library as is, and decreases my turnaround time should I need to modify this code in the future.

Now, I’m usually not a strict test driven developer, but these cloud code modules are a different story; the code is running on a server and accessing a 3rd party API. In this situation, quick build/test/debug cycles are impossible and testing is the only way go.

Here’s how I set up my testing environment. Please keep in mind that this is the first time I’ve used Node.js, first time I’ve written unit tests for JavaScript and the first real JS project I’ve worked on. In fact, before this, the only JS code I’d written was hackly little Safari extensions, so this is a whole new world for me. I’m writing this for someone with experience similar to mine; if you are experienced with Node, feel free to skip ahead.

Setting up the test environment

I assume you’ve already got Node and npm installed. If you don’t, they both can be installed via Homebrew.

I used Mocha.js for the testing framework and Expect.js for assertions. Mocha supports any assertion framework you can throw at it. Expect seems to work well and doesn’t generate Lint warnings like Should.js. Run the following commands from your project directory.

$ npm install mocha
$ npm install expect.js

These commands install the mocha and expect frameworks in the local node_modules directory. This greatly simplifies your environment. Code can be shared between collaborators without worrying about what framework version each dev has installed.

At this point, your Parse directory should look like this:

cloud /
  main.js
config /
  global.json
node_modules /
  .bin /
  mocha /
  expect /

Creating Cloud Code Modules

We’re all set to test, but first we need something to test. We’re going to add some code that just returns a helpful message. Modify main.js to look like so:

1
2
3
4
5
var message = require('cloud/message.js');

Parse.Cloud.define("get_message", function (request, response) {
  message.getMessage(request, response);
});

What I’ve done is load each Cloud Code function from a separate module, this worked well for me because each function is independent of all other functions, but YMMV. Let’s setup some code to test. First, create a file named message.js in your cloud directory. Now modify it to look like so.

1
2
3
exports.getMessage = function (request, response) {
  response.success("Good job, buddy");
};

A bit about how Node.js loads modules, since this was all new to me. When each module is loaded, there is an object created called exports that is available within that module. Any function attached to that object will be available externally when your module is loaded. So in this example, our message module creates one function called getMessage. When we call var message = require('cloud/message.js'); the object returned from the require() function is that exports object.

Creating Tests

Now let’s create some tests. First, the default directory for Mocha tests is test, so let’s put our test there. Create the test directory and put a file in there named, “messageTests.js”. Modify it to look like this:

1
2
3
4
5
6
7
8
9
10
var message = require('../cloud/message.js');
var expect = require("expect.js");

describe('Message', function () {
  describe('response', function () {
      it('should return the correct message', function () {
          expect().fail("No tests yet");
      });
  });
});

First we import our message and expect modules. The describe() function is used to define the scope for associated tests. The it() function defines a Mocha test. Let’s run our test.

$ node_modules/.bin/mocha 

Notice that the error message says, “Message response should return the correct message:”, so structure your describe and it messages to make that message nice and readable. Let’s replace our failing test with an actual tests.

1
2
3
4
5
6
7
8
it('should return the correct message', function (done) {
  message.getMessage({}, {
      success : function (message) {
          done();
          expect(message).to.be.eql("Good job, buddy");
      }
  });
});

There’s a few things to notice here. First, the done() function is an optional parameter to the describe() and it() methods. Any tests within will not complete successfully until the done() function is called, so you can use it to test callbacks and ensure that they were called. Second, notice the format of the expect() function. You can read the documentation for more details, but in general, the tests always follow this form, beginning with an expect() function and ending with a function.

Run the tests again and success! All our tests pass. All in all, it took me less than a day to try out different testing and exception modules, settle on Mocha and Expect, then write enough tests to nearly fully cover the Cloud Code I had written. Coming from Objective-C, the power and flexibility of JavaScript amazes me. Writing these tests was almost a joy.

JSLint: Expected ‘Return’ at Column X, Not Column Y

I’ve been writing some Javascript using the default settings in Chocolat, tabs instead of spaces and each tab is equivalent to 2 spaces. Running most of my javascript files through JSLint is fine, but there were a few lines that were generating warnings, even though the spacing looked just fine.

if (validateCardRequestDidSucceed(stripeResponse) === false) {
    response.error("Stripe card request failed with unknown error");
    return; // Expected 'return' at column 17, not column 19.
}

What’s wrong here? That spacing looks just fine to me. Turns out that the default settings in JSLint want spaces instead of tabs and 4 spaces per indentation. JSLint, by default, ignores tabbed indentation, but somehow that return had been indented with spaces.

Replacing the spaces with tabs cleared up the issue.

In other news, I should probably switch to 4-space indentation. I’m not picky about spacing and, all things being equal, I might as well stick with the JSLint conventions.

When isKindOfClass Is Not Kind of Class?

I’ve been running into an issue over the past few days where [objA isKindOfClass:[ClassA class]] is returning false when clearly objA is a kind of ClassA. I’m running these tests using SenTesting kit and I’m not compiling the .m files in my test target, which is the only issue that StackOverflow suggests.

I am including my Storyboards in my testing target. Perhaps that’s the problem? Let me just remove those Storyboards from the testing target…

BOOM. That was it.

Also, for future reference, in case anyone finds their way here while looking for how to load storyboards in a SenTestingKit test target, here’s how:

1
2
3
NSBundle *mainBundle = [NSBundle bundleForClass:[self class]];
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:name bundle:mainBundle];
viewController = [storyBoard instantiateViewControllerWithIdentifier:MainViewController];