Skip to content

Commit 8caffe9

Browse files
authored
Merge pull request #36 from cwakamo/safe-view-logging-in-the-background
[PlaygroundLogger] Make NSView and UIView logging short-circuit if no…
2 parents 6c112c2 + 2e44f91 commit 8caffe9

File tree

3 files changed

+60
-3
lines changed

3 files changed

+60
-3
lines changed

PlaygroundLogger/PlaygroundLogger/OpaqueRepresentations/AppKit/NSView+OpaqueImageRepresentable.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2017-2018 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2017-2019 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See http://swift.org/LICENSE.txt for license information
@@ -15,6 +15,12 @@
1515

1616
extension NSView: OpaqueImageRepresentable {
1717
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) throws {
18+
guard Thread.isMainThread else {
19+
// If we're not on the main thread, then just encode empty PNG data.
20+
encoder.encode(number: 0)
21+
return
22+
}
23+
1824
guard let bitmapRep = self.bitmapImageRepForCachingDisplay(in: self.bounds) else {
1925
if self.bounds == .zero {
2026
// If we couldn't get a bitmap representation because the view is zero-sized, encode empty PNG data.

PlaygroundLogger/PlaygroundLogger/OpaqueRepresentations/UIKit/UIView+OpaqueImageRepresentable.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2017-2018 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2017-2019 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See http://swift.org/LICENSE.txt for license information
@@ -15,6 +15,12 @@
1515

1616
extension UIView: OpaqueImageRepresentable {
1717
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) {
18+
guard Thread.isMainThread else {
19+
// If we're not on the main thread, then just encode empty PNG data.
20+
encoder.encode(number: 0)
21+
return
22+
}
23+
1824
let ir = UIGraphicsImageRenderer(size: bounds.size)
1925
let pngData = ir.pngData { _ in
2026
self.drawHierarchy(in: bounds, afterScreenUpdates: true)

PlaygroundLogger/PlaygroundLoggerTests/LogEntryTests.swift

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2018 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2018-2019 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See http://swift.org/LICENSE.txt for license information
@@ -81,6 +81,51 @@ class LogEntryTests: XCTestCase {
8181
try logEntry.encode(with: encoder, format: .current)
8282
}
8383

84+
func testViewBackgroundThread() throws {
85+
#if os(macOS)
86+
let view = NSView(frame: NSRect(x: 0, y: 0, width: 100, height: 100))
87+
#elseif os(iOS) || os(tvOS)
88+
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
89+
#endif
90+
91+
func testLoggingOfView() throws {
92+
let logEntry = try LogEntry(describing: view, name: "view", policy: .default)
93+
94+
guard case let .opaque(name, _, _, _, representation) = logEntry else {
95+
XCTFail("Expected an opaque log entry")
96+
return
97+
}
98+
99+
XCTAssertEqual(name, "view")
100+
XCTAssert(representation is ImageOpaqueRepresentation)
101+
102+
// Try to encode the log entry. This operation shouldn't throw; if it does, it will fail the test.
103+
let encoder = LogEncoder()
104+
try logEntry.encode(with: encoder, format: .current)
105+
}
106+
107+
try testLoggingOfView()
108+
109+
var backgroundTestSucceeded = false
110+
let expectation = self.expectation(description: "Background logging expectation")
111+
112+
DispatchQueue.global().async {
113+
do {
114+
try testLoggingOfView()
115+
backgroundTestSucceeded = true
116+
}
117+
catch {
118+
XCTFail("Logging the view failed")
119+
}
120+
121+
expectation.fulfill()
122+
}
123+
124+
self.wait(for: [expectation], timeout: 5)
125+
126+
XCTAssertTrue(backgroundTestSucceeded)
127+
}
128+
84129
func testLargeSet() throws {
85130
let set = Set(1...1000)
86131

0 commit comments

Comments
 (0)