George MacKerron: code blog

GIS, software development, and other snippets

Archive for the ‘iPhone’ Category

No more busywork! DRY up your NSString constants

without comments

Preamble

In the last few years, Objective-C has become enormously DRYer. For example: in the past, adding a property to a class meant adding several of: an ivar, a @property, a @synthesize, a getter/setter, and a release call in dealloc. Worse, renaming or deleting the property meant updating all these. This was error-prone busywork, and made iOS development frankly pretty tedious.

Nowadays a single @property is often all that’s needed. Plus of course we’ve lost all that retain / release / autorelease noise, and got fast enumeration, literals for NSNumber, NSArray, NSDictionary and so on. This is great (and is one reason why I’ve come back to Xcode after a brief dalliance with RubyMotion).

Anyway, I really do hate repeating myself, and one of the more annoying remaining areas where this has been necessary has been string constants. These are pretty widely used in Cocoa for NSNotification names, dictionary keys, and so on.

Problem

In the past I’ve used #define in my headers. For example,

#define TapNotification @"TapNotification"

This seems like fairly innocuous repetition, but it’s still annoying. And the idiomatic/Apple way is worse. You do this in the header file:

extern NSString* const TapNotification;

Backed up by this in the implementation file:

NSString* const TapNotification = @"TapNotification";

We type the same identifier (and its accompanying line noise) no fewer than THREE times.

Solution

The best solution I’ve found involves a macro plus a one-line sed command.

The macro goes like this:

#define StrConst(s) extern NSString* const s;

And the one-line sed command (added as a build phase straight after ‘Target Dependencies’) goes like this:

