I've got a released app using Realm and there are some crash logs showing that there is sometimes a failure to create the realm with a configuration resulting in a EXC_BREAKPOINT (SIGTRAP) crash. (there's 9 crash files for a few hundred app installations so its not something which is happening frequently)
@objc class Database : NSObject
{
let configuration = Realm.Configuration(encryptionKey: Database.getKey() as Data)
var transactionRealm:Realm? = nil
override init()
{
let realm = try! Realm(configuration: configuration) // Crash here
<snip>
}
// This getKey() method is taken from the Realm website
class func getKey() -> NSData {
let keychainIdentifier = "Realm.EncryptionKey.AppKey"
let keychainIdentifierData = keychainIdentifier.data(using: String.Encoding.utf8, allowLossyConversion: false)!
// First check in the keychain for an existing key
var query: [NSString: AnyObject] = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: keychainIdentifierData as AnyObject,
kSecAttrKeySizeInBits: 512 as AnyObject,
kSecReturnData: true as AnyObject
]
// To avoid Swift optimization bug, should use withUnsafeMutablePointer() function to retrieve the keychain item
// See also: http://stackoverflow.com/questions/24145838/querying-ios-keychain-using-swift/27721328#27721328
var dataTypeRef: AnyObject?
var status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0)) }
if status == errSecSuccess {
return dataTypeRef as! NSData
}
// No pre-existing key from this application, so generate a new one
let keyData = NSMutableData(length: 64)!
let result = SecRandomCopyBytes(kSecRandomDefault, 64, keyData.mutableBytes.bindMemory(to: UInt8.self, capacity: 64))
assert(result == 0, "REALM - Failed to get random bytes")
// Store the key in the keychain
query = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: keychainIdentifierData as AnyObject,
kSecAttrKeySizeInBits: 512 as AnyObject,
kSecValueData: keyData,
kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlock
]
status = SecItemAdd(query as CFDictionary, nil)
assert(status == errSecSuccess, "REALM - Failed to insert the new key in the keychain")
return keyData
}
Here's the relevant portion of the crash file:
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000103c0f30c
Termination Signal: Trace/BPT trap: 5
Termination Reason: Namespace SIGNAL, Code 0x5
Terminating Process: exc handler [0]
Triggered by Thread: 0
Thread 0 name:
Thread 0 Crashed:
0 libswiftCore.dylib 0x0000000103c0f30c 0x103ab4000 + 1422092
1 libswiftCore.dylib 0x0000000103c0f30c 0x103ab4000 + 1422092
2 libswiftCore.dylib 0x0000000103b13d2c 0x103ab4000 + 392492
3 libswiftCore.dylib 0x0000000103b13bf4 0x103ab4000 + 392180
4 My app 0x000000010334ff14 _TFC14Caller_Name_ID8DatabasecfT_S0_ + 1648 (Database.swift:21)
5 My app 0x0000000103330624 -[Model createDatabase] + 200 (Model.m:271)
Line 21 of the Database.swift file is the one indicated in the code above in the Init() method.
If the reason for the Realm crash is because getKey() fails, then why would that be failing? If thats not the cause, that what are other reasons for the failure? And is there anything the code can do (such as retry to create the Realm object) if there is a failure?