Turns out I was being caught out by the Enable Foundation Assertions build setting. It seems to be set to No by default for release builds.
I was using code from Keychain Services Tasks for iOS in the Apple Docs which has a lot of the keychain calls (including SecItemAdd) wrapped in NSAssert() therefore they weren't getting called and nothing was getting saved to the keychain.