sed -nE 's/[[:<:]]StrConst[[:space:]]*\([[:space:]]*([^)[:space:]]+)[[:space:]]*\)/NSString* const \1 = @"\1";/pg' ${SOURCE_ROOT}/${PROJECT_NAME}/*.h > ${SOURCE_ROOT}/${PROJECT_NAME}/AutoStrConsts.m

Now all you do for a string constant is type this in your header file:

StrConst(TapNotification)

The macro converts this to the right form for the header, and the sed command searches all your headers to create a single implementation file that contains all the corresponding definitions (you’ll need to manually add this file to the project when it’s first created).

If you think this is too much magic, I’ll understand. But for me, it’s a necessary battle in the war on busywork.

Written by George

July 2nd, 2014 at 10:13 am

Posted in iPhone,Mac

Lightweight inline formatting for NSAttributedString

without comments

For Cocoa developers: I’ve just put a small category on NSMutableAttributedString on Github.

It applies *bold*, /italic/, _underline_, -strikethrough-, ^superscript^ and ~subscript~ styles, and handles */nested/* and *overlapping /styles* properly/.

More details at https://github.com/jawj/NSMutableAttributedString-InlineStyles

Written by George

March 11th, 2014 at 4:13 pm

Posted in iPhone,Mac

Using vDSP_deq22 as a bandpass filter

with one comment

For reasons that may become clearer in future, I needed to use a bandpass filter in an iOS app. The DSP part of Apple’s Accelerate framework makes this lightning fast both for the programmer to implement and for the machine to execute … if the programmer knows how use vDSP_deq22, which is documented, at best, concisely.

The following functions produce the five-coefficient filter definition you need to pass to vDSP_deq22. Since this took me a little while to put together, I thought I’d share.

void makeBandpassFilterWithFcAndQ(float* filter, double Fs, double Fc, double Q) {
 
  // Fs = sampling rate, Fc = centre freq
  // with thanks to http://www.earlevel.com/main/2013/10/13/biquad-calculator-v2/
  // and https://github.com/bartolsthoorn/NVDSP
 
  double K = tan(M_PI * Fc / Fs);
  double norm = 1.0 / (1.0 + K / Q + K * K);
  filter[0] = (float)(K / Q * norm);
  filter[1] = 0.0f;
  filter[2] = -filter[0];
  filter[3] = (float)(2.0 * (K * K - 1.0) * norm);
  filter[4] = (float)((1.0 - K / Q + K * K) * norm);
}
 
void makeBandpassFilterWithFreqRange(float* filter, double Fs, double Fbtm, double Ftop) {
 
  // with thanks to 
  // http://stackoverflow.com/questions/15627013/how-do-i-configure-a-bandpass-filter
  // -- this sets Q such that there's -3dB gain (= 50% power loss) at Fbtm and Ftop
 
  double Fc = sqrt(Fbtm * Ftop);
  double Q = Fc / (Ftop - Fbtm);
  makeBandpassFilterWithFcAndQ(filter, Fs, Fc, Q);
}

And you use it like so:

float filter[5];
makeBandpassFilterWithFreqRange(filter, sampleRate, filterLoRate, filterHiRate);
vDSP_deq22(rawFloats, rawStride, filter, filteredFloats, filteredStride, numRawFloats - 2); 
  // rawFloats and filteredFloats are pointers, of course

Written by George

February 4th, 2014 at 2:37 pm

Posted in iPhone,Mac

Objective-C SHA1 categories for NSData and NSString

without comments

I recently needed to calculate a SHA1 hash in an iOS app.

In iOS4+ it’s possible to use CommonCrypto, but Mappiness has always supported iOS3. I therefore added NSData and NSString categories to a public domain C implementation instead. This remains public domain: do with it what you will.

It relies on a hex-encoding category on NSData, which you can also consider public domain.

Read the rest of this entry »

Written by George

June 19th, 2012 at 10:12 am

Posted in iPhone

Passcode view controller

without comments

Need to protect something with a passcode in an iPhone app you’re developing?

Then you may find my MIT-licensed passcode view controller — as seen in the mappiness app and in the short screencast below — of use.

See Github for the code and (scant) documentation.

Written by George

October 28th, 2011 at 5:33 pm

Posted in iPhone

Four things I’ve learned using Push Notifications

without comments

My current iPhone app/research project, mappiness, is heavily reliant on Apple’s Push Notification Service (APNS).

We’re now sending about one million notifications a month, and it’s working beautifully. The obvious alternative — using SMS messages — would be costing us tens of thousands of pounds a month.

If you’re using or contemplating using Push Notifications, you may find these four points of interest:

  1. Urban Airship offer a well-though-out and reliable service. But if you’re using them just as an intermediary in telling the APNS to beep users X, Y and Z right now — not making use of their scheduling or broadcast features, for example — it might well not be worth it. You’ll cut out a layer of indirection, and save money if you get big enough for it to matter, by talking to Apple directly.
  2. There’s a surprising dearth of viable-looking open-source options for interfacing with the APNS. (APNS uses a binary protocol over a secure connection, and doesn’t like this connection torn down and reopened too often, so you can’t easily interface with it directly from a web app or cron job). But there is pyapns, an XML-RPC-speaking APNS provider built on Python’s Twisted networking framework, with client libraries for Python and Ruby. I’ve found this straightforward and rock-solid.
  3. The APNS feedback service sometimes reports device tokens as inactive for no obvious reason, so make sure you’re prepared to hear from and reactivate users you’ve previously inactivated. (mappiness got bitten by this early on: a few dozen people were unable to authenticate to our server because they’d been reported as inactive and we’d assumed they were never coming back, despite that fact they had the app installed and Push Notifications switched on).
  4. The app delegate method application:didRegisterForRemoteNotificationsWithDeviceToken: seems occasionally to return phantom zero-length device tokens — so don’t let your app or server get flummoxed by these. (We suffered from this on mappiness too: the bad device token got added to the front of a queue for sending from the app to our server; the server wouldn’t accept it; and this blocked all further data getting sent back until we fixed the server to silently ignore the bad tokens).

Written by George

September 11th, 2010 at 3:32 pm

Posted in iPhone,Ruby

O2 mobile broadband on a Mac: tips for you, suggestion for O2

with 21 comments

Until Monday, O2 is offering a half-price USB dongle for pay-as-you-go mobile broadband. Buy it via Quidco, and you get not only the dongle but also a month’s access (or 3GB, whichever is the sooner) absolutely free.

So: free modem. No further commitment. And the opportunity to buy access a day at a time for £2, on a train journey, for example, or in an airport lounge, where the cheapest paid-for WiFi option is rarely less than £5, and often nearer £10. Handy.

Update. O2 is no longer doing the modem at half price, but the Quidco cashback has increased so that it still fully covers the modem and a £15 top-up.

Read the rest of this entry »

Written by George

August 1st, 2009 at 1:52 pm

Posted in iPhone,Mac