Cocoa Factory

Industrial strength software for iOS and Mac

Auto-incrementing Xcode Build Numbers

There are as many schemes for versioning of Xcode projects as there are developers. One of the difficulties, of course, is the way that Xcode labels the two version identifiers in the IDE. First, there’s CFBundleShortVersionString which according the documentation is:

“the release version number of the bundle which identifies a released iteration of the app. The release version number is a string comprised of three period-separated integers. The first integer represents major revisions to the app, such as revisions that implement new features or major changes. The second integer denotes revisions that implement less prominent features. The third integer represents maintenance releases.”

This differs from CFBundleVersion which is:

“the build version number of the bundle, which identifies an iteration (released or unreleased) of the bundle. The build version number should be a string comprised of three non-negative, period-separated integers with the first integer being greater than zero.”

Importantly, Apple uses CFBundleVersion to version your app and CFBundleShortVersionString to present the version to the user. So, on submission, the CFBundleVersion must be higher than the last version submitted. That’s why I use the following script to auto-increment the CFBundleVersion every time I build the source:

1
2
3
4
#!/bin/bash
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

When I setup a new project, this script is one of the build phases.

Organizing Developer Reference Materials

Like every other developer, I lookup information, API’s, blog posts every day. Recently, I was inspired to change that way that I accumulate all of this data. Since I’m a long-term DEVONthink user. I decided to harness some of is power to organize my reference materials. Here’s how I went about organizing everything and why.

Make a committment to keeping everything in one place

As I started this process, I was trying to solve two problems:

  • I wanted to be able to find developer-related information that was important to me.
  • I wanted to control the data - meaning I wanted to have the data stored locally.
  • I wanted to be able to find information again without having to reconstruct the Google search that found it in the first place. Sometimes, you find interesting material only after a circuitous search. It’s hard to remember those pathways and they are dynamic. Further, I’m in the process of designing and building an office out in the country where web access is harder.

These goals are best met by ensuring there’s a place for everything go. In my case, I keep a single DEVONThink database called dev for this. I have others where I keep personal data, hobby-related information, etc.

Gather everything

I started by adopting the GTD approach of gathering everything in one place. In this case, it meant grabbing references from Dropbox, from Evernote, and a bunch of other places and dropping them in a virgin DEVONthink database. I’ve used DEVONthink for years - long before Evernote and the majority of my reference materials were already there; so the workflow was already somewhat familiar to me. After ongoing mental debates about the merits of DEVONthink (DT) vs Evernote, I’ve finally come down on the side of DT. Although I like the accessibility of Evernote, with DT, the security of the data, its format, and location are all known to me. It’s certainly not as ubiquitous as Evernote; but DT syncing is getting better. Nonetheless, I’m sure everything about this workflow is doable in Evernote, too.

Whatever tool you use, gather everything means exactly that - find a software home that can keep everything you need and put it there. And classify it.

In what form do I save my data? It depends. Basically, I favor plain text > right text > pdf. I save a lot of web pages for offline reference. It’s easy to use the Safari DT plugin to generate paginated PDF content. That said, sometimes I’ll capture rich text from the Reader version of the page and save that.

Setup a basic group structure

Figure 1 DEVONthink groupsFigure 1 DEVONthink groups The top-level entity in DT is the database, followed by Groups. I created a single group called “references” and sub-groups by letters “A” to “Z”. Each letter gets alphabetic topics. Figure 1 shows my current “C” group expanded to show subgroups. As an example, note that although the “core data” group has only three items in it. There are other locations where there may be other entries about Core Data, e.g. NSManagedObjectContext may have its own group. We’ll get to tagging and search next. The group structure is arbitrary because as you get better at tagging, the latter becomes the main way of finding things. While I have a file-system bias, groups are becoming less-used because of the power of tag-based search.

Setup and maintain a hierarchical tagging structure

Figure 2 Top-level tagsFigure 2 Top-level tags Tags are an orthogonal way of finding information in DT. Although you go drill-down the group hierarchy if you wanted (in a manner analogous to the file system), tags look orthogonally across the data. And the better and more consistent you are with tagging, the better your searches become. An important feature of DT tags is that they are hierarchical as I discovered here. I spent a long while coming up with a concise hierarchy for my data which is shown in Figure 2.

Since the tag hierarchy is what’s important to this system, I’ll briefly explain what each top-level item is:

  • language Since many of my entities contain code, I wanted to be able to find items by language.
  • main_areas This holds all of the - well, main areas.
  • people I tag posts that are attributable to a particular author here. The format of the tag is like people_fnln or people_alanduncan.
  • platforms e.g. platform_apple_ios
  • source Where did the entity come from?
  • status Is the item read or not?
  • use_type Why was the item saved? e.g. use_type_reference or use_type_tutorial

