Преглед изворни кода

Stop using spinlocks

Apple engineers have pointed out that OSSpinLocks are vulnerable to live locking
on iOS in cases of priority inversion:

. http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
. https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
ibireme пре 9 година
родитељ
комит
c93da033ad

+ 1 - 1
Demo/YYTextDemo/YYImage/YYAnimatedImageView.h

@@ -1,6 +1,6 @@
 //
 //  YYAnimatedImageView.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/10/19.
 //  Copyright (c) 2015 ibireme.

+ 53 - 43
Demo/YYTextDemo/YYImage/YYAnimatedImageView.m

@@ -1,6 +1,6 @@
 //
 //  YYAnimatedImageView.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/10/19.
 //  Copyright (c) 2015 ibireme.
@@ -12,19 +12,18 @@
 #import "YYAnimatedImageView.h"
 #import "YYImageCoder.h"
 #import <pthread.h>
-#import <libkern/OSAtomic.h>
 #import <mach/mach.h>
 
 
 #define BUFFER_SIZE (10 * 1024 * 1024) // 10MB (minimum memory buffer size)
 
-#define LOCK(...) OSSpinLockLock(&self->_lock); \
+#define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \
 __VA_ARGS__; \
-OSSpinLockUnlock(&self->_lock);
+dispatch_semaphore_signal(self->_lock);
 
-#define LOCK_VIEW(...) OSSpinLockLock(&view->_lock); \
+#define LOCK_VIEW(...) dispatch_semaphore_wait(view->_lock, DISPATCH_TIME_FOREVER); \
 __VA_ARGS__; \
