From 5dfb78e30614bff9858d7a722cac5c89763c5afb Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Tue, 11 Jun 2024 20:56:31 +0900 Subject: [PATCH 01/19] Enable upcoming features for Swift 6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Set "Isolated Global Variables” to Yes - Set "Isolated Default Values” to Yes - Set "Region Based Isolation” to Yes - Set "Infer Sendable for Methods and Key Path Literals” to Yes - Set "Concise Magic File” to Yes - Set 'Deprecate Application Main' to Yes - Set 'Import ObjC Forward Declaration' to Yes - Set 'Implicity Opened Existentials' to Yes - Set 'Forward Trailing Closures' to Yes - Set 'Disable Outward Actor Isolation Inference' to Yes - Set 'Default internal imports' to Yes - Set strict concurrency to complete --- FloatingPanel.xcodeproj/project.pbxproj | 36 +++++++++++++++++++++++++ Sources/Controller.swift | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/FloatingPanel.xcodeproj/project.pbxproj b/FloatingPanel.xcodeproj/project.pbxproj index 7d9486d0..a246779c 100644 --- a/FloatingPanel.xcodeproj/project.pbxproj +++ b/FloatingPanel.xcodeproj/project.pbxproj @@ -536,6 +536,18 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_STRICT_CONCURRENCY = complete; + SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES; + SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES; + SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES; + SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES; + SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES; + SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES; + SWIFT_UPCOMING_FEATURE_IMPORT_OBJC_FORWARD_DECLS = YES; + SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES; + SWIFT_UPCOMING_FEATURE_INTERNAL_IMPORTS_BY_DEFAULT = YES; + SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES; + SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -567,6 +579,18 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_STRICT_CONCURRENCY = complete; + SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES; + SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES; + SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES; + SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES; + SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES; + SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES; + SWIFT_UPCOMING_FEATURE_IMPORT_OBJC_FORWARD_DECLS = YES; + SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES; + SWIFT_UPCOMING_FEATURE_INTERNAL_IMPORTS_BY_DEFAULT = YES; + SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES; + SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -707,6 +731,18 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "TEST DEBUG FP_LOG"; SWIFT_COMPILATION_MODE = singlefile; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_STRICT_CONCURRENCY = complete; + SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES; + SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES; + SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES; + SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES; + SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES; + SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES; + SWIFT_UPCOMING_FEATURE_IMPORT_OBJC_FORWARD_DECLS = YES; + SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES; + SWIFT_UPCOMING_FEATURE_INTERNAL_IMPORTS_BY_DEFAULT = YES; + SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES; + SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/Sources/Controller.swift b/Sources/Controller.swift index 099c50a4..88131bca 100644 --- a/Sources/Controller.swift +++ b/Sources/Controller.swift @@ -770,7 +770,7 @@ extension FloatingPanelController { // MARK: - Swizzling -private var originalDismissImp: IMP? +@MainActor private var originalDismissImp: IMP? private typealias DismissFunction = @convention(c) (AnyObject, Selector, Bool, (() -> Void)?) -> Void extension FloatingPanelController { private static let dismissSwizzling: Void = { From 010d248ca5f03eade9620880c599bae26e933a01 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Mon, 17 Jun 2024 21:13:46 +0900 Subject: [PATCH 02/19] Fix concurrency checks --- Sources/Controller.swift | 19 +++++++++++-------- Sources/Core.swift | 6 ++---- Sources/Extensions.swift | 1 + Sources/Layout.swift | 2 ++ Sources/LayoutAnchoring.swift | 1 + Sources/LayoutProperties.swift | 3 +++ Sources/Logging.swift | 4 ++-- Sources/Position.swift | 1 + Sources/State.swift | 2 +- 9 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Sources/Controller.swift b/Sources/Controller.swift index 88131bca..022e9294 100644 --- a/Sources/Controller.swift +++ b/Sources/Controller.swift @@ -6,6 +6,7 @@ import os.log /// A set of methods implemented by the delegate of a panel controller allows the adopting delegate to respond to /// messages from the FloatingPanelController class and thus respond to, and in some affect, operations such as /// dragging, attracting a panel, layout of a panel and the content, and transition animations. +@MainActor @objc public protocol FloatingPanelControllerDelegate { /// Returns a FloatingPanelLayout object. If you use the default one, you can use a `FloatingPanelBottomLayout` object. @objc(floatingPanel:layoutForTraitCollection:) optional @@ -495,16 +496,18 @@ open class FloatingPanelController: UIViewController { // 2. The safe area top inset can be variable on the large title navigation bar(iOS11+). // That's why it needs the observation to keep `adjustedContentInsets` correct. safeAreaInsetsObservation = self.view.observe(\.safeAreaInsets, options: [.initial, .new, .old]) { [weak self] (_, change) in - // Use `self.view.safeAreaInsets` because `change.newValue` can be nil in particular case when - // is reported in https://github.com/SCENEE/FloatingPanel/issues/330 - guard let self = self, change.oldValue != self.view.safeAreaInsets else { return } + MainActor.assumeIsolated { + // Use `self.view.safeAreaInsets` because `change.newValue` can be nil in particular case when + // is reported in https://github.com/SCENEE/FloatingPanel/issues/330 + guard let self = self, change.oldValue != self.view.safeAreaInsets else { return } - // Sometimes the bounding rectangle of the controlled view becomes invalid when the screen is rotated. - // This results in its safeAreaInsets change. In that case, `self.update(safeAreaInsets:)` leads - // an unsatisfied constraints error. So this method should not be called with those bounds. - guard self.view.bounds.height > 0 && self.view.bounds.width > 0 else { return } + // Sometimes the bounding rectangle of the controlled view becomes invalid when the screen is rotated. + // This results in its safeAreaInsets change. In that case, `self.update(safeAreaInsets:)` leads + // an unsatisfied constraints error. So this method should not be called with those bounds. + guard self.view.bounds.height > 0 && self.view.bounds.width > 0 else { return } - self.update(safeAreaInsets: self.view.safeAreaInsets) + self.update(safeAreaInsets: self.view.safeAreaInsets) + } } move(to: floatingPanel.layoutAdapter.initialState, diff --git a/Sources/Core.swift b/Sources/Core.swift index 2d19ac79..5b2c77e5 100644 --- a/Sources/Core.swift +++ b/Sources/Core.swift @@ -4,7 +4,6 @@ import Combine import UIKit import os.log -/// /// The presentation model of FloatingPanel /// class Core: NSObject, UIGestureRecognizerDelegate { @@ -116,8 +115,7 @@ class Core: NSObject, UIGestureRecognizerDelegate { } deinit { - // Release `NumericSpringAnimator.displayLink` from the run loop. - self.moveAnimator?.stopAnimation(false) + moveAnimator?.stopAnimation(false) } func move( @@ -1348,7 +1346,7 @@ public class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer { // MARK: - Animator -private class NumericSpringAnimator: NSObject { +private final class NumericSpringAnimator: NSObject, @unchecked Sendable { struct Data { let value: CGFloat let velocity: CGFloat diff --git a/Sources/Extensions.swift b/Sources/Extensions.swift index 8d635855..248bd81c 100644 --- a/Sources/Extensions.swift +++ b/Sources/Extensions.swift @@ -36,6 +36,7 @@ extension CGPoint { // MARK: - UIKit +@MainActor protocol LayoutGuideProvider { var topAnchor: NSLayoutYAxisAnchor { get } var leftAnchor: NSLayoutXAxisAnchor { get } diff --git a/Sources/Layout.swift b/Sources/Layout.swift index 2118e4c6..579a1416 100644 --- a/Sources/Layout.swift +++ b/Sources/Layout.swift @@ -4,6 +4,7 @@ import UIKit import os.log /// An interface for generating layout information for a panel. +@MainActor @objc public protocol FloatingPanelLayout { /// Returns the position of a panel in a `FloatingPanelController` view . @objc var position: FloatingPanelPosition { get } @@ -60,6 +61,7 @@ struct LayoutSegment { let upper: FloatingPanelState? } +@MainActor class LayoutAdapter { private unowned var vc: FloatingPanelController private let defaultLayout = FloatingPanelBottomLayout() diff --git a/Sources/LayoutAnchoring.swift b/Sources/LayoutAnchoring.swift index 83388738..56beda83 100644 --- a/Sources/LayoutAnchoring.swift +++ b/Sources/LayoutAnchoring.swift @@ -3,6 +3,7 @@ import UIKit /// An interface for implementing custom layout anchor objects. +@MainActor @objc public protocol FloatingPanelLayoutAnchoring { var referenceGuide: FloatingPanelLayoutReferenceGuide { get } func layoutConstraints(_ fpc: FloatingPanelController, for position: FloatingPanelPosition) -> [NSLayoutConstraint] diff --git a/Sources/LayoutProperties.swift b/Sources/LayoutProperties.swift index c33b410b..6eeb5911 100644 --- a/Sources/LayoutProperties.swift +++ b/Sources/LayoutProperties.swift @@ -3,6 +3,7 @@ import UIKit /// Constants that specify the edge of the container of a panel. +@MainActor @objc public enum FloatingPanelReferenceEdge: Int { case top case left @@ -28,6 +29,7 @@ extension FloatingPanelReferenceEdge { } /// A representation to specify a rectangular area to lay out a panel. +@MainActor @objc public enum FloatingPanelLayoutReferenceGuide: Int { case superview = 0 case safeArea = 1 @@ -45,6 +47,7 @@ extension FloatingPanelLayoutReferenceGuide { } /// A representation to specify a bounding box which limit the content size of a panel. +@MainActor @objc public enum FloatingPanelLayoutContentBoundingGuide: Int { case none = 0 case superview = 1 diff --git a/Sources/Logging.swift b/Sources/Logging.swift index e813254b..25fa051f 100644 --- a/Sources/Logging.swift +++ b/Sources/Logging.swift @@ -3,11 +3,11 @@ import os.log let msg = StaticString("%{public}@") -let sysLog = OSLog(subsystem: Logging.subsystem, category: Logging.category) +nonisolated(unsafe) let sysLog = OSLog(subsystem: Logging.subsystem, category: Logging.category) #if FP_LOG let devLog = OSLog(subsystem: Logging.subsystem, category: "\(Logging.category):dev") #else -let devLog = OSLog.disabled +nonisolated(unsafe) let devLog = OSLog.disabled #endif struct Logging { diff --git a/Sources/Position.swift b/Sources/Position.swift index 973bc55f..ebf84f0d 100644 --- a/Sources/Position.swift +++ b/Sources/Position.swift @@ -3,6 +3,7 @@ import UIKit /// Constants describing the position of a panel in a screen +@MainActor @objc public enum FloatingPanelPosition: Int { case top case left diff --git a/Sources/State.swift b/Sources/State.swift index 25d57b9d..70591111 100644 --- a/Sources/State.swift +++ b/Sources/State.swift @@ -4,7 +4,7 @@ import Foundation /// An object that represents the display state of a panel in a screen. @objc -open class FloatingPanelState: NSObject, NSCopying, RawRepresentable { +public final class FloatingPanelState: NSObject, NSCopying, RawRepresentable, Sendable { public typealias RawValue = String required public init?(rawValue: RawValue) { From 19ebf525752980d9e46e6dfe43a0a1da3ea18301 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Mon, 17 Jun 2024 21:20:52 +0900 Subject: [PATCH 03/19] Fix a concurrency warning in Samples app --- Examples/Samples/Sources/UseCases/UseCaseController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Examples/Samples/Sources/UseCases/UseCaseController.swift b/Examples/Samples/Sources/UseCases/UseCaseController.swift index f1a52d61..f4515cfc 100644 --- a/Examples/Samples/Sources/UseCases/UseCaseController.swift +++ b/Examples/Samples/Sources/UseCases/UseCaseController.swift @@ -3,6 +3,7 @@ import UIKit import FloatingPanel +@MainActor final class UseCaseController: NSObject { unowned let mainVC: MainViewController private(set) var useCase: UseCase From f4edfb2bf2feac651c706af44c55e195c28dd78f Mon Sep 17 00:00:00 2001 From: Keita Watanabe Date: Mon, 5 Aug 2024 21:42:56 +0900 Subject: [PATCH 04/19] Fix existential-any for Swift6 (#639) * Fixed existential any * Added upcoming feature flag --- FloatingPanel.xcodeproj/project.pbxproj | 3 +++ Sources/Behavior.swift | 6 +++--- Sources/Controller.swift | 18 +++++++++--------- Sources/Core.swift | 8 ++++---- Sources/Layout.swift | 16 ++++++++-------- Sources/LayoutAnchoring.swift | 4 ++-- Sources/LayoutProperties.swift | 4 ++-- Sources/Position.swift | 2 +- Sources/Transitioning.swift | 16 ++++++++-------- 9 files changed, 40 insertions(+), 37 deletions(-) diff --git a/FloatingPanel.xcodeproj/project.pbxproj b/FloatingPanel.xcodeproj/project.pbxproj index a246779c..c3e09666 100644 --- a/FloatingPanel.xcodeproj/project.pbxproj +++ b/FloatingPanel.xcodeproj/project.pbxproj @@ -530,6 +530,7 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; + OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny"; PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -575,6 +576,7 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; + OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny"; PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -725,6 +727,7 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; + OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny"; PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; diff --git a/Sources/Behavior.swift b/Sources/Behavior.swift index 339f6395..d0716b89 100644 --- a/Sources/Behavior.swift +++ b/Sources/Behavior.swift @@ -86,9 +86,9 @@ open class FloatingPanelDefaultBehavior: FloatingPanelBehavior { class BehaviorAdapter { unowned let vc: FloatingPanelController - fileprivate var behavior: FloatingPanelBehavior + fileprivate var behavior: any FloatingPanelBehavior - init(vc: FloatingPanelController, behavior: FloatingPanelBehavior) { + init(vc: FloatingPanelController, behavior: any FloatingPanelBehavior) { self.vc = vc self.behavior = behavior } @@ -123,7 +123,7 @@ class BehaviorAdapter { } extension FloatingPanelController { - var _behavior: FloatingPanelBehavior { + var _behavior: any FloatingPanelBehavior { get { floatingPanel.behaviorAdapter.behavior } set { floatingPanel.behaviorAdapter.behavior = newValue} } diff --git a/Sources/Controller.swift b/Sources/Controller.swift index 022e9294..03a29400 100644 --- a/Sources/Controller.swift +++ b/Sources/Controller.swift @@ -10,11 +10,11 @@ import os.log @objc public protocol FloatingPanelControllerDelegate { /// Returns a FloatingPanelLayout object. If you use the default one, you can use a `FloatingPanelBottomLayout` object. @objc(floatingPanel:layoutForTraitCollection:) optional - func floatingPanel(_ fpc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout + func floatingPanel(_ fpc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> any FloatingPanelLayout /// Returns a FloatingPanelLayout object. If you use the default one, you can use a `FloatingPanelBottomLayout` object. @objc(floatingPanel:layoutForSize:) optional - func floatingPanel(_ fpc: FloatingPanelController, layoutFor size: CGSize) -> FloatingPanelLayout + func floatingPanel(_ fpc: FloatingPanelController, layoutFor size: CGSize) -> any FloatingPanelLayout /// Returns a UIViewPropertyAnimator object to add/present the panel to a state anchor. /// @@ -163,7 +163,7 @@ open class FloatingPanelController: UIViewController { /// The delegate of a panel controller object. @objc - public weak var delegate: FloatingPanelControllerDelegate?{ + public weak var delegate: (any FloatingPanelControllerDelegate)?{ didSet{ didUpdateDelegate() } @@ -211,7 +211,7 @@ open class FloatingPanelController: UIViewController { /// You need to call ``invalidateLayout()`` if you want to apply a new layout object into the panel /// immediately. @objc - public var layout: FloatingPanelLayout { + public var layout: any FloatingPanelLayout { get { _layout } set { _layout = newValue @@ -224,7 +224,7 @@ open class FloatingPanelController: UIViewController { /// The behavior object that the controller manages @objc - public var behavior: FloatingPanelBehavior { + public var behavior: any FloatingPanelBehavior { get { _behavior } set { _behavior = newValue @@ -295,7 +295,7 @@ open class FloatingPanelController: UIViewController { /// Initialize a newly created panel controller. @objc - public init(delegate: FloatingPanelControllerDelegate? = nil) { + public init(delegate: (any FloatingPanelControllerDelegate)? = nil) { super.init(nibName: nil, bundle: nil) self.delegate = delegate setUp() @@ -307,7 +307,7 @@ open class FloatingPanelController: UIViewController { modalPresentationStyle = .custom transitioningDelegate = modalTransition - let initialLayout: FloatingPanelLayout + let initialLayout: any FloatingPanelLayout if let layout = delegate?.floatingPanel?(self, layoutFor: traitCollection) { initialLayout = layout } else { @@ -357,7 +357,7 @@ open class FloatingPanelController: UIViewController { floatingPanel.adjustScrollContentInsetIfNeeded() } - open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + open override func viewWillTransition(to size: CGSize, with coordinator: any UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if self.view.bounds.size == size { @@ -376,7 +376,7 @@ open class FloatingPanelController: UIViewController { } } - open override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { + open override func willTransition(to newCollection: UITraitCollection, with coordinator: any UIViewControllerTransitionCoordinator) { super.willTransition(to: newCollection, with: coordinator) if shouldUpdateLayout(from: traitCollection, to: newCollection) == false { diff --git a/Sources/Core.swift b/Sources/Core.swift index 5b2c77e5..221ec14c 100644 --- a/Sources/Core.swift +++ b/Sources/Core.swift @@ -80,7 +80,7 @@ class Core: NSObject, UIGestureRecognizerDelegate { // MARK: - Interface - init(_ vc: FloatingPanelController, layout: FloatingPanelLayout, behavior: FloatingPanelBehavior) { + init(_ vc: FloatingPanelController, layout: any FloatingPanelLayout, behavior: any FloatingPanelBehavior) { ownerVC = vc surfaceView = SurfaceView() @@ -1284,7 +1284,7 @@ public class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer { /// /// - Note: The delegate is used by FloatingPanel itself. If you set your own delegate object, an /// exception is raised. If you want to handle the methods of UIGestureRecognizerDelegate, you can use `delegateProxy`. - public override weak var delegate: UIGestureRecognizerDelegate? { + public override weak var delegate: (any UIGestureRecognizerDelegate)? { get { return super.delegate } @@ -1305,7 +1305,7 @@ public class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer { /// The default object implementing a set methods of the delegate of the gesture recognizer. /// /// Use this property with ``delegateProxy`` when you need to use the default gesture behaviors in a proxy implementation. - public var delegateOrigin: UIGestureRecognizerDelegate { + public var delegateOrigin: any UIGestureRecognizerDelegate { return floatingPanel } @@ -1313,7 +1313,7 @@ public class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer { /// /// `UIGestureRecognizerDelegate` methods implementing by this object are called instead of the default delegate, /// ``delegateOrigin``. - public weak var delegateProxy: UIGestureRecognizerDelegate? { + public weak var delegateProxy: (any UIGestureRecognizerDelegate)? { didSet { self.delegate = floatingPanel?.panGestureDelegateRouter // Update the cached IMP } diff --git a/Sources/Layout.swift b/Sources/Layout.swift index 579a1416..38eff34d 100644 --- a/Sources/Layout.swift +++ b/Sources/Layout.swift @@ -13,7 +13,7 @@ import os.log @objc var initialState: FloatingPanelState { get } /// Returns the layout anchors to specify the snapping locations for each state. - @objc var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] { get } + @objc var anchors: [FloatingPanelState: any FloatingPanelLayoutAnchoring] { get } /// Returns layout constraints to determine the cross dimension of a panel. @objc optional func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] @@ -32,7 +32,7 @@ open class FloatingPanelBottomLayout: NSObject, FloatingPanelLayout { return .half } - open var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] { + open var anchors: [FloatingPanelState: any FloatingPanelLayoutAnchoring] { return [ .full: FloatingPanelLayoutAnchor(absoluteInset: 18.0, edge: .top, referenceGuide: .safeArea), .half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea), @@ -66,7 +66,7 @@ class LayoutAdapter { private unowned var vc: FloatingPanelController private let defaultLayout = FloatingPanelBottomLayout() - fileprivate var layout: FloatingPanelLayout { + fileprivate var layout: any FloatingPanelLayout { didSet { surfaceView.position = position } @@ -289,7 +289,7 @@ class LayoutAdapter { return offset.rounded(by: surfaceView.fp_displayScale) } - private var hiddenAnchor: FloatingPanelLayoutAnchoring { + private var hiddenAnchor: any FloatingPanelLayoutAnchoring { switch position { case .top: return FloatingPanelLayoutAnchor(absoluteInset: -100, edge: .top, referenceGuide: .superview) @@ -302,7 +302,7 @@ class LayoutAdapter { } } - init(vc: FloatingPanelController, layout: FloatingPanelLayout) { + init(vc: FloatingPanelController, layout: any FloatingPanelLayout) { self.vc = vc self.layout = layout } @@ -406,7 +406,7 @@ class LayoutAdapter { } } - private func referenceEdge(of anchor: FloatingPanelLayoutAnchoring) -> FloatingPanelReferenceEdge { + private func referenceEdge(of anchor: any FloatingPanelLayoutAnchoring) -> FloatingPanelReferenceEdge { switch anchor { case is FloatingPanelIntrinsicLayoutAnchor, is FloatingPanelAdaptiveLayoutAnchor: @@ -548,7 +548,7 @@ class LayoutAdapter { NSLayoutConstraint.deactivate(constraint: interactionConstraint) interactionConstraint = nil - let layoutGuideProvider: LayoutGuideProvider + let layoutGuideProvider: any LayoutGuideProvider switch anchor.referenceGuide { case .safeArea: layoutGuideProvider = vc.view.safeAreaLayoutGuide @@ -856,7 +856,7 @@ extension LayoutAdapter { } extension FloatingPanelController { - var _layout: FloatingPanelLayout { + var _layout: any FloatingPanelLayout { get { floatingPanel.layoutAdapter.layout } diff --git a/Sources/LayoutAnchoring.swift b/Sources/LayoutAnchoring.swift index 56beda83..02783d14 100644 --- a/Sources/LayoutAnchoring.swift +++ b/Sources/LayoutAnchoring.swift @@ -66,7 +66,7 @@ public extension FloatingPanelLayoutAnchor { } } - private func layoutConstraints(_ layoutGuide: LayoutGuideProvider, for edgeAnchor: NSLayoutYAxisAnchor) -> [NSLayoutConstraint] { + private func layoutConstraints(_ layoutGuide: any LayoutGuideProvider, for edgeAnchor: NSLayoutYAxisAnchor) -> [NSLayoutConstraint] { switch referenceEdge { case .top: if isAbsolute { @@ -85,7 +85,7 @@ public extension FloatingPanelLayoutAnchor { } } - private func layoutConstraints(_ layoutGuide: LayoutGuideProvider, for edgeAnchor: NSLayoutXAxisAnchor) -> [NSLayoutConstraint] { + private func layoutConstraints(_ layoutGuide: any LayoutGuideProvider, for edgeAnchor: NSLayoutXAxisAnchor) -> [NSLayoutConstraint] { switch referenceEdge { case .left: if isAbsolute { diff --git a/Sources/LayoutProperties.swift b/Sources/LayoutProperties.swift index 6eeb5911..f2f95fff 100644 --- a/Sources/LayoutProperties.swift +++ b/Sources/LayoutProperties.swift @@ -36,7 +36,7 @@ extension FloatingPanelReferenceEdge { } extension FloatingPanelLayoutReferenceGuide { - func layoutGuide(vc: UIViewController) -> LayoutGuideProvider { + func layoutGuide(vc: UIViewController) -> any LayoutGuideProvider { switch self { case .safeArea: return vc.view.safeAreaLayoutGuide @@ -55,7 +55,7 @@ extension FloatingPanelLayoutReferenceGuide { } extension FloatingPanelLayoutContentBoundingGuide { - func layoutGuide(_ fpc: FloatingPanelController) -> LayoutGuideProvider? { + func layoutGuide(_ fpc: FloatingPanelController) -> (any LayoutGuideProvider)? { switch self { case .superview: return fpc.view diff --git a/Sources/Position.swift b/Sources/Position.swift index ebf84f0d..2c7c1317 100644 --- a/Sources/Position.swift +++ b/Sources/Position.swift @@ -26,7 +26,7 @@ extension FloatingPanelPosition { } } - func mainDimensionAnchor(_ layoutGuide: LayoutGuideProvider) -> NSLayoutDimension { + func mainDimensionAnchor(_ layoutGuide: any LayoutGuideProvider) -> NSLayoutDimension { switch self { case .top, .bottom: return layoutGuide.heightAnchor case .left, .right: return layoutGuide.widthAnchor diff --git a/Sources/Transitioning.swift b/Sources/Transitioning.swift index ff771f8b..006e259d 100644 --- a/Sources/Transitioning.swift +++ b/Sources/Transitioning.swift @@ -5,11 +5,11 @@ import UIKit class ModalTransition: NSObject, UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController, presenting: UIViewController, - source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + source: UIViewController) -> (any UIViewControllerAnimatedTransitioning)? { return ModalPresentTransition() } - func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + func animationController(forDismissed dismissed: UIViewController) -> (any UIViewControllerAnimatedTransitioning)? { return ModalDismissTransition() } @@ -81,7 +81,7 @@ class PresentationController: UIPresentationController { } class ModalPresentTransition: NSObject, UIViewControllerAnimatedTransitioning { - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + func transitionDuration(using transitionContext: (any UIViewControllerContextTransitioning)?) -> TimeInterval { guard let fpc = transitionContext?.viewController(forKey: .to) as? FloatingPanelController else { return 0.0 } @@ -90,7 +90,7 @@ class ModalPresentTransition: NSObject, UIViewControllerAnimatedTransitioning { return TimeInterval(animator.duration) } - func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { + func interruptibleAnimator(using transitionContext: any UIViewControllerContextTransitioning) -> any UIViewImplicitlyAnimating { guard let fpc = transitionContext.viewController(forKey: .to) as? FloatingPanelController else { fatalError() } @@ -110,13 +110,13 @@ class ModalPresentTransition: NSObject, UIViewControllerAnimatedTransitioning { return transitionAnimator } - func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + func animateTransition(using transitionContext: any UIViewControllerContextTransitioning) { self.interruptibleAnimator(using: transitionContext).startAnimation() } } class ModalDismissTransition: NSObject, UIViewControllerAnimatedTransitioning { - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + func transitionDuration(using transitionContext: (any UIViewControllerContextTransitioning)?) -> TimeInterval { guard let fpc = transitionContext?.viewController(forKey: .from) as? FloatingPanelController else { return 0.0 } @@ -125,7 +125,7 @@ class ModalDismissTransition: NSObject, UIViewControllerAnimatedTransitioning { return TimeInterval(animator.duration) } - func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { + func interruptibleAnimator(using transitionContext: any UIViewControllerContextTransitioning) -> any UIViewImplicitlyAnimating { guard let fpc = transitionContext.viewController(forKey: .from) as? FloatingPanelController else { fatalError() } @@ -142,7 +142,7 @@ class ModalDismissTransition: NSObject, UIViewControllerAnimatedTransitioning { return fpc.transitionAnimator! } - func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + func animateTransition(using transitionContext: any UIViewControllerContextTransitioning) { self.interruptibleAnimator(using: transitionContext).startAnimation() } } From 54ddc3cc5dba194df7cb3cdfe68907f1eaddb5f5 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Fri, 9 Aug 2024 14:26:44 +0900 Subject: [PATCH 05/19] Replace OTHER_SWIFT_FLAGS with SWIFT_UPCOMING_FEATURE_EXISTENTIAL_ANY --- FloatingPanel.xcodeproj/project.pbxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FloatingPanel.xcodeproj/project.pbxproj b/FloatingPanel.xcodeproj/project.pbxproj index c3e09666..aec23db6 100644 --- a/FloatingPanel.xcodeproj/project.pbxproj +++ b/FloatingPanel.xcodeproj/project.pbxproj @@ -530,7 +530,6 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny"; PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -541,6 +540,7 @@ SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES; SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES; SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES; + SWIFT_UPCOMING_FEATURE_EXISTENTIAL_ANY = YES; SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES; SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES; SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES; @@ -576,7 +576,6 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny"; PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -585,6 +584,7 @@ SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES; SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES; SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES; + SWIFT_UPCOMING_FEATURE_EXISTENTIAL_ANY = YES; SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES; SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES; SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES; @@ -727,7 +727,6 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny"; PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanel; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -738,6 +737,7 @@ SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES; SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES; SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES; + SWIFT_UPCOMING_FEATURE_EXISTENTIAL_ANY = YES; SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES; SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES; SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES; From d30dd7dd2e07a0f8f628d13401b0cf7fb532bc87 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Fri, 9 Aug 2024 14:49:17 +0900 Subject: [PATCH 06/19] Enable Swift 6 --- FloatingPanel.xcodeproj/project.pbxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FloatingPanel.xcodeproj/project.pbxproj b/FloatingPanel.xcodeproj/project.pbxproj index aec23db6..07250373 100644 --- a/FloatingPanel.xcodeproj/project.pbxproj +++ b/FloatingPanel.xcodeproj/project.pbxproj @@ -549,7 +549,7 @@ SWIFT_UPCOMING_FEATURE_INTERNAL_IMPORTS_BY_DEFAULT = YES; SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES; SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -593,7 +593,7 @@ SWIFT_UPCOMING_FEATURE_INTERNAL_IMPORTS_BY_DEFAULT = YES; SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES; SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -746,7 +746,7 @@ SWIFT_UPCOMING_FEATURE_INTERNAL_IMPORTS_BY_DEFAULT = YES; SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES; SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Test; From 09ee35e564338d1617e3f7dc77cdd4557ac8ba4b Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Fri, 16 Aug 2024 15:34:04 +0900 Subject: [PATCH 07/19] Fix compile errors on main actor-isolated initializers --- Sources/BackdropView.swift | 4 ++-- Sources/Core.swift | 2 +- Sources/GrabberView.swift | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/BackdropView.swift b/Sources/BackdropView.swift index b1e48c79..71a7a23b 100644 --- a/Sources/BackdropView.swift +++ b/Sources/BackdropView.swift @@ -12,10 +12,10 @@ open class BackdropView: UIView { /// To dismiss a panel by tap gestures on the backdrop, `dismissalTapGestureRecognizer.isEnabled` is set to true. @objc public var dismissalTapGestureRecognizer: UITapGestureRecognizer - public init() { + public override init(frame: CGRect = .zero) { dismissalTapGestureRecognizer = UITapGestureRecognizer() dismissalTapGestureRecognizer.isEnabled = false - super.init(frame: .zero) + super.init(frame: frame) addGestureRecognizer(dismissalTapGestureRecognizer) } diff --git a/Sources/Core.swift b/Sources/Core.swift index 221ec14c..38b71811 100644 --- a/Sources/Core.swift +++ b/Sources/Core.swift @@ -1267,7 +1267,7 @@ public class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer { self.floatingPanel = floatingPanel } - init() { + override init(target: Any? = nil, action: Selector? = nil) { super.init(target: nil, action: nil) name = "FloatingPanelPanGestureRecognizer" } diff --git a/Sources/GrabberView.swift b/Sources/GrabberView.swift index 75934fd2..599641e9 100644 --- a/Sources/GrabberView.swift +++ b/Sources/GrabberView.swift @@ -12,8 +12,8 @@ public class GrabberView: UIView { super.init(coder: aDecoder) } - init() { - super.init(frame: .zero) + override init(frame: CGRect = .zero) { + super.init(frame: frame) backgroundColor = barColor } From fd4ab55bc8146754f1369b003fe2bf49509b6948 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Thu, 22 Aug 2024 13:52:45 +0900 Subject: [PATCH 08/19] [Workaround] add 'nonisolated(unsafe)' attributes for strict concurrency errors --- Sources/Core.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Sources/Core.swift b/Sources/Core.swift index 38b71811..df03a6ce 100644 --- a/Sources/Core.swift +++ b/Sources/Core.swift @@ -1305,17 +1305,21 @@ public class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer { /// The default object implementing a set methods of the delegate of the gesture recognizer. /// /// Use this property with ``delegateProxy`` when you need to use the default gesture behaviors in a proxy implementation. + nonisolated(unsafe) // Enable to be called in DelegateRouter.responds(to:) and DelegateRouter.forwardingTarget(for :) in Xcode 16 Beta 6 public var delegateOrigin: any UIGestureRecognizerDelegate { - return floatingPanel + MainActor.assumeIsolated { floatingPanel } } /// A proxy object to intercept the default behavior of the gesture recognizer. /// /// `UIGestureRecognizerDelegate` methods implementing by this object are called instead of the default delegate, /// ``delegateOrigin``. + nonisolated(unsafe) // Enable to be called in DelegateRouter.responds(to:) and DelegateRouter.forwardingTarget(for :) in Xcode 16 Beta 6 public weak var delegateProxy: (any UIGestureRecognizerDelegate)? { didSet { - self.delegate = floatingPanel?.panGestureDelegateRouter // Update the cached IMP + MainActor.assumeIsolated { + self.delegate = floatingPanel?.panGestureDelegateRouter // Update the cached IMP + } } } From 9373c0af0bceb4209f901f3d22f593c8475531fb Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Fri, 25 Oct 2024 15:54:26 +0900 Subject: [PATCH 09/19] Remove `nonisolated(unsafe)' for a constant with 'Sendable' type 'OSLog', --- Sources/Logging.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Logging.swift b/Sources/Logging.swift index 25fa051f..e813254b 100644 --- a/Sources/Logging.swift +++ b/Sources/Logging.swift @@ -3,11 +3,11 @@ import os.log let msg = StaticString("%{public}@") -nonisolated(unsafe) let sysLog = OSLog(subsystem: Logging.subsystem, category: Logging.category) +let sysLog = OSLog(subsystem: Logging.subsystem, category: Logging.category) #if FP_LOG let devLog = OSLog(subsystem: Logging.subsystem, category: "\(Logging.category):dev") #else -nonisolated(unsafe) let devLog = OSLog.disabled +let devLog = OSLog.disabled #endif struct Logging { From ae20dfd934f8ddd2f892facc03f2786368a5da20 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Fri, 25 Oct 2024 16:07:49 +0900 Subject: [PATCH 10/19] Fix testing issues --- Tests/ControllerTests.swift | 1 + Tests/CoreTests.swift | 1 + Tests/LayoutTests.swift | 3 +++ Tests/TestSupports.swift | 2 ++ 4 files changed, 7 insertions(+) diff --git a/Tests/ControllerTests.swift b/Tests/ControllerTests.swift index e0f41b16..49a5d712 100644 --- a/Tests/ControllerTests.swift +++ b/Tests/ControllerTests.swift @@ -4,6 +4,7 @@ import OSLog import XCTest @testable import FloatingPanel +@MainActor class ControllerTests: XCTestCase { override func setUp() {} override func tearDown() {} diff --git a/Tests/CoreTests.swift b/Tests/CoreTests.swift index 9dfda5e3..32754d99 100644 --- a/Tests/CoreTests.swift +++ b/Tests/CoreTests.swift @@ -3,6 +3,7 @@ import XCTest @testable import FloatingPanel +@MainActor class CoreTests: XCTestCase { override func setUp() {} override func tearDown() {} diff --git a/Tests/LayoutTests.swift b/Tests/LayoutTests.swift index b99a9ca5..315ed90f 100644 --- a/Tests/LayoutTests.swift +++ b/Tests/LayoutTests.swift @@ -3,6 +3,7 @@ import XCTest @testable import FloatingPanel +@MainActor class LayoutTests: XCTestCase { var fpc: FloatingPanelController! override func setUp() { @@ -662,6 +663,8 @@ class LayoutTests: XCTestCase { } private typealias LayoutSegmentTestParameter = (UInt, pos: CGFloat, forwardY: Bool, lower: FloatingPanelState?, upper: FloatingPanelState?) + +@MainActor private func assertLayoutSegment(_ floatingPanel: Core, with params: [LayoutSegmentTestParameter]) { params.forEach { (line, pos, forwardY, lowr, upper) in let segment = floatingPanel.layoutAdapter.segment(at: pos, forward: forwardY) diff --git a/Tests/TestSupports.swift b/Tests/TestSupports.swift index 9601cfe7..44fd38cb 100644 --- a/Tests/TestSupports.swift +++ b/Tests/TestSupports.swift @@ -16,6 +16,8 @@ extension FloatingPanelController { } class FloatingPanelTestDelegate: FloatingPanelControllerDelegate { + @MainActor + init() {} var position: FloatingPanelState = .hidden var didMoveCallback: ((FloatingPanelController) -> Void)? func floatingPanelDidChangeState(_ vc: FloatingPanelController) { From fef6cbd384d494fbd28af935b286872c0a5af3c1 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Fri, 25 Oct 2024 16:15:07 +0900 Subject: [PATCH 11/19] Suppress retroactive confirmance warnings --- Sources/Extensions.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Extensions.swift b/Sources/Extensions.swift index 248bd81c..1a5e2c46 100644 --- a/Sources/Extensions.swift +++ b/Sources/Extensions.swift @@ -94,7 +94,7 @@ extension UIView { } #if FP_LOG -extension UIGestureRecognizer.State: CustomDebugStringConvertible { +extension UIGestureRecognizer.State: @retroactive CustomDebugStringConvertible { public var debugDescription: String { switch self { case .began: return "began" From d9f01cc5b334bae9fbae4f54cd3bb91b7b38adb7 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Mon, 21 Oct 2024 22:02:39 +0900 Subject: [PATCH 12/19] Set ENABLE_USER_SCRIPT_SANDBOXING to YES --- Examples/Maps-SwiftUI/Maps-SwiftUI.xcodeproj/project.pbxproj | 2 ++ Examples/Maps/Maps.xcodeproj/project.pbxproj | 2 ++ Examples/Samples/Samples.xcodeproj/project.pbxproj | 2 ++ Examples/SamplesObjC/SamplesObjC.xcodeproj/project.pbxproj | 2 ++ Examples/Stocks/Stocks.xcodeproj/project.pbxproj | 2 ++ FloatingPanel.xcodeproj/project.pbxproj | 3 +++ 6 files changed, 13 insertions(+) diff --git a/Examples/Maps-SwiftUI/Maps-SwiftUI.xcodeproj/project.pbxproj b/Examples/Maps-SwiftUI/Maps-SwiftUI.xcodeproj/project.pbxproj index 1163657e..59f24c70 100644 --- a/Examples/Maps-SwiftUI/Maps-SwiftUI.xcodeproj/project.pbxproj +++ b/Examples/Maps-SwiftUI/Maps-SwiftUI.xcodeproj/project.pbxproj @@ -234,6 +234,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -295,6 +296,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/Examples/Maps/Maps.xcodeproj/project.pbxproj b/Examples/Maps/Maps.xcodeproj/project.pbxproj index 1e3c59de..dc5c0632 100644 --- a/Examples/Maps/Maps.xcodeproj/project.pbxproj +++ b/Examples/Maps/Maps.xcodeproj/project.pbxproj @@ -248,6 +248,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -310,6 +311,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/Examples/Samples/Samples.xcodeproj/project.pbxproj b/Examples/Samples/Samples.xcodeproj/project.pbxproj index 3ddace28..90ebe43d 100644 --- a/Examples/Samples/Samples.xcodeproj/project.pbxproj +++ b/Examples/Samples/Samples.xcodeproj/project.pbxproj @@ -340,6 +340,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -402,6 +403,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/Examples/SamplesObjC/SamplesObjC.xcodeproj/project.pbxproj b/Examples/SamplesObjC/SamplesObjC.xcodeproj/project.pbxproj index 346599ab..87187cb6 100644 --- a/Examples/SamplesObjC/SamplesObjC.xcodeproj/project.pbxproj +++ b/Examples/SamplesObjC/SamplesObjC.xcodeproj/project.pbxproj @@ -240,6 +240,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -300,6 +301,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/Examples/Stocks/Stocks.xcodeproj/project.pbxproj b/Examples/Stocks/Stocks.xcodeproj/project.pbxproj index c5bb1f6c..0ba0ffa3 100644 --- a/Examples/Stocks/Stocks.xcodeproj/project.pbxproj +++ b/Examples/Stocks/Stocks.xcodeproj/project.pbxproj @@ -232,6 +232,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -294,6 +295,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/FloatingPanel.xcodeproj/project.pbxproj b/FloatingPanel.xcodeproj/project.pbxproj index 07250373..f32adac3 100644 --- a/FloatingPanel.xcodeproj/project.pbxproj +++ b/FloatingPanel.xcodeproj/project.pbxproj @@ -421,6 +421,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -487,6 +488,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -679,6 +681,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; From 1825c08eb5b344cd1117b3159719fb3ab3ad4691 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Wed, 23 Apr 2025 10:26:50 +0900 Subject: [PATCH 13/19] Build Maps example in Swift 6 --- Examples/Maps/Maps.xcodeproj/project.pbxproj | 4 ++-- Examples/Maps/Maps/AppDelegate.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Examples/Maps/Maps.xcodeproj/project.pbxproj b/Examples/Maps/Maps.xcodeproj/project.pbxproj index dc5c0632..47ab2156 100644 --- a/Examples/Maps/Maps.xcodeproj/project.pbxproj +++ b/Examples/Maps/Maps.xcodeproj/project.pbxproj @@ -348,7 +348,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = example.Maps; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -371,7 +371,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = example.Maps; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/Examples/Maps/Maps/AppDelegate.swift b/Examples/Maps/Maps/AppDelegate.swift index 57b82957..1d565918 100644 --- a/Examples/Maps/Maps/AppDelegate.swift +++ b/Examples/Maps/Maps/AppDelegate.swift @@ -2,7 +2,7 @@ import UIKit -@UIApplicationMain +@main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? } From 7ca9050143d28f37ab6df789ee2e5a5e8c0ffca0 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Thu, 23 Oct 2025 13:14:25 +0900 Subject: [PATCH 14/19] Fix compiler errors and warnings on Xcode 26.0.1 --- Sources/Behavior.swift | 4 +-- Sources/Controller.swift | 4 +-- Sources/Core.swift | 2 +- Sources/Layout.swift | 3 +- Sources/SurfaceView.swift | 2 +- .../SwiftUI/FloatingPanelCoordinator.swift | 6 ++++ Sources/SwiftUI/FloatingPanelProxy.swift | 1 + Sources/SwiftUI/FloatingPanelView.swift | 29 ++++++++++++------- Sources/SwiftUI/SurfaceAppearance+.swift | 4 +++ Sources/SwiftUI/View+floatingPanel.swift | 4 +++ .../SwiftUI/View+floatingPanelBehavior.swift | 10 +++++-- .../View+floatingPanelConfiguration.swift | 8 +++-- .../SwiftUI/View+floatingPanelLayout.swift | 12 +++++--- .../View+floatingPanelScrollTracking.swift | 4 +++ Sources/SwiftUI/View+floatingPanelState.swift | 6 +++- .../SwiftUI/View+floatingPanelSurface.swift | 8 +++-- Tests/TestSupports.swift | 2 +- 17 files changed, 78 insertions(+), 31 deletions(-) diff --git a/Sources/Behavior.swift b/Sources/Behavior.swift index d0716b89..afb129a5 100644 --- a/Sources/Behavior.swift +++ b/Sources/Behavior.swift @@ -4,7 +4,7 @@ import UIKit /// An interface for generating behavior information to fine-tune the behavior of a panel. @objc -public protocol FloatingPanelBehavior { +public protocol FloatingPanelBehavior: Sendable { /// A floating-point value that determines the rate of oscillation magnitude reduction after the user lifts their finger. /// /// The oscillation magnitude to attract a panel to an anchor can be adjusted this value between 0.979 and 1.0 @@ -58,7 +58,7 @@ public protocol FloatingPanelBehavior { /// The default behavior object for a panel /// /// This behavior object is fine-tuned to behave as a search panel(card) in Apple Maps on iPhone portrait orientation. -open class FloatingPanelDefaultBehavior: FloatingPanelBehavior { +open class FloatingPanelDefaultBehavior: FloatingPanelBehavior, @unchecked Sendable { public init() {} open var springDecelerationRate: CGFloat { diff --git a/Sources/Controller.swift b/Sources/Controller.swift index 03a29400..68ff92f2 100644 --- a/Sources/Controller.swift +++ b/Sources/Controller.swift @@ -147,14 +147,14 @@ import os.log open class FloatingPanelController: UIViewController { /// Constants indicating how safe area insets are added to the adjusted content inset. @objc - public enum ContentInsetAdjustmentBehavior: Int { + public enum ContentInsetAdjustmentBehavior: Int, Sendable { case always case never } /// A flag used to determine how the controller object lays out the content view when the surface position changes. @objc - public enum ContentMode: Int { + public enum ContentMode: Int, Sendable { /// The option to fix the content to keep the height of the top most position. case `static` /// The option to scale the content to fit the bounds of the root view by changing the surface position. diff --git a/Sources/Core.swift b/Sources/Core.swift index df03a6ce..cef5e6c2 100644 --- a/Sources/Core.swift +++ b/Sources/Core.swift @@ -1305,7 +1305,7 @@ public class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer { /// The default object implementing a set methods of the delegate of the gesture recognizer. /// /// Use this property with ``delegateProxy`` when you need to use the default gesture behaviors in a proxy implementation. - nonisolated(unsafe) // Enable to be called in DelegateRouter.responds(to:) and DelegateRouter.forwardingTarget(for :) in Xcode 16 Beta 6 + nonisolated // Enable to be called in DelegateRouter.responds(to:) and DelegateRouter.forwardingTarget(for :) in Xcode 16 Beta 6 public var delegateOrigin: any UIGestureRecognizerDelegate { MainActor.assumeIsolated { floatingPanel } } diff --git a/Sources/Layout.swift b/Sources/Layout.swift index 38eff34d..a809aeed 100644 --- a/Sources/Layout.swift +++ b/Sources/Layout.swift @@ -25,9 +25,10 @@ import os.log /// A layout object that lays out a panel in bottom sheet style. @objcMembers open class FloatingPanelBottomLayout: NSObject, FloatingPanelLayout { - public override init() { + public nonisolated override init() { super.init() } + open var initialState: FloatingPanelState { return .half } diff --git a/Sources/SurfaceView.swift b/Sources/SurfaceView.swift index 1c02ab90..f59c3a10 100644 --- a/Sources/SurfaceView.swift +++ b/Sources/SurfaceView.swift @@ -6,7 +6,7 @@ import os.log /// An object for customizing the appearance of a surface view @objc(FloatingPanelSurfaceAppearance) @objcMembers -public class SurfaceAppearance: NSObject { +public class SurfaceAppearance: NSObject, @unchecked Sendable { /// An object that represents information to render a shadow @objc(FloatingPanelSurfaceAppearanceShadow) diff --git a/Sources/SwiftUI/FloatingPanelCoordinator.swift b/Sources/SwiftUI/FloatingPanelCoordinator.swift index 408b4def..54069a1c 100644 --- a/Sources/SwiftUI/FloatingPanelCoordinator.swift +++ b/Sources/SwiftUI/FloatingPanelCoordinator.swift @@ -1,7 +1,11 @@ // Copyright 2025 the FloatingPanel authors. All rights reserved. MIT license. #if canImport(SwiftUI) +#if compiler(>=6.0) +public import SwiftUI +#else import SwiftUI +#endif /// A protocol that defines the coordination between SwiftUI and UIKit for FloatingPanel integration. /// @@ -24,6 +28,7 @@ import SwiftUI /// 3. Handle the setup of the floating panel with the provided hosting controllers /// 4. Optionally provide custom implementation for `onUpdate` method @available(iOS 14, *) +@MainActor public protocol FloatingPanelCoordinator { /// The type of events this coordinator can dispatch to its host view. /// @@ -89,6 +94,7 @@ extension FloatingPanelCoordinator { /// and an empty event enumeration. Use this coordinator for basic floating panel integration /// when you don't need custom event handling or special configuration. @available(iOS 14, *) +@MainActor public final class FloatingPanelDefaultCoordinator: FloatingPanelCoordinator { public enum Event {} diff --git a/Sources/SwiftUI/FloatingPanelProxy.swift b/Sources/SwiftUI/FloatingPanelProxy.swift index f786c990..21e8ce7a 100644 --- a/Sources/SwiftUI/FloatingPanelProxy.swift +++ b/Sources/SwiftUI/FloatingPanelProxy.swift @@ -29,6 +29,7 @@ import SwiftUI /// } /// ``` @available(iOS 14, *) +@MainActor public struct FloatingPanelProxy { /// The associated floating panel controller. /// diff --git a/Sources/SwiftUI/FloatingPanelView.swift b/Sources/SwiftUI/FloatingPanelView.swift index 972a150c..c11fc678 100644 --- a/Sources/SwiftUI/FloatingPanelView.swift +++ b/Sources/SwiftUI/FloatingPanelView.swift @@ -62,11 +62,11 @@ struct FloatingPanelView: UIViewControllerRep /// The layout object that defines the position and size of the floating panel. @Environment(\.layout) - private var layout: FloatingPanelLayout + private var layout: any FloatingPanelLayout /// The behavior object that defines the interaction dynamics of the floating panel. @Environment(\.behavior) - private var behavior: FloatingPanelBehavior + private var behavior: any FloatingPanelBehavior /// The behavior for determining the adjusted content insets in the panel. @Environment(\.contentInsetAdjustmentBehavior) @@ -154,15 +154,24 @@ extension FloatingPanelView { /// with a lifecycle that spans across FloatingPanelView as a FloatingPanelCoordinator. This object was created to /// control `FloatingPanelView/state` binding property. @available(iOS 14, *) +@MainActor class FloatingPanelCoordinatorProxy { private let origin: any FloatingPanelCoordinator private var stateBinding: Binding - private var subscriptions: Set = Set() - var proxy: FloatingPanelProxy { origin.proxy } var controller: FloatingPanelController { origin.controller } + class NonSendableBox { + var subscriptions: Set = Set() + deinit { + for subscription in subscriptions { + subscription.cancel() + } + } + } + private var box = NonSendableBox() + init( coordinator: any FloatingPanelCoordinator, state: Binding @@ -171,12 +180,6 @@ class FloatingPanelCoordinatorProxy { self.stateBinding = state } - deinit { - for subscription in subscriptions { - subscription.cancel() - } - } - func setupFloatingPanel( mainHostingController: UIHostingController
, contentHostingController: UIHostingController @@ -199,6 +202,7 @@ extension FloatingPanelCoordinatorProxy { // MARK: - Layout and behavior updates /// Update layout and behavior objects for the specified floating panel. + @MainActor func update( layout: (any FloatingPanelLayout)?, behavior: (any FloatingPanelBehavior)? @@ -228,12 +232,14 @@ extension FloatingPanelCoordinatorProxy { // MARK: - State updates // Update the state of FloatingPanelController + @MainActor func update(state: FloatingPanelState?) { guard let state = state else { return } controller.move(to: state, animated: false) } /// Start observing ``FloatingPanelController/state`` through the `Core` object. + @MainActor func observeStateChanges() { controller.floatingPanel.statePublisher .sink { [weak self] state in @@ -243,7 +249,7 @@ extension FloatingPanelCoordinatorProxy { Task { @MainActor in self.stateBinding.wrappedValue = state } - }.store(in: &subscriptions) + }.store(in: &box.subscriptions) } } @@ -252,6 +258,7 @@ extension FloatingPanelCoordinatorProxy { // MARK: - Environment updates /// Applies animatable environment value changes. + @MainActor func apply(animatableChanges: @escaping () -> Void, transaction: Transaction) { /// Returns the default animator object for compatibility with iOS 17 and earlier. func animateUsingDefaultAnimator(changes: @escaping () -> Void) { diff --git a/Sources/SwiftUI/SurfaceAppearance+.swift b/Sources/SwiftUI/SurfaceAppearance+.swift index 8c2b9893..1ed7eeb8 100644 --- a/Sources/SwiftUI/SurfaceAppearance+.swift +++ b/Sources/SwiftUI/SurfaceAppearance+.swift @@ -1,7 +1,11 @@ // Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license. #if canImport(SwiftUI) +#if compiler(>=6.0) +public import SwiftUI +#else import SwiftUI +#endif @available(iOS 14, *) extension FloatingPanel.SurfaceAppearance { diff --git a/Sources/SwiftUI/View+floatingPanel.swift b/Sources/SwiftUI/View+floatingPanel.swift index 24905a47..5e585076 100644 --- a/Sources/SwiftUI/View+floatingPanel.swift +++ b/Sources/SwiftUI/View+floatingPanel.swift @@ -1,7 +1,11 @@ // Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license. #if canImport(SwiftUI) +#if compiler(>=6.0) +public import SwiftUI +#else import SwiftUI +#endif @available(iOS 14, *) extension View { diff --git a/Sources/SwiftUI/View+floatingPanelBehavior.swift b/Sources/SwiftUI/View+floatingPanelBehavior.swift index a41482ae..f3e16523 100644 --- a/Sources/SwiftUI/View+floatingPanelBehavior.swift +++ b/Sources/SwiftUI/View+floatingPanelBehavior.swift @@ -1,15 +1,19 @@ // Copyright 2025 the FloatingPanel authors. All rights reserved. MIT license. #if canImport(SwiftUI) +#if compiler(>=6.0) +public import SwiftUI +#else import SwiftUI +#endif @available(iOS 14, *) extension EnvironmentValues { struct BehaviorKey: EnvironmentKey { - static var defaultValue: FloatingPanelBehavior = FloatingPanelDefaultBehavior() + static let defaultValue: any FloatingPanelBehavior = FloatingPanelDefaultBehavior() } - var behavior: FloatingPanelBehavior { + var behavior: any FloatingPanelBehavior { get { self[BehaviorKey.self] } set { self[BehaviorKey.self] = newValue } } @@ -54,7 +58,7 @@ extension View { /// - Parameter behavior: An object conforming to the `FloatingPanelBehavior` protocol /// that controls the panel's interactive dynamics, or `nil` to use the default behavior. public func floatingPanelBehavior( - _ behavior: FloatingPanelBehavior? + _ behavior: (any FloatingPanelBehavior)? ) -> some View { environment(\.behavior, behavior ?? FloatingPanelDefaultBehavior()) } diff --git a/Sources/SwiftUI/View+floatingPanelConfiguration.swift b/Sources/SwiftUI/View+floatingPanelConfiguration.swift index 16cc133e..3abe00e4 100644 --- a/Sources/SwiftUI/View+floatingPanelConfiguration.swift +++ b/Sources/SwiftUI/View+floatingPanelConfiguration.swift @@ -1,12 +1,16 @@ // Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license. #if canImport(SwiftUI) +#if compiler(>=6.0) +public import SwiftUI +#else import SwiftUI +#endif @available(iOS 14, *) extension EnvironmentValues { struct ContentInsetAdjustmentBehaviorKey: EnvironmentKey { - static var defaultValue: FloatingPanelController.ContentInsetAdjustmentBehavior = .always + static let defaultValue: FloatingPanelController.ContentInsetAdjustmentBehavior = .always } var contentInsetAdjustmentBehavior: FloatingPanelController.ContentInsetAdjustmentBehavior { @@ -15,7 +19,7 @@ extension EnvironmentValues { } struct ContentModeKey: EnvironmentKey { - static var defaultValue: FloatingPanelController.ContentMode = .static + static let defaultValue: FloatingPanelController.ContentMode = .static } var contentMode: FloatingPanelController.ContentMode { diff --git a/Sources/SwiftUI/View+floatingPanelLayout.swift b/Sources/SwiftUI/View+floatingPanelLayout.swift index 50399c27..08646513 100644 --- a/Sources/SwiftUI/View+floatingPanelLayout.swift +++ b/Sources/SwiftUI/View+floatingPanelLayout.swift @@ -1,15 +1,19 @@ // Copyright 2025 the FloatingPanel authors. All rights reserved. MIT license. #if canImport(SwiftUI) +#if compiler(>=6.0) +public import SwiftUI +#else import SwiftUI +#endif @available(iOS 14, *) extension EnvironmentValues { - struct LayoutKey: EnvironmentKey { - static var defaultValue: FloatingPanelLayout = FloatingPanelBottomLayout() + private struct LayoutKey: EnvironmentKey { + static var defaultValue: any FloatingPanelLayout { FloatingPanelBottomLayout() } } - var layout: FloatingPanelLayout { + var layout: any FloatingPanelLayout { get { self[LayoutKey.self] } set { self[LayoutKey.self] = newValue } } @@ -63,7 +67,7 @@ extension View { /// - Parameter layout: An object conforming to the `FloatingPanelLayout` protocol /// that defines the panel's position and dimensions, or `nil` to use the default layout. public func floatingPanelLayout( - _ layout: FloatingPanelLayout? + _ layout: (any FloatingPanelLayout)? ) -> some View { environment(\.layout, layout ?? FloatingPanelBottomLayout()) } diff --git a/Sources/SwiftUI/View+floatingPanelScrollTracking.swift b/Sources/SwiftUI/View+floatingPanelScrollTracking.swift index 5be422e5..1957332b 100644 --- a/Sources/SwiftUI/View+floatingPanelScrollTracking.swift +++ b/Sources/SwiftUI/View+floatingPanelScrollTracking.swift @@ -1,7 +1,11 @@ // Copyright 2025 the FloatingPanel authors. All rights reserved. MIT license. #if canImport(SwiftUI) +#if compiler(>=6.0) +public import SwiftUI +#else import SwiftUI +#endif @available(iOS 14, *) extension View { diff --git a/Sources/SwiftUI/View+floatingPanelState.swift b/Sources/SwiftUI/View+floatingPanelState.swift index a43cbee5..415d6dbb 100644 --- a/Sources/SwiftUI/View+floatingPanelState.swift +++ b/Sources/SwiftUI/View+floatingPanelState.swift @@ -1,12 +1,16 @@ // Copyright 2025 the FloatingPanel authors. All rights reserved. MIT license. #if canImport(SwiftUI) +#if compiler(>=6.0) +public import SwiftUI +#else import SwiftUI +#endif @available(iOS 14, *) extension EnvironmentValues { struct StateKey: EnvironmentKey { - static var defaultValue: Binding = .constant(nil) + static let defaultValue: Binding = .constant(nil) } var state: Binding { diff --git a/Sources/SwiftUI/View+floatingPanelSurface.swift b/Sources/SwiftUI/View+floatingPanelSurface.swift index 7f9276fd..b34acb45 100644 --- a/Sources/SwiftUI/View+floatingPanelSurface.swift +++ b/Sources/SwiftUI/View+floatingPanelSurface.swift @@ -1,12 +1,16 @@ // Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license. #if canImport(SwiftUI) +#if compiler(>=6.0) +public import SwiftUI +#else import SwiftUI +#endif @available(iOS 14, *) extension EnvironmentValues { struct SurfaceAppearanceKey: EnvironmentKey { - static var defaultValue = SurfaceAppearance() + static let defaultValue = SurfaceAppearance() } var surfaceAppearance: SurfaceAppearance { @@ -15,7 +19,7 @@ extension EnvironmentValues { } struct GrabberHandlePaddingKey: EnvironmentKey { - static var defaultValue: CGFloat = 6.0 + static let defaultValue: CGFloat = 6.0 } var grabberHandlePadding: CGFloat { diff --git a/Tests/TestSupports.swift b/Tests/TestSupports.swift index 44fd38cb..88eea760 100644 --- a/Tests/TestSupports.swift +++ b/Tests/TestSupports.swift @@ -84,7 +84,7 @@ class FloatingPanelTopPositionedLayout: FloatingPanelLayout { ] } -class FloatingPanelProjectableBehavior: FloatingPanelBehavior { +final class FloatingPanelProjectableBehavior: FloatingPanelBehavior { func shouldProjectMomentum(_ fpc: FloatingPanelController, to proposedState: FloatingPanelState) -> Bool { return true } From 11abecc777cb8355331cf46ed0e92fe28828c7f0 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Thu, 23 Oct 2025 13:45:08 +0900 Subject: [PATCH 15/19] Resolve warnings on Maps app --- Examples/Maps/Maps/MainViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Examples/Maps/Maps/MainViewController.swift b/Examples/Maps/Maps/MainViewController.swift index dd8d54c3..73ea65c0 100644 --- a/Examples/Maps/Maps/MainViewController.swift +++ b/Examples/Maps/Maps/MainViewController.swift @@ -310,7 +310,7 @@ class SearchPanelPadLayout: FloatingPanelLayout { } } -class SearchPaneliPadBehavior: FloatingPanelBehavior { +final class SearchPaneliPadBehavior: FloatingPanelBehavior { var springDecelerationRate: CGFloat { return UIScrollView.DecelerationRate.fast.rawValue - 0.003 } From aeaef60c832fd653e46ae45ea68c32da368ae823 Mon Sep 17 00:00:00 2001 From: Shin Yamamoto Date: Thu, 23 Oct 2025 13:45:31 +0900 Subject: [PATCH 16/19] Resolve warnings on Samples app --- .../Sources/Base.lproj/Main.storyboard | 26 +++++++------------ .../TabBarViewController.swift | 2 +- .../Sources/UseCases/UseCaseController.swift | 9 ++++--- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Examples/Samples/Sources/Base.lproj/Main.storyboard b/Examples/Samples/Sources/Base.lproj/Main.storyboard index 25e176b5..e7ae157e 100644 --- a/Examples/Samples/Sources/Base.lproj/Main.storyboard +++ b/Examples/Samples/Sources/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -15,7 +15,6 @@ - @@ -87,7 +86,7 @@ - + @@ -270,7 +269,7 @@ - +