The beauty of hierarchical tags is that by clicking on any level of the hierarchy you can see everything in that branch. Surprisingly useful.

Use tags to advantage

Figure 3 Tag hierarchiesFigure 3 Tag hierarchies Since tags are key to finding content in my databases, I treat them with a lot of care, adding layers of specificity where it makes sense and pruning others. Figure 3 shows one of my main_areas - topic_workflow fully expanded to show the hierarchy. One of the neat things that you can do with DT tags is dragging documents between tags. By doing this, you can add a new tag to a document. If you delete a document from a tag’s list, you remove that tag from the document.

Frequently Given Answers

What about mobile access?

DEVONthink has an iOS version. I couldn’t really make use of it. Instead, the desktop version of DT Pro Office runs an embedded web server. I expose that on the WAN. Works for me.

What else do you find useful?

DT allows you to hyperlink content. This is useful to me in the following way: let’s assume that I’ve been working on figuring out how to do something. I’ve got a handful of tabs open in Safari with pages that helped me accomplish the task. When I’ve finished, I’d like to write up a summary so that if I have to do it again, I can refer to it. In DT, I’d just import all of the pages as PDFs and hyperlink them into a rich-text document. In a way, it’s like developing your own very highly tailored version of the web.

Why don’t you use just use Evernote?

I like Evernote. A lot. But I really admire DEVONthink’s scriptability, the way its hyperlinking works and the fact that the data is on my machine. In the end, it works for me.

App Version Icon Overlays: The Mac Edition

If you haven’t heard yet, the fifth iteration of NSConference was awesome. Lots of great talks, meeting other developers, and of course, sunny Leicester, UK.

Fig 1. Stamped iconFig 1. Stamped icon Among the great talks was Evan Doll’s about how Flipboard makes use of the development toolchain in novel ways to make their process more efficient and less error-prone. Krzysztof Zablocki has written up a great description on his implementation of Evan’s idea. It works really well for iOS. It’s such a neat trick, that I thought I’d build on it for Mac OS. Turns out that core process is almost the same as Krzysztof’s; but with some twists.

Read on for more about how I implemented Mac icon overlays.

Introducing CCFScrollingTabBar

We’re pleased to announce the release of a new open source control called CCFScrollingTabBar, a refined scrolling control for iPhone. You can find it on github here.

It’s a little like JSScrollableTabBar with completely customizable colors. Rather than just talk about it, here’s what it looks like: For the developer, this is a simple component to use. Just provide the instance of CCFScrollableTabView with the colors for the gradient background and text, and the titles of the tabs, and we take care of the rest. You can receive delegate messages when the use taps on an item. We setup a simple example project to see it in action.

Using CCFScrollingTabBar in a nutshell

Our example project uses a scrolling tab bar instantiated in a nib. It should be exactly 41 pixels high. Your instance of CCFScrollingTabView should have a delegate and a data source. Without a data source you would see nothing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma mark - CCFScrollableTabViewDataSource


- (UIColor *)textColorInScrollableTabView:(CCFScrollableTabView *)tabView {
    return [UIColor whiteColor];
}

- (UIColor *)darkColorInScrollableTabView:(CCFScrollableTabView *)tabView {
    return [UIColor colorWithRed:0.0706f green:0.1529f blue:0.4235f alpha:1.0f];
}

- (UIColor *)lightColorInScrollableTabView:(CCFScrollableTabView *)tabView {
    return [UIColor colorWithRed:0.258f green:0.639f blue:0.890f alpha:1.0f];
}

- (NSArray *)titlesInScrollableTabView:(CCFScrollableTabView *)tabView {
    return [NSArray arrayWithObjects:@"Afrikaans",@"Basque",@"Catalan",@"Croatian",@"Danish",@"English",@"French",@"German",@"Hungarian", nil];
}

That’s it! If you want to know when the user taps on an item, you should implement the scrollableTabView:didSelectItemAtIndex: method on the CCFScrollableTabViewDelegate protocol. That way your class will get a message with the index of the selection.

Comments, questions? Contact Alan at @NSBum

Troubleshooting Cocoapods Installation

CocoaPods is a popular new way to manage dependencies in Xcode projects.

Canonical installation

CocoaPods is installed as a ruby gem; and usually everything ‘just works.’ Here’s how you install CocoaPods:

1
$ sudo gem install cocoapods