-OSSpinLockUnlock(&view->_lock);
+dispatch_semaphore_signal(view->_lock);
 
 
 static int64_t _YYDeviceMemoryTotal() {
@@ -113,12 +112,12 @@ static int64_t _YYDeviceMemoryFree() {
 
 
 
-typedef NS_ENUM(NSUInteger, YYAnimagedImageType) {
-    YYAnimagedImageTypeNone = 0,
-    YYAnimagedImageTypeImage,
-    YYAnimagedImageTypeHighlightedImage,
-    YYAnimagedImageTypeImages,
-    YYAnimagedImageTypeHighlightedImages,
+typedef NS_ENUM(NSUInteger, YYAnimatedImageType) {
+    YYAnimatedImageTypeNone = 0,
+    YYAnimatedImageTypeImage,
+    YYAnimatedImageTypeHighlightedImage,
+    YYAnimatedImageTypeImages,
+    YYAnimatedImageTypeHighlightedImages,
 };
 
 @interface YYAnimatedImageView() {
@@ -126,7 +125,7 @@ typedef NS_ENUM(NSUInteger, YYAnimagedImageType) {
     UIImage <YYAnimatedImage> *_curAnimatedImage;
     
     dispatch_once_t _onceToken;
-    OSSpinLock _lock; ///< lock for _buffer
+    dispatch_semaphore_t _lock; ///< lock for _buffer
     NSOperationQueue *_requestQueue; ///< image request queue, serial
     
     CADisplayLink *_link; ///< ticker for change frame
@@ -197,6 +196,13 @@ typedef NS_ENUM(NSUInteger, YYAnimagedImageType) {
     return self;
 }
 
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    _runloopMode = NSRunLoopCommonModes;
+    _autoPlayAnimatedImage = YES;
+    return self;
+}
+
 - (instancetype)initWithImage:(UIImage *)image {
     self = [super init];
     _runloopMode = NSRunLoopCommonModes;
@@ -220,7 +226,7 @@ typedef NS_ENUM(NSUInteger, YYAnimagedImageType) {
 // init the animated params.
 - (void)resetAnimated {
     dispatch_once(&_onceToken, ^{
-        _lock = OS_SPINLOCK_INIT;
+        _lock = dispatch_semaphore_create(1);
         _buffer = [NSMutableDictionary new];
         _requestQueue = [[NSOperationQueue alloc] init];
         _requestQueue.maxConcurrentOperationCount = 1;
@@ -265,22 +271,22 @@ typedef NS_ENUM(NSUInteger, YYAnimagedImageType) {
 
 - (void)setImage:(UIImage *)image {
     if (self.image == image) return;
-    [self setImage:image withType:YYAnimagedImageTypeImage];
+    [self setImage:image withType:YYAnimatedImageTypeImage];
 }
 
 - (void)setHighlightedImage:(UIImage *)highlightedImage {
     if (self.highlightedImage == highlightedImage) return;
-    [self setImage:highlightedImage withType:YYAnimagedImageTypeHighlightedImage];
+    [self setImage:highlightedImage withType:YYAnimatedImageTypeHighlightedImage];
 }
 
 - (void)setAnimationImages:(NSArray *)animationImages {
     if (self.animationImages == animationImages) return;
-    [self setImage:animationImages withType:YYAnimagedImageTypeImages];
+    [self setImage:animationImages withType:YYAnimatedImageTypeImages];
 }
 
 - (void)setHighlightedAnimationImages:(NSArray *)highlightedAnimationImages {
     if (self.highlightedAnimationImages == highlightedAnimationImages) return;
-    [self setImage:highlightedAnimationImages withType:YYAnimagedImageTypeHighlightedImages];
+    [self setImage:highlightedAnimationImages withType:YYAnimatedImageTypeHighlightedImages];
 }
 
 - (void)setHighlighted:(BOOL)highlighted {
@@ -289,46 +295,46 @@ typedef NS_ENUM(NSUInteger, YYAnimagedImageType) {
     [self imageChanged];
 }
 
-- (id)imageForType:(YYAnimagedImageType)type {
+- (id)imageForType:(YYAnimatedImageType)type {
     switch (type) {
-        case YYAnimagedImageTypeNone: return nil;
-        case YYAnimagedImageTypeImage: return self.image;
-        case YYAnimagedImageTypeHighlightedImage: return self.highlightedImage;
-        case YYAnimagedImageTypeImages: return self.animationImages;
-        case YYAnimagedImageTypeHighlightedImages: return self.highlightedAnimationImages;
+        case YYAnimatedImageTypeNone: return nil;
+        case YYAnimatedImageTypeImage: return self.image;
+        case YYAnimatedImageTypeHighlightedImage: return self.highlightedImage;
+        case YYAnimatedImageTypeImages: return self.animationImages;
+        case YYAnimatedImageTypeHighlightedImages: return self.highlightedAnimationImages;
     }
     return nil;
 }
 
-- (YYAnimagedImageType)currentImageType {
-    YYAnimagedImageType curType = YYAnimagedImageTypeNone;
+- (YYAnimatedImageType)currentImageType {
+    YYAnimatedImageType curType = YYAnimatedImageTypeNone;
     if (self.highlighted) {
-        if (self.highlightedAnimationImages.count) curType = YYAnimagedImageTypeHighlightedImages;
-        else if (self.highlightedImage) curType = YYAnimagedImageTypeHighlightedImage;
+        if (self.highlightedAnimationImages.count) curType = YYAnimatedImageTypeHighlightedImages;
+        else if (self.highlightedImage) curType = YYAnimatedImageTypeHighlightedImage;
     }
-    if (curType == YYAnimagedImageTypeNone) {
-        if (self.animationImages.count) curType = YYAnimagedImageTypeImages;
-        else if (self.image) curType = YYAnimagedImageTypeImage;
+    if (curType == YYAnimatedImageTypeNone) {
+        if (self.animationImages.count) curType = YYAnimatedImageTypeImages;
+        else if (self.image) curType = YYAnimatedImageTypeImage;
     }
     return curType;
 }
 
-- (void)setImage:(id)image withType:(YYAnimagedImageType)type {
+- (void)setImage:(id)image withType:(YYAnimatedImageType)type {
     [self stopAnimating];
     if (_link) [self resetAnimated];
     _curFrame = nil;
     switch (type) {
-        case YYAnimagedImageTypeNone: break;
-        case YYAnimagedImageTypeImage: super.image = image; break;
-        case YYAnimagedImageTypeHighlightedImage: super.highlightedImage = image; break;
-        case YYAnimagedImageTypeImages: super.animationImages = image; break;
-        case YYAnimagedImageTypeHighlightedImages: super.highlightedAnimationImages = image; break;
+        case YYAnimatedImageTypeNone: break;
+        case YYAnimatedImageTypeImage: super.image = image; break;
+        case YYAnimatedImageTypeHighlightedImage: super.highlightedImage = image; break;
+        case YYAnimatedImageTypeImages: super.animationImages = image; break;
+        case YYAnimatedImageTypeHighlightedImages: super.highlightedAnimationImages = image; break;
     }
     [self imageChanged];
 }
 
 - (void)imageChanged {
-    YYAnimagedImageType newType = [self currentImageType];
+    YYAnimatedImageType newType = [self currentImageType];
     id newVisibleImage = [self imageForType:newType];
     NSUInteger newImageFrameCount = 0;
     BOOL hasContentsRect = NO;
@@ -397,8 +403,8 @@ typedef NS_ENUM(NSUInteger, YYAnimagedImageType) {
 }
 
 - (void)startAnimating {
-    YYAnimagedImageType type = [self currentImageType];
-    if (type == YYAnimagedImageTypeImages || type == YYAnimagedImageTypeHighlightedImages) {
+    YYAnimatedImageType type = [self currentImageType];
+    if (type == YYAnimatedImageTypeImages || type == YYAnimatedImageTypeHighlightedImages) {
         NSArray *images = [self imageForType:type];
         if (images.count > 0) {
             [super startAnimating];
@@ -620,17 +626,21 @@ typedef NS_ENUM(NSUInteger, YYAnimagedImageType) {
     self = [super initWithCoder:aDecoder];
     _runloopMode = [aDecoder decodeObjectForKey:@"runloopMode"];
     if (_runloopMode.length == 0) _runloopMode = NSRunLoopCommonModes;
-    _autoPlayAnimatedImage = [aDecoder decodeBoolForKey:@"autoPlayAnimatedImage"];
+    if ([aDecoder containsValueForKey:@"autoPlayAnimatedImage"]) {
+        _autoPlayAnimatedImage = [aDecoder decodeBoolForKey:@"autoPlayAnimatedImage"];
+    } else {
+        _autoPlayAnimatedImage = YES;
+    }
     
     UIImage *image = [aDecoder decodeObjectForKey:@"YYAnimatedImage"];
     UIImage *highlightedImage = [aDecoder decodeObjectForKey:@"YYHighlightedAnimatedImage"];
     if (image) {
         self.image = image;
-        [self setImage:image withType:YYAnimagedImageTypeImage];
+        [self setImage:image withType:YYAnimatedImageTypeImage];
     }
     if (highlightedImage) {
         self.highlightedImage = highlightedImage;
-        [self setImage:highlightedImage withType:YYAnimagedImageTypeHighlightedImage];
+        [self setImage:highlightedImage withType:YYAnimatedImageTypeHighlightedImage];
     }
     return self;
 }

+ 3 - 1
Demo/YYTextDemo/YYImage/YYFrameImage.h

@@ -1,6 +1,6 @@
 //
 //  YYFrameImage.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/12/9.
 //  Copyright (c) 2015 ibireme.
@@ -13,6 +13,8 @@
 
 #if __has_include(<YYImage/YYImage.h>)
 #import <YYImage/YYAnimatedImageView.h>
+#elif __has_include(<YYWebImage/YYImage.h>)
+#import <YYWebImage/YYAnimatedImageView.h>
 #else
 #import "YYAnimatedImageView.h"
 #endif

+ 1 - 1
Demo/YYTextDemo/YYImage/YYFrameImage.m

@@ -1,6 +1,6 @@
 //
 //  YYFrameImage.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/12/9.
 //  Copyright (c) 2015 ibireme.

+ 6 - 1
Demo/YYTextDemo/YYImage/YYImage.h

@@ -1,6 +1,6 @@
 //
 //  YYImage.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/10/20.
 //  Copyright (c) 2015 ibireme.
@@ -18,6 +18,11 @@ FOUNDATION_EXPORT const unsigned char YYImageVersionString[];
 #import <YYImage/YYSpriteSheetImage.h>
 #import <YYImage/YYImageCoder.h>
 #import <YYImage/YYAnimatedImageView.h>
+#elif __has_include(<YYWebImage/YYImage.h>)
+#import <YYWebImage/YYFrameImage.h>
+#import <YYWebImage/YYSpriteSheetImage.h>
+#import <YYWebImage/YYImageCoder.h>
+#import <YYWebImage/YYAnimatedImageView.h>
 #else
 #import "YYFrameImage.h"
 #import "YYSpriteSheetImage.h"

+ 11 - 12
Demo/YYTextDemo/YYImage/YYImage.m

@@ -1,6 +1,6 @@
 //
 //  YYImage.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/10/20.
 //  Copyright (c) 2015 ibireme.
@@ -10,7 +10,6 @@
 //
 
 #import "YYImage.h"
-#import <libkern/OSAtomic.h>
 
 /**
  An array of NSNumber objects, shows the best order for path scale search.
@@ -88,7 +87,7 @@ static CGFloat _NSStringPathScale(NSString *string) {
 @implementation YYImage {
     YYImageDecoder *_decoder;
     NSArray *_preloadedFrames;
-    OSSpinLock _preloadedLock;
+    dispatch_semaphore_t _preloadedLock;
     NSUInteger _bytesPerFrame;
 }
 
@@ -101,12 +100,12 @@ static CGFloat _NSStringPathScale(NSString *string) {
     NSString *path = nil;
     CGFloat scale = 1;
     
+    // If no extension, guess by system supported (same as UIImage).
+    NSArray *exts = ext.length > 0 ? @[ext] : @[@"", @"png", @"jpeg", @"jpg", @"gif", @"webp", @"apng"];
     NSArray *scales = _NSBundlePreferredScales();
     for (int s = 0; s < scales.count; s++) {
         scale = ((NSNumber *)scales[s]).floatValue;
         NSString *scaledName = _NSStringByAppendingNameScale(res, scale);
-        // If no extension, guess by system supported (same as UIImage).
-        NSArray *exts = ext.length > 0 ? @[ext] : @[@"", @"png", @"jpeg", @"jpg", @"gif", @"webp"];
         for (NSString *e in exts) {
             path = [[NSBundle mainBundle] pathForResource:scaledName ofType:e];
             if (path) break;
@@ -145,7 +144,7 @@ static CGFloat _NSStringPathScale(NSString *string) {
 - (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale {
     if (data.length == 0) return nil;
     if (scale <= 0) scale = [UIScreen mainScreen].scale;
-    _preloadedLock = OS_SPINLOCK_INIT;
+    _preloadedLock = dispatch_semaphore_create(1);
     @autoreleasepool {
         YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:scale];
         YYImageFrame *frame = [decoder frameAtIndex:0 decodeForDisplay:YES];
@@ -180,13 +179,13 @@ static CGFloat _NSStringPathScale(NSString *string) {
                     [frames addObject:[NSNull null]];
                 }
             }
-            OSSpinLockLock(&_preloadedLock);
+            dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
             _preloadedFrames = frames;
-            OSSpinLockUnlock(&_preloadedLock);
+            dispatch_semaphore_signal(_preloadedLock);
         } else {
-            OSSpinLockLock(&_preloadedLock);
+            dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
             _preloadedFrames = nil;
-            OSSpinLockUnlock(&_preloadedLock);
+            dispatch_semaphore_signal(_preloadedLock);
         }
     }
 }
@@ -229,9 +228,9 @@ static CGFloat _NSStringPathScale(NSString *string) {
 
 - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index {
     if (index >= _decoder.frameCount) return nil;
-    OSSpinLockLock(&_preloadedLock);
+    dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
     UIImage *image = _preloadedFrames[index];
-    OSSpinLockUnlock(&_preloadedLock);
+    dispatch_semaphore_signal(_preloadedLock);
     if (image) return image == (id)[NSNull null] ? nil : image;
     return [_decoder frameAtIndex:index decodeForDisplay:YES].image;
 }

+ 1 - 1
Demo/YYTextDemo/YYImage/YYImageCoder.h

@@ -1,6 +1,6 @@
 //
 //  YYImageCoder.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 15/5/13.
 //  Copyright (c) 2015 ibireme.

+ 17 - 18
Demo/YYTextDemo/YYImage/YYImageCoder.m

@@ -1,6 +1,6 @@
 //
 //  YYImageCoder.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 15/5/13.
 //  Copyright (c) 2015 ibireme.
@@ -19,7 +19,6 @@
 #import <AssetsLibrary/AssetsLibrary.h>
 #import <objc/runtime.h>
 #import <pthread.h>
-#import <libkern/OSAtomic.h>
 #import <zlib.h>
 
 
@@ -924,7 +923,7 @@ CGImageRef YYCGImageCreateAffineTransformCopy(CGImageRef imageRef, CGAffineTrans
     if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) return NULL;
     
     CGDataProviderRef tmpProvider = NULL, destProvider = NULL;
-    CGImageRef tmpImage = NULL, destImage = NULL;;
+    CGImageRef tmpImage = NULL, destImage = NULL;
     vImage_Buffer src = {0}, tmp = {0}, dest = {0};
     if(!YYCGImageDecodeToBitmapBufferWith32BitFormat(imageRef, &src, kCGImageAlphaFirst | kCGBitmapByteOrderDefault)) return NULL;
     
@@ -1506,7 +1505,7 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
 
 
 @implementation YYImageDecoder {
-    pthread_mutex_t _lock;
+    pthread_mutex_t _lock; // recursive lock
     
     BOOL _sourceTypeDetected;
     CGImageSourceRef _source;
@@ -1516,7 +1515,7 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
 #endif
     
     UIImageOrientation _orientation;
-    OSSpinLock _framesLock;
+    dispatch_semaphore_t _framesLock;
     NSArray *_frames; ///< Array<GGImageDecoderFrame>, without image
     BOOL _needBlend;
     NSUInteger _blendFrameIndex;
@@ -1548,7 +1547,7 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     self = [super init];
     if (scale <= 0) scale = 1;
     _scale = scale;
-    _framesLock = OS_SPINLOCK_INIT;
+    _framesLock = dispatch_semaphore_create(1);
     
     pthread_mutexattr_t attr;
     pthread_mutexattr_init (&attr);
@@ -1577,11 +1576,11 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
 
 - (NSTimeInterval)frameDurationAtIndex:(NSUInteger)index {
     NSTimeInterval result = 0;
-    OSSpinLockLock(&_framesLock); // for better performance when play animation...
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     if (index < _frames.count) {
         result = ((_YYImageDecoderFrame *)_frames[index]).duration;
     }
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
     return result;
 }
 
@@ -1746,9 +1745,9 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     _loopCount = 0;
     if (_webpSource) WebPDemuxDelete(_webpSource);
     _webpSource = NULL;
-    OSSpinLockLock(&_framesLock);
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     _frames = nil;
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
     
     /*
      https://developers.google.com/speed/webp/docs/api
@@ -1832,9 +1831,9 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     _loopCount = webpLoopCount;
     _needBlend = needBlend;
     _webpSource = demuxer;
-    OSSpinLockLock(&_framesLock);
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     _frames = frames;
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
 #endif
 }
 
@@ -1930,9 +1929,9 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     _loopCount = apng->apng_loop_num;
     _needBlend = needBlend;
     _apngSource = apng;
-    OSSpinLockLock(&_framesLock);
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     _frames = frames;
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
 }
 
 - (void)_updateSourceImageIO {
@@ -1940,9 +1939,9 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     _height = 0;
     _orientation = UIImageOrientationUp;
     _loopCount = 0;
-    OSSpinLockLock(&_framesLock);
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     _frames = nil;
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
     
     if (!_source) {
         if (_finalized) {
@@ -2026,9 +2025,9 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
             CFRelease(properties);
         }
     }
-    OSSpinLockLock(&_framesLock);
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     _frames = frames;
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
 }
 
 - (CGImageRef)_newUnblendedImageAtIndex:(NSUInteger)index

+ 3 - 1
Demo/YYTextDemo/YYImage/YYSpriteSheetImage.h

@@ -1,6 +1,6 @@
 //
 //  YYSpriteImage.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 15/4/21.
 //  Copyright (c) 2015 ibireme.
@@ -13,6 +13,8 @@
 
 #if __has_include(<YYImage/YYImage.h>)
 #import <YYImage/YYAnimatedImageView.h>
+#elif __has_include(<YYWebImage/YYImage.h>)
+#import <YYWebImage/YYAnimatedImageView.h>
 #else
 #import "YYAnimatedImageView.h"
 #endif

+ 1 - 1
Demo/YYTextDemo/YYImage/YYSpriteSheetImage.m

@@ -1,6 +1,6 @@
 //
 //  YYSpriteImage.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 15/4/21.
 //  Copyright (c) 2015 ibireme.

+ 8 - 9
YYText/Component/YYTextLayout.m

@@ -14,7 +14,6 @@
 #import "YYTextAttribute.h"
 #import "YYTextArchiver.h"
 #import "NSAttributedString+YYText.h"
-#import <libkern/OSAtomic.h>
 
 const CGSize YYTextContainerMaxSize = (CGSize){0x100000, 0x100000};
 
@@ -68,7 +67,7 @@ static inline UIEdgeInsets UIEdgeInsetRotateVertical(UIEdgeInsets insets) {
 @implementation YYTextContainer {
     @package
     BOOL _readonly; ///< used only in YYTextLayout.implementation
-    OSSpinLock _lock;
+    dispatch_semaphore_t _lock;
     
     CGSize _size;
     UIEdgeInsets _insets;
@@ -104,14 +103,14 @@ static inline UIEdgeInsets UIEdgeInsetRotateVertical(UIEdgeInsets insets) {
 - (instancetype)init {
     self = [super init];
     if (!self) return nil;
-    _lock = OS_SPINLOCK_INIT;
+    _lock = dispatch_semaphore_create(1);
     _pathFillEvenOdd = YES;
     return self;
 }
 
 - (id)copyWithZone:(NSZone *)zone {
     YYTextContainer *one = [self.class new];
-    OSSpinLockLock(&_lock);
+    dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
     one->_size = _size;
     one->_insets = _insets;
     one->_path = _path;
@@ -123,7 +122,7 @@ static inline UIEdgeInsets UIEdgeInsetRotateVertical(UIEdgeInsets insets) {
     one->_truncationType = _truncationType;
     one->_truncationToken = _truncationToken.copy;
     one->_linePositionModifier = [(NSObject *)_linePositionModifier copy];
-    OSSpinLockUnlock(&_lock);
+    dispatch_semaphore_signal(_lock);
     return one;
 }
 
@@ -165,9 +164,9 @@ static inline UIEdgeInsets UIEdgeInsetRotateVertical(UIEdgeInsets insets) {
 }
 
 #define Getter(...) \
-OSSpinLockLock(&_lock); \
+dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); \
 __VA_ARGS__; \
-OSSpinLockUnlock(&_lock);
+dispatch_semaphore_signal(_lock);
 
 #define Setter(...) \
 if (_readonly) { \
@@ -175,9 +174,9 @@ if (_readonly) { \
 reason:@"Cannot change the property of the 'container' in 'YYTextLayout'." userInfo:nil]; \
 return; \
 } \
-OSSpinLockLock(&_lock); \
+dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); \
 __VA_ARGS__; \
-OSSpinLockUnlock(&_lock);
+dispatch_semaphore_signal(_lock);
 
 - (CGSize)size {
     Getter(CGSize size = _size) return size;

+ 4 - 5
YYText/String/YYTextParser.m

@@ -14,7 +14,6 @@
 #import "YYTextAttribute.h"
 #import "NSAttributedString+YYText.h"
 #import "NSParagraphStyle+YYText.h"
-#import <libkern/OSAtomic.h>
 
 
 #pragma mark - Markdown Parser
@@ -300,19 +299,19 @@
 
 #pragma mark - Emoticon Parser
 
-#define LOCK(...) OSSpinLockLock(&_lock); \
+#define LOCK(...) dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); \
 __VA_ARGS__; \
-OSSpinLockUnlock(&_lock);
+dispatch_semaphore_signal(_lock);
 
 @implementation YYTextSimpleEmoticonParser {
     NSRegularExpression *_regex;
     NSDictionary *_mapper;
-    OSSpinLock _lock;
+    dispatch_semaphore_t _lock;
 }
 
 - (instancetype)init {
     self = [super init];
-    _lock = OS_SPINLOCK_INIT;
+    _lock = dispatch_semaphore_create(1);
     return self;
 }