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:
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 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 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 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.
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 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.
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.
123456789101112131415161718
#pragma mark - CCFScrollableTabViewDataSource-(UIColor*)textColorInScrollableTabView:(CCFScrollableTabView*)tabView{return[UIColorwhiteColor];}-(UIColor*)darkColorInScrollableTabView:(CCFScrollableTabView*)tabView{return[UIColorcolorWithRed:0.0706fgreen:0.1529fblue:0.4235falpha:1.0f];}-(UIColor*)lightColorInScrollableTabView:(CCFScrollableTabView*)tabView{return[UIColorcolorWithRed:0.258fgreen:0.639fblue:0.890falpha:1.0f];}-(NSArray*)titlesInScrollableTabView:(CCFScrollableTabView*)tabView{return[NSArrayarrayWithObjects:@"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.
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:
1234567
/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.
This installs rvm and the latest stable version of ruby. Next update the terminal and check the version of ruby in use:
12
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:
12345678
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.
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.
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.
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:
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.
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.
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
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
123
xorl%eax,%eaxpopq%rbpret
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.
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.
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.
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.
All that’s left is to clean up, restoring the registers and the stack before returning.
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.