@@ -53,6 +53,7 @@ @interface FICImageTable () {
5353 NSCountedSet *_chunkSet;
5454
5555 NSRecursiveLock *_lock;
56+ CFMutableDictionaryRef _indexNumbers;
5657
5758 // Image table metadata
5859 NSMutableDictionary *_indexMap; // Key: entity UUID, value: integer index into the table file
@@ -129,6 +130,8 @@ - (instancetype)initWithFormat:(FICImageFormat *)imageFormat {
129130 }
130131
131132 _lock = [[NSRecursiveLock alloc ] init ];
133+ _indexNumbers = CFDictionaryCreateMutable (kCFAllocatorDefault , 0 , NULL , &kCFTypeDictionaryValueCallBacks );
134+
132135 _imageFormat = [imageFormat copy ];
133136 _imageFormatDictionary = [imageFormat dictionaryRepresentation ];
134137
@@ -268,16 +271,6 @@ - (void)setEntryForEntityUUID:(NSString *)entityUUID sourceImageUUID:(NSString *
268271 // Create context whose backing store *is* the mapped file data
269272 FICImageTableEntry *entryData = [self _entryDataAtIndex: newEntryIndex];
270273 if (entryData) {
271- CGContextRef context = CGBitmapContextCreate ([entryData bytes ], pixelSize.width , pixelSize.height , bitsPerComponent, _imageRowLength, colorSpace, bitmapInfo);
272- CGColorSpaceRelease (colorSpace);
273-
274- CGContextTranslateCTM (context, 0 , pixelSize.height );
275- CGContextScaleCTM (context, _screenScale, -_screenScale);
276-
277- // Call drawing block to allow client to draw into the context
278- imageDrawingBlock (context, [_imageFormat imageSize ]);
279- CGContextRelease (context);
280-
281274 [entryData setEntityUUIDBytes: FICUUIDBytesWithString (entityUUID)];
282275 [entryData setSourceImageUUIDBytes: FICUUIDBytesWithString (sourceImageUUID)];
283276
@@ -290,12 +283,32 @@ - (void)setEntryForEntityUUID:(NSString *)entityUUID sourceImageUUID:(NSString *
290283 [self _entryWasAccessedWithEntityUUID: entityUUID];
291284 [self saveMetadata ];
292285
293- // Write the data back to the filesystem
294- [entryData flush ];
286+ // Unique, unchanging pointer for this entry's index
287+ NSNumber *indexNumber = [self _numberForEntryAtIndex: newEntryIndex];
288+
289+ // Relinquish the image table lock before calling potentially slow imageDrawingBlock to unblock other FIC operations
290+ [_lock unlock ];
291+
292+ CGContextRef context = CGBitmapContextCreate ([entryData bytes ], pixelSize.width , pixelSize.height , bitsPerComponent, _imageRowLength, colorSpace, bitmapInfo);
293+ CGColorSpaceRelease (colorSpace);
294+
295+ CGContextTranslateCTM (context, 0 , pixelSize.height );
296+ CGContextScaleCTM (context, _screenScale, -_screenScale);
297+
298+ @synchronized (indexNumber) {
299+ // Call drawing block to allow client to draw into the context
300+ imageDrawingBlock (context, [_imageFormat imageSize ]);
301+ CGContextRelease (context);
302+
303+ // Write the data back to the filesystem
304+ [entryData flush ];
305+ }
306+ } else {
307+ [_lock unlock ];
295308 }
309+ } else {
310+ [_lock unlock ];
296311 }
297-
298- [_lock unlock ];
299312 }
300313}
301314
@@ -564,6 +577,16 @@ - (void)_entryWasAccessedWithEntityUUID:(NSString *)entityUUID {
564577 }
565578}
566579
580+ // Unchanging pointer value for a given entry index to synchronize on
581+ - (NSNumber *)_numberForEntryAtIndex : (NSInteger )index {
582+ NSNumber *resultNumber = (__bridge id )CFDictionaryGetValue (_indexNumbers, (const void *)index);
583+ if (!resultNumber) {
584+ resultNumber = [NSNumber numberWithInteger: index];
585+ CFDictionarySetValue (_indexNumbers, (const void *)index, (__bridge void *)resultNumber);
586+ }
587+ return resultNumber;
588+ }
589+
567590#pragma mark - Working with Metadata
568591
569592- (void )saveMetadata {
0 commit comments