If everything works properly, you should see something like this:

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
Fetching: i18n-0.6.1.gem (100%)
Fetching: multi_json-1.5.0.gem (100%)
Fetching: activesupport-3.2.11.gem (100%)
Fetching: colored-1.2.gem (100%)
Fetching: xcodeproj-0.4.2.gem (100%)
Building native extensions.  This could take a while...
Fetching: multipart-post-1.1.5.gem (100%)
Fetching: faraday-0.8.4.gem (100%)
Fetching: addressable-2.3.2.gem (100%)
Fetching: faraday_middleware-0.9.0.gem (100%)
Fetching: hashie-1.2.0.gem (100%)
Fetching: netrc-0.7.7.gem (100%)
Fetching: octokit-1.22.0.gem (100%)
Fetching: escape-0.0.4.gem (100%)
Fetching: json-1.7.6.gem (100%)
Building native extensions.  This could take a while...
Fetching: open4-1.3.0.gem (100%)
Fetching: rake-0.9.6.gem (100%)
Fetching: cocoapods-0.16.1.gem (100%)
Successfully installed i18n-0.6.1
Successfully installed multi_json-1.5.0
Successfully installed activesupport-3.2.11
Successfully installed colored-1.2
Successfully installed xcodeproj-0.4.2
Successfully installed multipart-post-1.1.5
Successfully installed faraday-0.8.4
Successfully installed addressable-2.3.2
Successfully installed faraday_middleware-0.9.0
Successfully installed hashie-1.2.0
Successfully installed netrc-0.7.7
Successfully installed octokit-1.22.0
Successfully installed escape-0.0.4
Successfully installed json-1.7.6
Successfully installed open4-1.3.0
Successfully installed rake-0.9.6
Successfully installed cocoapods-0.16.1
17 gems installed
Installing ri documentation for i18n-0.6.1...
Installing ri documentation for multi_json-1.5.0...
Installing ri documentation for activesupport-3.2.11...
Installing ri documentation for colored-1.2...
Installing ri documentation for xcodeproj-0.4.2...
Installing ri documentation for multipart-post-1.1.5...
Installing ri documentation for faraday-0.8.4...
Installing ri documentation for addressable-2.3.2...
Installing ri documentation for faraday_middleware-0.9.0...
Installing ri documentation for hashie-1.2.0...
Installing ri documentation for netrc-0.7.7...
Installing ri documentation for octokit-1.22.0...
Installing ri documentation for escape-0.0.4...
Installing ri documentation for json-1.7.6...
Installing ri documentation for open4-1.3.0...
Installing ri documentation for rake-0.9.6...
Installing ri documentation for cocoapods-0.16.1...
Installing RDoc documentation for i18n-0.6.1...
Installing RDoc documentation for multi_json-1.5.0...
Installing RDoc documentation for activesupport-3.2.11...
Installing RDoc documentation for colored-1.2...
Installing RDoc documentation for xcodeproj-0.4.2...
Installing RDoc documentation for multipart-post-1.1.5...
Installing RDoc documentation for faraday-0.8.4...
Installing RDoc documentation for addressable-2.3.2...
Installing RDoc documentation for faraday_middleware-0.9.0...
Installing RDoc documentation for hashie-1.2.0...
Installing RDoc documentation for netrc-0.7.7...
Installing RDoc documentation for octokit-1.22.0...
Installing RDoc documentation for escape-0.0.4...
Installing RDoc documentation for json-1.7.6...
Installing RDoc documentation for open4-1.3.0...
Installing RDoc documentation for rake-0.9.6...
Installing RDoc documentation for cocoapods-0.16.1...

Failed installation

However, CocoaPods installation can fail for a number of reasons. Here are a few things to check if the installation fails:

  • Have you installed the Xcode command line tools? If you update Xcode, then you need to re-download the command line tools. This is a common gotcha.

  • Are you using MacRuby? MacRuby is not supported. Your ruby should be Ruby MRI 1.8.7 or 1.9.3

Errors during installation

Our initial attempt with sudo gem install cocoapods gave the following error:

