diff --git a/build.sh b/build.sh index c33cccc86..ea0709863 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,6 @@ #!/bin/sh +echo "Clean dist" rm -rf dist mkdir dist mkdir dist/package @@ -25,7 +26,6 @@ cp LICENSE.md dist/package/LICENSE.md cp README.md dist/package/README.md cp package.json dist/package/package.json -# npm pack echo "NPM pack" cd dist/package PACKAGE="$(npm pack)" diff --git a/ios/TNSWidgets/TNSWidgets/UIImage+TNSBlocks.h b/ios/TNSWidgets/TNSWidgets/UIImage+TNSBlocks.h index c242ee3b5..cdcbd3361 100644 --- a/ios/TNSWidgets/TNSWidgets/UIImage+TNSBlocks.h +++ b/ios/TNSWidgets/TNSWidgets/UIImage+TNSBlocks.h @@ -6,10 +6,18 @@ // Copyright © 2016 Telerik A D. All rights reserved. // - - @interface UIImage (TNSBlocks) -+ (void) tns_imageNamed: (NSString*) name completion: (void (^) (UIImage*))callback; +/** + * Similar to imageNamed: however it runs on a separate queue so the UI thread is not blocked. + * It also draws the UIImage in a small thumb to force decoding potentially avoiding UI hicckups when displayed. + */ ++ (void) tns_safeDecodeImageNamed: (NSString*) name completion: (void (^) (UIImage*))callback; + +/** + * Same as imageNamed, however calls to this method are sinchronized to be thread safe in iOS8 along with calls to tns_safeImageNamed and tns_safeDecodeImageNamed:completion: + * imageNamed is thread safe in iOS 9 and later so in later versions this methods simply fallbacks to imageNamed: + */ ++ (UIImage*) tns_safeImageNamed: (NSString*) name; @end diff --git a/ios/TNSWidgets/TNSWidgets/UIImage+TNSBlocks.m b/ios/TNSWidgets/TNSWidgets/UIImage+TNSBlocks.m index adcaf4f14..1fa7162f2 100644 --- a/ios/TNSWidgets/TNSWidgets/UIImage+TNSBlocks.m +++ b/ios/TNSWidgets/TNSWidgets/UIImage+TNSBlocks.m @@ -10,28 +10,56 @@ @implementation UIImage (TNSBlocks) +static NSLock* image_lock_handle; static dispatch_queue_t image_queue; + +void image_lock() { + if (image_lock_handle) { + [image_lock_handle lock]; + } +} + +void image_unlock() { + if (image_lock_handle) { + [image_lock_handle unlock]; + } +} + + (void) initialize { image_queue = dispatch_queue_create("org.nativescript.TNSWidgets.image", NULL); + if ([[NSProcessInfo processInfo] operatingSystemVersion].majorVersion >= 9) { + // UIImage imageNamed: is said to be thread safe, in iOS9 and later, in offical Apple reference. + image_lock_handle = nil; + } else { + image_lock_handle = [NSLock new]; + } } - (void) tns_decompressImage { - CGImageRef cgImg = [self CGImage]; - // TODO: Do performance tests if actual drawing is necessary - - // UIGraphicsBeginImageContext(CGSizeMake(1, 1)); - // [self drawAtPoint:CGPointZero]; - // UIGraphicsEndImageContext(); + UIGraphicsBeginImageContext(CGSizeMake(1, 1)); + [self drawAtPoint:CGPointZero]; + UIGraphicsEndImageContext(); } -+ (void) tns_imageNamed: (NSString*) name completion: (void (^) (UIImage*))callback { ++ (void) tns_safeDecodeImageNamed: (NSString*) name completion: (void (^) (UIImage*))callback { dispatch_async(image_queue, ^(void){ + image_lock(); UIImage* image = [UIImage imageNamed: name]; - [image tns_decompressImage]; + if (image) { + [image tns_decompressImage]; + } + image_unlock(); dispatch_async(dispatch_get_main_queue(), ^(void) { callback(image); }); }); } ++ (UIImage*) tns_safeImageNamed: (NSString*) name { + image_lock(); + UIImage* image = [UIImage imageNamed: name]; + image_unlock(); + return image; +} + @end