Isaac Overacker

maker of things

Creating an Xcode Plugin: A Quick-Start Guide

Xcode has a rich ecosystem of third-party plugins, exposed and cataloged by the wonderful Xcode plugin Alcatraz. Some of my favorites: Auto-Importer, BBUFullIssueNavigator, and FuzzyAutocomplete.

However extensive the Xcode plugin catalog may be, there are surely other useful plugins to be written. The process of writing a plugin is not very well documented, and frustratingly, much of the code required to interact with Xcode is still private. However, thanks to the efforts of a few clever developers, getting started is much easier than it used to be. Read on for a quick-start guide to creating an Xcode (5+) plugin.

Image Caching With AFNetworking

AFNetworking is one of the most popular open-source networking frameworks for iOS. You’re probably already using it, but if you’re not, you should consider it. One of the lesser-known features of AFNetworking is the ability to easily load an image from a URL to be used in a UIImageView.

Integrating Test Dependencies With CocoaPods

Most Xcode projects should have some level of test coverage, and any time unit tests are involved it’s nice to have a framework for generating mock objects. However, we don’t want to bloat our production app package with these test frameworks, so it’s nice to link these libraries only with the test target. Configuring this properly can be tricky, and the CocoaPods documentation isn’t very clear on exactly how to accomplish this in the podfile.

The cleanest solution I’ve found to this problem involves specifying the pods for each target individually and using a Ruby function to import the common pods. Here is a sample podfile that accomplishes this:

Podfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
platform :ios, '7.0'

def import_common_pods
   pod 'AFNetworking'
end

target 'MyAppTarget' do
   import_common_pods
end

target 'MyAppTestTarget' do
   import_common_pods
   pod 'OCMock'
end

Note that you may run into a few issues with this if you’re adding this to an existing project and the previous podfile did not explicitly specify the non-test target. In that case, you may need to delete the old Pods.xcconfig and libPods.a files then regenerate your workspace with pod install.

Update

As of CocoaPods 0.34, there’s a cleaner solution built-in:

Podfile
1
2
3
4
5
6
7
8
9
source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '7.0'

pod 'AFNetworking'

target "MyAppTestTarget", :exclusive => true do
   pod 'OCMock'
end

Architecture Headaches With CocoaPods

I recently inherited an iOS project from another developer. This project was not using CocoaPods for dependency management, so naturally, I converted it to using CocoaPods as soon as I could. When I first installed the pods, I received this warning in the console:

Terminal
1
2
3
[!] Found multiple values (`armv7`, `armv7s`) for the
architectures (`ARCHS`) build setting for the `Pods` 
target definition. Using the first.

It seemed harmless enough, and the project built without problems for the iPhone simulator. I carried on for a few weeks working on new features, and then I tried to build a version of the app targeting the iOS devices. Suddenly, I had linker errors.

1
2
3
4
"_OBJC_CLASS_$_FBSession", referenced from:
  objc-class-ref in MySourceFile.m
  ...
ld: symbol(s) not found for architecture armv7s

I looked around for solutions, but of course with linker errors it’s can be very difficult to find answers for a particular issue. Finally, after many hours of searching, reading, and highly scientific trial and error, I decided to look into the multiple architecture warning from CocoaPods, and that’s where I found my issue. In this particular case, the Pods-* targets in my Pods project were targeting armv7 (which is pretty obvious from the CocoaPods warning, but a few weeks had passed), whereas my main app target architectures included both armv7 and armv7s, hence the linker error above.

The solution was to update the target architectures for the app to $(ARCHS_STANDARD_32_BIT) instead of manually specifying both armv7 and armv7s. Then, when running pod install, the $(ARCHS_STANDARD_32_BIT) is set for the Pods-* projects as well and everything is happy.

Note: the reason armv7 and armv7s architectures had been specified for the app is that there is a dependency on a library that does not yet support 64-bit architectures. It looks like $(ARCHS_STANDARD_32_BIT) is a much better way to handle that situation.

The Death of FlightPath and the Future of iOS Usage Statistics

As a longtime user of TestFlight for both test build distribution and usage analytics, I was extremely disappointed to find that they have cancelled their FlightPath beta program for tracking usage statistics in your live app once distributed via the App Store. It was great to be able to reuse the same checkpoint infrastructure to collect usage statistics. Alas, they claim to be focusing more on their core product, which might be a good thing in the end.

As a replacement, I have started working with Flurry, which provides a great deal of usage statistics, including an event infrastructure similar to TestFlight’s checkpoint system.

Make sure to sign up for a free account and copy your application key. Let’s get started!