Enumerating results from an asynchronous network call in Objective-C

| Comments

I have a facade over an asynchronous network call—that also performs pagination, ie multiple network calls in order to handle very large result sets—along the lines of this but I now want to use it in a context where knowing when it’s finished iterating is important (e.g in an NSOperation):

1
2
3
4
5
[myClient enumerateFoosAtURL:URL usingBlock:^(id foo, BOOL *stop) {
  ...
} failure:^(NSError *error) {
  ...
}];

The simplest thing might be to add an extra block but that is so sucky I nearly vomited in my mouth just typing out the example below:

1
2
3
4
5
6
7
[myClient enumerateFoosAtURL:URL usingBlock:^(id foo, BOOL *stop) {
  ...
} success:^{
  // we're done
} failure:^(NSError *error) {
  ...
}];

A less sucky option might be to indicate if there are more to come:

1
2
3
4
5
6
7
8
[myClient enumerateFoosAtURL:URL usingBlock:^(id foo, BOOL more, BOOL *stop) {
  ...
  if (!more) {
    // we're done
  }
} failure:^(NSError *error) {
  ...
}];

Yet another option that I think I like the most might be to simply transform the semantics of the original into this:

1
2
3
4
5
6
7
8
9
10
[myClient enumerateFoosAtURL:URL usingBlock:^(id foo, BOOL *stop) {
  ...
} finished:^(NSError *error) {
  if (error) {
    // an error occurred
  } else {
    // we're done
    ...
  }
}];

Update Tony Wallace suggested that he prefered the

“less sucky option” because it makes it more obvious that the method returns paginated results.

And I have to say I agree with him on that. The only fly in the oitment however, turns out to be some filtering performed within the API methods which meant that determining if there were more results would have required some fancy look-ahead code.

In the end I went with my last option. It seems to have worked out rather painlessly :)

Site44.com deploy task for Octopress

| Comments

Further to my previous post, I also added a rake task to my Rakefile that uses rsync to deploy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
rsync_delete   = false
deploy_default = "local"

# snip

desc "Deploy website via local rsync"
task :local do
  exclude = ""
  if File.exists?('./rsync-exclude')
    exclude = "--exclude-from '#{File.expand_path('./rsync-exclude')}'"
  end
  puts "## Deploying website via local rsync"
  ok_failed system("rsync -avz #{exclude} #{"--delete" unless rsync_delete == false} #{public_dir}/ #{deploy_dir}")
end

I initally thought it would be pretty neat to work out the local website location in Dropbox but in the end I decided it was simpler to just leave the deploy_dir variable set to the default "_deploy" and have that directory symlinked to the approproprate Dropbox folder.

Generate a site44.com redirects file for your Octopress blog

| Comments

Over the weekend I converted my, albeit languishing blog from straight Jekyll on GitHub Pages to use Octopress served via Site44.

In the process I also took the opportunity to switch the URLs I was using for blog entries to the Octopress default. This in turn left me needing a bunch of redirects.

Site44 supports redirects via a well-known text file in the root of your website. The text file provides a mapping between source and destination paths. That’s all very well and good but I didn’t much feel like creating 300+ redirect mappings by hand. Besides the tedious nature of the task, the chances I was going to screw one or more of them up in the process were fairly high.

Thankfully, due to a previous blog move, I happened to have a bunch of permalink definitions in the front-matter of most of my blog entries. All I really needed then was a way to turn those into said text file.

A quick Google turned up the Alias Generator plugin for Octopress by Thomas Mango which was very close to, but not quite what I needed.

Hack hack hack on the plugin, a quick rename of all the permalink attributes in my posts to alias, and voila! a new plugin that generates a redirects.site44.txt with all my redirects:

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
61
62
63
64
65
66
67
68
69
70
71
72
73
# Site 44 Redirects Text Generator for Posts.
#
# Generates a www.site44.com compatible redirects file pages for posts with aliases set in the YAML Front Matter.
#
# Place the full path of the alias (place to redirect from) inside the
# destination post's YAML Front Matter. One or more aliases may be given.
#
# Example Post Configuration:
#
#   ---
#     layout: post
#     title: "How I Keep Limited Pressing Running"
#     alias: /post/6301645915/how-i-keep-limited-pressing-running/index.html
#   ---
#
# Example Post Configuration:
#
#   ---
#     layout: post
#     title: "How I Keep Limited Pressing Running"
#     alias: [/first-alias/index.html, /second-alias/index.html]
#   ---
#
# Author: Simon Harris
# Site: http://harukizaemon.com

module Jekyll
  REDIRECTS_SITE44_TXT_FILE_NAME = "redirects.site44.txt"

  class RedirectsSite44TxtFile < StaticFile
    def write(dest)
      begin
        super(dest)
      rescue
      end

      true
    end
  end

  class RedirectsSite44TxtGenerator < Generator
    def generate(site)
      unless File.exists?(site.dest)
        FileUtils.mkdir_p(site.dest)
      end

      File.open(File.join(site.dest, REDIRECTS_SITE44_TXT_FILE_NAME), "w") do |file|
        process_posts(site, file)
        process_pages(site, file)
      end

      site.static_files << Jekyll::RedirectsSite44TxtFile.new(site, site.dest, "/", REDIRECTS_SITE44_TXT_FILE_NAME)
    end

    def process_posts(site, file)
      site.posts.each do |post|
        generate_aliases(file, post.url, post.data['alias'])
      end
    end

    def process_pages(site, file)
      site.pages.each do |page|
        generate_aliases(file, page.destination('').gsub(/index\.(html|htm)$/, ''), page.data['alias'])
      end
    end

    def generate_aliases(file, destination_path, aliases)
      Array(aliases).compact.each do |alias_path|
        file.puts("#{alias_path} #{destination_path}")
      end
    end
  end
end

What a week

| Comments

Six days ago, my extraordinary wife Jess gave birth to our third and final (yes, really!) child at home, a beautiful boy with a working title where his name shall shortly, hopefully, be.

Two days ago, I turned 40.

Today, I finally shipped my first iPhone app, Readtime, that I have been working on sporadically for a few months now with Benjamin Birnbaum and Ben Green, and the support of the Cogent folk.

I wish I had something pithy to end with but I don’t. I’m mostly just sitting here, wired, reflecting on what a crazy time it’s been, how utterly fortunate I am to have the life that I do, and hoping that by writing it all down, I might finally get to sleep. I think it’s worked :)

Update: Our son has a name: George Samuel Harris.