From 245e1f7c3f7432ae0fef3f7a0b972487f4bad302 Mon Sep 17 00:00:00 2001 From: Sam Pettersson Date: Thu, 13 Aug 2020 14:58:55 +0200 Subject: [PATCH] Fix crash on using `signal(for:)` on UIVisualEffectViews --- Flow.xcodeproj/project.pbxproj | 4 +++ Flow/UIView+Signal.swift | 13 ++++++++-- ...llbackerView+UIVisualEffectViewTests.swift | 26 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 FlowTests/CallbackerView+UIVisualEffectViewTests.swift diff --git a/Flow.xcodeproj/project.pbxproj b/Flow.xcodeproj/project.pbxproj index e24413a..8f83155 100644 --- a/Flow.xcodeproj/project.pbxproj +++ b/Flow.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 792AC15B227C8A6800F8BBAD /* SignalProviderTests+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 792AC15A227C8A6800F8BBAD /* SignalProviderTests+Internal.swift */; }; 8E890FC106FB7A89BD1727CC /* EitherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E890194B06CBB3311E44757 /* EitherTests.swift */; }; DA6D58EF230E925700564CC1 /* MemoryUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA6D58EB230E918800564CC1 /* MemoryUtilsTests.swift */; }; + EB4E033624E5707000CD7F8F /* CallbackerView+UIVisualEffectViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB4E033524E5707000CD7F8F /* CallbackerView+UIVisualEffectViewTests.swift */; }; F610ABAE1D91743500A161AB /* Future+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F610ABA71D91743500A161AB /* Future+Additions.swift */; }; F610ABB01D91743500A161AB /* FutureQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = F610ABA91D91743500A161AB /* FutureQueue.swift */; }; F610ABB21D91743500A161AB /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = F610ABAB1D91743500A161AB /* Result.swift */; }; @@ -91,6 +92,7 @@ 792AC15A227C8A6800F8BBAD /* SignalProviderTests+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "SignalProviderTests+Internal.swift"; path = "FlowTests/SignalProviderTests+Internal.swift"; sourceTree = ""; }; 8E890194B06CBB3311E44757 /* EitherTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EitherTests.swift; path = FlowTests/EitherTests.swift; sourceTree = ""; }; DA6D58EB230E918800564CC1 /* MemoryUtilsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MemoryUtilsTests.swift; path = FlowTests/MemoryUtilsTests.swift; sourceTree = ""; }; + EB4E033524E5707000CD7F8F /* CallbackerView+UIVisualEffectViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "CallbackerView+UIVisualEffectViewTests.swift"; path = "FlowTests/CallbackerView+UIVisualEffectViewTests.swift"; sourceTree = ""; }; F610ABA61D91743500A161AB /* Future.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Future.swift; path = Flow/Future.swift; sourceTree = SOURCE_ROOT; }; F610ABA71D91743500A161AB /* Future+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Future+Additions.swift"; path = "Flow/Future+Additions.swift"; sourceTree = SOURCE_ROOT; }; F610ABA91D91743500A161AB /* FutureQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FutureQueue.swift; path = Flow/FutureQueue.swift; sourceTree = SOURCE_ROOT; }; @@ -298,6 +300,7 @@ F610ABB51D91747000A161AB /* FutureQueueTests.swift */, F610ABB61D91747000A161AB /* FutureRepeatTests.swift */, F610ABB71D91747000A161AB /* FutureSchedulingTests.swift */, + EB4E033524E5707000CD7F8F /* CallbackerView+UIVisualEffectViewTests.swift */, F610ABB81D91747000A161AB /* FutureSplitTests.swift */, F610ABB91D91747000A161AB /* FutureUtilitiesTests.swift */, F6A8808D1D9182B900CA257F /* CallbackerTests.swift */, @@ -519,6 +522,7 @@ F610ABBE1D91747000A161AB /* FutureRepeatTests.swift in Sources */, F610ABC01D91747000A161AB /* FutureSplitTests.swift in Sources */, 215DEF371DEC368700CEB724 /* RecursiveTests.swift in Sources */, + EB4E033624E5707000CD7F8F /* CallbackerView+UIVisualEffectViewTests.swift in Sources */, F66835D42091C29C002D2676 /* UIViewSignalTests.swift in Sources */, 792AC15B227C8A6800F8BBAD /* SignalProviderTests+Internal.swift in Sources */, F6C0FED2202B44360076B877 /* DelegateTests.swift in Sources */, diff --git a/Flow/UIView+Signal.swift b/Flow/UIView+Signal.swift index a008ba7..a87ff3b 100644 --- a/Flow/UIView+Signal.swift +++ b/Flow/UIView+Signal.swift @@ -98,13 +98,22 @@ public extension UIView { private extension UIView { func signal(for keyPath: KeyPath>) -> Signal { return Signal(onValue: { callback in - let view = (self.viewWithTag(987892442) as? CallbackerView) ?? { + var callbackerViewParent: UIView { + if let parent = self as? UIVisualEffectView { + return parent.contentView + } + + return self + } + + let view = (callbackerViewParent.viewWithTag(987892442) as? CallbackerView) ?? { let view = CallbackerView(frame: self.bounds) view.autoresizingMask = [.flexibleWidth, .flexibleHeight] // trick so layoutsubViews is called when the view is resized view.tag = 987892442 view.backgroundColor = .clear view.isUserInteractionEnabled = false - self.insertSubview(view, at: 0) + callbackerViewParent.insertSubview(view, at: 0) + view.setNeedsLayout() return view }() diff --git a/FlowTests/CallbackerView+UIVisualEffectViewTests.swift b/FlowTests/CallbackerView+UIVisualEffectViewTests.swift new file mode 100644 index 0000000..a4f8ba6 --- /dev/null +++ b/FlowTests/CallbackerView+UIVisualEffectViewTests.swift @@ -0,0 +1,26 @@ +// +// Callbacker+UIVisualEffectViewTests.swift +// FlowTests +// +// Created by Sam Pettersson on 2020-08-13. +// Copyright © 2020 iZettle. All rights reserved. +// + +import Foundation +import XCTest +import Flow + +class CallbackerViewUIVisualEffectViewTests: XCTestCase { + func testNotCrashing() { + let effectView = UIVisualEffectView() + let bag = DisposeBag() + + let expectation = self.expectation(description: "did trigger bounds") + + bag += effectView.signal(for: \.bounds).atOnce().onValue { _ in + expectation.fulfill() + } + + waitForExpectations(timeout: 10) + } +}