Manuel Manuel - 1 year ago 147
iOS Question

Why does app crash at NSData getBytes?

NSData is extended to determine the file type:

extension NSData {
var dataType: String? {

// Ensure data length is at least 1 byte
guard self.length > 0 else { return nil }

// Get first byte
var c = [UInt8](count: 1, repeatedValue: 0)
self.getBytes(&c, length: 1)

// Identify data type
switch (c[0]) {
case 0xFF:
return "jpg"
case 0x89:
return "png"
case 0x47:
return "gif"
case 0x49, 0x4D:
return "tiff"
return nil //unknown

The method above is called on a
object from image data that is fetched from a server.

dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {

do {
// Fetch image synchronously from server
let query = PFQuery(className: <...>)
let result = try query.getFirstObject()

let imageObject = result.objectForKey(<...>) as? PFFile,
let imageData = try? imageObject.getData(),
let image = imageData.dataType == "gif" ? UIImage.animatedImageWithAnimatedGIFData(imageData) : UIImage(data: imageData)
else {


} catch (let error as NSError) {

However the app very rarely crashes at line

enter image description here

What is the reason for this?

The buffer of getBytes is
, an
- do I have to take any special memory considerations because of that?


The crashes still occur with the following variation of the code:

// Get first byte
var c: UInt8 = 0;
self.getBytes(&c, length: 1)


The crashes still occur with the following variation of the code:

// Get first byte
var c = [UInt8](count: 1, repeatedValue: 0)
c.withUnsafeMutableBufferPointer {
buffer in
getBytes(buffer.baseAddress, length: 1)

guard c.indices.contains(0) else { return nil }

I got the following crash and included the whole thread, maybe someone can spot a hint:

Thread 18 Crashed:
0 libsystem_platform.dylib 0x21a8e198 _platform_memmove$VARIANT$CortexA9 + 92
1 Foundation 0x22512923 __34-[_NSDispatchData getBytes:range:]_block_invoke + 176
2 libdispatch.dylib 0x218d238d _dispatch_data_apply + 82
3 libdispatch.dylib 0x218d4a51 dispatch_data_apply + 26
4 Foundation 0x22512865 -[_NSDispatchData getBytes:range:] + 86
5 Foundation 0x2267730b -[_NSDispatchData getBytes:length:] + 24
6 MyAppName 0x00079ba0 partial apply forwarder for (extension in MyAppName):__ObjC.NSData.(dataType.getter : Swift.String?).(closure #1) (NSData+Extension.swift:54)
7 MyAppName 0x00079c14 partial apply forwarder for reabstraction thunk helper from @callee_owned (@inout Swift.UnsafeMutableBufferPointer<Swift.UInt8>) -> (@unowned (), @error @owned Swift.ErrorType) to @callee_owned (@inout Swift.UnsafeMutableBufferPointer<Swift.UInt8>) -> (@out (), @error @owned Swift.ErrorType) (NSData+Extension.swift:0)
8 MyAppName 0x00079cb8 generic specialization <Swift.UInt8, ()> of Swift.Array.withUnsafeMutableBufferPointer <A> ((inout Swift.UnsafeMutableBufferPointer<A>) throws -> A1) throws -> A1 (NSData+Extension.swift:0)
9 MyAppName 0x00079a70 (extension in MyAppName):__ObjC.NSData.dataType.getter : Swift.String? (NSData+Extension.swift:55)
10 MyAppName 0x00079948 @objc (extension in MyAppName):__ObjC.NSData.dataType.getter : Swift.String? (NSData+Extension.swift:0)
11 MyAppName 0x000d2264 MyAppName.DataManager.(fetchImagesFromServer (MyAppName.ImageSet) -> ()).(closure #1) (DataManager.swift:1214)
12 libdispatch.dylib 0x218cd823 _dispatch_call_block_and_release + 8
13 libdispatch.dylib 0x218dc5e9 _dispatch_root_queue_drain + 1558
14 libdispatch.dylib 0x218dbfcd _dispatch_worker_thread3 + 94
15 libsystem_pthread.dylib 0x21a91b29 _pthread_wqthread + 1022
16 libsystem_pthread.dylib 0x21a91718 start_wqthread + 6


The crashes still occur with the following variation of the code:

// Get first byte
var c = UnsafeMutablePointer<UInt8>.alloc(1)
defer { c.dealloc(1) }
self.getBytes(c, length: 1)

switch (c[0]) { ...

Answer Source

With the help of an Apple engineer (via a TSI ticket) the issue was finally identified. All code permutations above for reading the first byte are valid and working.

The issue was that the NSData object was created when a file was fetched from a server using the Parse iOS SDK which stores the data in a temporary file with file protection key NSFileProtectionCompleteUntilFirstUserAuthentication.

The file protection key allows reading data of the NSData object only after the user unlocks the device once after reboot. Although the data is not readable before unlocking, the NSData object can be created and even the NSData.length property is accessible. However, attempting to read the data would throw an exception.

I changed the code and added a check if the protected data is available before attempting to read it with UIApplication.sharedApplication().protectedDataAvailable.

You may wonder why a file was fetched by the app before the device was even unlocked. The app was started by a remote user notification. That explains why the crash happened so rarely.

Learned 2 things:

  • Always check your file protection key
  • Apple technical support is worth the money