Skip to content

Commit 1b87ff4

Browse files
committed
Ensure thread safety on caching images
1 parent 70f1e7a commit 1b87ff4

File tree

2 files changed

+18
-25
lines changed

2 files changed

+18
-25
lines changed

Sources/SwiftyImage.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ open class ImageDrawer {
120120

121121
// MARK: Cache
122122

123+
private static let lock: NSLock = NSLock()
123124
private static var cachedImages = [String: UIImage]()
124125
private var cacheKey: String {
125126
var attributes = [String: String]()
@@ -267,8 +268,10 @@ open class ImageDrawer {
267268
}
268269

269270
private func imageWithSize(_ size: CGSize, useCache: Bool = true) -> UIImage {
270-
if let cachedImage = type(of: self).cachedImages[self.cacheKey], useCache {
271-
return cachedImage
271+
if useCache {
272+
if let cachedImage = type(of: self).cachedImages[self.cacheKey] {
273+
return cachedImage
274+
}
272275
}
273276

274277
var imageSize = CGSize(width: size.width, height: size.height)
@@ -448,7 +451,9 @@ open class ImageDrawer {
448451
}
449452

450453
if useCache {
451-
type(of: self).cachedImages[self.cacheKey] = image
454+
ImageDrawer.lock.lock()
455+
ImageDrawer.cachedImages[self.cacheKey] = image
456+
ImageDrawer.lock.unlock()
452457
}
453458

454459
return image

SwiftyImageTests/SwiftyImageTests.swift

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,17 @@
88

99
import UIKit
1010
import XCTest
11+
import SwiftyImage
1112

1213
class SwiftyImageTests: XCTestCase {
13-
14-
override func setUp() {
15-
super.setUp()
16-
// Put setup code here. This method is called before the invocation of each test method in the class.
14+
func testCacheLock() {
15+
for _ in 0..<100 {
16+
DispatchQueue.global().async {
17+
_ = UIImage.resizable().border(width: 1).corner(radius: 15).image
18+
}
1719
}
18-
19-
override func tearDown() {
20-
// Put teardown code here. This method is called after the invocation of each test method in the class.
21-
super.tearDown()
22-
}
23-
24-
func testExample() {
25-
// This is an example of a functional test case.
26-
XCTAssert(true, "Pass")
27-
}
28-
29-
func testPerformanceExample() {
30-
// This is an example of a performance test case.
31-
self.measure() {
32-
// Put the code you want to measure the time of here.
33-
}
34-
}
35-
20+
21+
let expectation = XCTestExpectation()
22+
XCTWaiter().wait(for: [expectation], timeout: 1)
23+
}
3624
}

0 commit comments

Comments
 (0)