1
2
3
4
5
6
7
/usr/local/lib/ruby/1.9.1/yaml.rb:56:in `<top (required)>':
It seems your ruby installation is missing psych (for YAML output).
To eliminate this warning, please install libyaml and reinstall your ruby.
ERROR:  Loading command: install (LoadError)
    cannot load such file -- zlib
ERROR:  While executing gem ... (NameError)
    uninitialized constant Gem::Commands::InstallCommand

First, we tried to just install the libyaml package with rvm pkg install libyaml but this got us nowhere. Same error when we try to sudo gem install cocoapods.

Since we weren’t using ruby for anything else on the system, blowing away RVM seemed like a benign (if nuclear) option. So we used rvm implode and removed all references to .rvm in our PATH. You need to also take a look at .bashrc .profile and .bash_profile for other references to rvm if you want to try this option. See the accepted answer to this question for details on the nuclear option for removing rvm.

Next we reinstalled rvm:

1
curl -L https://get.rvm.io | bash -s stable --ruby

This installs rvm and the latest stable version of ruby. Next update the terminal and check the version of ruby in use:

1
2
Darwin:~ alan$ source /usr/local/rvm/scripts/rvm
Darwin:~ alan$ which ruby

Hmmm….we’re still using the system ruby. Let’s see what ruby versions we have:

1
2
3
4
5
6
7
8
Darwin:~ alan$ rvm list

A RVM version 1.18.5 (stable) is installed yet 1.15.7 (stable) is loaded.
Please do one of the following:
  * 'rvm reload'
  * open a new shell
  * 'echo rvm_auto_reload_flag=1 >> ~/.rvmrc' # for auto reload with msg.
  * 'echo rvm_auto_reload_flag=2 >> ~/.rvmrc' # for silent auto reload.

So, let’s do as it says and reload:

1
2
3
4
5
6
7
8
9
10
11
12
Darwin:~ alan$ rvm reload
RVM reloaded!
Darwin:~ alan$ rvm list

rvm rubies

   ruby-1.9.3-p194 [ x86_64 ]
=* ruby-1.9.3-p374 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

Now we can confirm the ruby version in use:

1
2
Darwin:~ alan$ which ruby
/usr/local/rvm/rubies/ruby-1.9.3-p374/bin/ruby

So we should be good to go. Let’s try installing CocoaPods again:

1
2
3
4
5
6
7
Darwin:~ alan$ sudo gem install cocoapods
Fetching: i18n-0.6.1.gem (100%)
Fetching: multi_json-1.5.0.gem (100%)
Fetching: activesupport-3.2.11.gem (100%)
Fetching: colored-1.2.gem (100%)
Fetching: xcodeproj-0.4.2.gem (100%)
# many more lines follow...

Success! Now back to the canonical installation:

1
2
3
4
Darwin:~ alan$ pod setup
Setting up CocoaPods master repo
Cloning spec repo `master' from `https://github.com/CocoaPods/Specs.git' (branch `master')
Setup completed (read-only access)

“`

Conclusion

For developers with more experience dealing with ruby, its versions and dependencies, deleting rvm and reinstalling may seem like a blunt instrument. For me, this worked well and allowed us to start working with CocoaPods after a lot of earlier frustration.

Questions/comments?

I’d love to hear from you at @NSBum.

Expanding NSOutlineView at Load Time

Ran across this post on Simply Hacking that deals with the problem of expanding items in NSOutlineView when the view loads.

If you try to expand items in awakeFromNib, it will fail because the content is not prepared until after awakeFromNib is called on the controller. The key is to observe content on the NSTreeController using KVO.

LLDB Print Registers

Somes while debugging, or when you want to understand what the compiler doing with your code under the hood, you may want to print the contents of all the registers in the current frame.

To print the current register contents in LLDB it’s register read: console

Announcing RegexMatch for Mac

We’re delighted to announce our newest app - RegexMatch for Mac OS! If you use regular expressions in your development process, you’ll want to check it out. You can write and test regular expressions, then generate and export code in your language of choice.

Learn more about RegexMatch.

Do you like RegexMatch - drop us a line @CocoaFactory

Forgetting Sandbox Entitlements

I was recently prepping a Mac OS app for Sandbox compliance but couldn’t figure out why the following error: NSPOSIXErrorDomain Code=1 "The operation couldn’t be completed. Operation not permitted"

Finally it dawned on me that even simple outgoing network requests from the app, need to be specifically enabled thusly.

I wish the error were more descriptive or that the userInfo dictionary of the NSError at least had a Sandbox violation description key.

Questions or comments about this post? Contact the author of this post @NSBum.

X86_64 Assembly Language Tutorial:part 4

In Part I or our x86_64 assembly language tutorial for Mac OS, we analyzed the disassembly of a simple C program. In Part II, we extended the example and learned more about the x86_64 ABI and register usage. In Part III, we delved into the world of objects and showed what happens behind the scenes when objects meet silicon.

This time, we’ll take a break from the analytical mode to try our hand at writing a simple program in assembly. We’re going to use two different assemblers to show the range of syntactical differences.

Xcode assembly language project

Although Xcode doesn’t have an assembly language project template, you can start a new command line tool project for Mac OS and just delete the main.m file. Then you can add an assembly language file to the project and paste the following code:

Like we’ve done with each of the prior tutorials, lets walk through the code, as simple as it is, step-by-step

Step 1 - Preamble

1
2
3
.private_extern   _main
.globl  _main
_main:                                  #   main entry point

Here we’re just defining symbols for our entry point _main.

Step 2 - Save frame pointer

1
2
3
pushq    %rbp

movq   %rsp, %rbp

Now we just save the frame pointer.

Step 3 - Print a “Hello world!” string

1
2
3
4
5
6
7
8
9
leaq _helloMessage(%rip), %rdi
callq  _puts

//

.section    __TEXT,__cstring,cstring_literals

_helloMessage:
    .asciz   "Hello world!"

Here we load a reference to the _helloMessage into %rdi our first function argument register. And call _puts. The leaq instruction is the 64-bit version of lea in x86 assembly. This instruction places the address specified by the second operand into the register specified by the first operand. It’s not the contents of the memory location that are loaded, only the effective address that is computed and placed into the register. (Sounds like a pointer in higher level languages, doesn’t it?)

Step 4 - Clean up

1
2
3
xorl %eax, %eax
popq   %rbp
ret

Here we zero our function return register, pop the frame pointer, and return. That was easy!

NASM project

Next, we’re going to go through an alternative way of getting the job done with an assembler called nasm - for “netwide assembler”. It uses a very different syntax than we are accustomed to seeing from the analyses we’ve done so far. We also are responsible for building the Mach-O object code and linking the program ourselves. But it’s a good experience to go through.

Download the 64-bit version of nasm

For compatibility with our GNU assembler version of the “Hello world” program, we want to do it in 64 bit form. But the version of nasm that ships with Mac as of this writing is an older 32 bit version. You can check it our on your computer with nasm -v at the Terminal. On my machine, it is 0.98.40. We need to download the latest version before continuing. You can find it here. I just downloaded it, unzipped, and copied to /usr/bin so I wouldn’t have to deal with mofiying the path.

Write the program for use in nasm

Here’s the complete source:

The first thing to recognize with nasm syntax is that the operand order is reversed compared with the GNU assembler syntax. So the instruction mov r15, rsp moves the contents of register rsp to r15. We also omit the % sign before register names. And nasm infers the correct version of an instruction depending on the width of the operands; so we use mov instead of movb, movl, or movq. Apart from those differences, we do things the same way. Let’s go through the program step-by-step.

Step 1: Application sections

1
2
3
4
5
6
7
8
section .data

    hello            db "Hello, world!", 0

section .text

    global _main
    extern _puts

We being with a data section that contain a single symbol hello. db signifies a data block. In this case the data block is a NULL-terminated string. The 0 after the string is the NULL termination. After the .data section, we have the .text section which is the code. He expose _main - our entry point - as a global symbol and mame note that _puts is defined elsewhere and will need to be linked.

Step 2: Prologue

1
2
3
4
_main:
    push    r15             ;save %r15 to stack
    mov     r15,    rsp     ;load the stack pointer into %r15
    push    rbx             ;push base pointer to the stack

This is similar to the prologues we’ve seen before - but take a close look here at the reversed order of the operands. If you don’t understand what our function prologue is doing at this point, best go back to our earlier tutorials and review.

Step 3: Call puts

1
2
3
4
5
mov     rbx,    rsp     ;load the stack pointer into the base pointer
and     spl,    0xF0    ;align the stack pointer on a boundary

mov     rdi,    hello   ;move address of string to %rdi (1st function arg register)
call    _puts           ;call puts

The first two instructions have the effect of aligning the stack pointer to a 16 byte boundary as required by the x86_64 ABI before the upcoming call. Then we move the address of the symbol hello to the %rdi register (the first function argument register) and call _puts.

Step 4: Cleanup

1
2
3
4
5
6
mov     rsp,    rbx     ;mov %rbx back into stack pointer after the library call

pop     rbx             ;restore %rbx (a callee saved register)
mov     rsp,    r15     ;restore the stack pointer from %r15
pop     r15             ;restore %r15
ret

All that’s left is to clean up, restoring the registers and the stack before returning.

"Build, link, run"

Build

But the program text file isn’t useful by itself. Save it to disk as “hello64.asm”. Now we need to generate the object code. You will need to adjust the path names but on my machine, it’s: nasm-2.09.10 -f macho64 hello64.asm to generate the 64-bit Mach-O object code and gcc -m64 -mmacosx-version-min=10.6 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk -o hello64 hello64.o to link it.

Now to run our little application, from the directory where it resides: /.hello64.

Questions or comments about this post? Contact the author of this post @NSBum.