From 860049639efd50dab4f27c20fb5d91fb6380a790 Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Tue, 29 Apr 2025 14:13:22 -0400 Subject: [PATCH 01/17] Bump to deployment target iOS 13 --- Example/ImageSlideshow.xcodeproj/project.pbxproj | 14 ++++++++------ Example/Podfile | 2 +- ImageSlideshow.podspec | 4 ++-- Package.swift | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Example/ImageSlideshow.xcodeproj/project.pbxproj b/Example/ImageSlideshow.xcodeproj/project.pbxproj index 888725d1..47cc209f 100644 --- a/Example/ImageSlideshow.xcodeproj/project.pbxproj +++ b/Example/ImageSlideshow.xcodeproj/project.pbxproj @@ -543,7 +543,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -592,7 +592,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -608,7 +608,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 5VWB99DS38; INFOPLIST_FILE = ImageSlideshow/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MODULE_NAME = ExampleApp; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; @@ -624,7 +624,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 5VWB99DS38; INFOPLIST_FILE = ImageSlideshow/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MODULE_NAME = ExampleApp; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; @@ -644,6 +644,7 @@ "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -659,6 +660,7 @@ DEVELOPMENT_TEAM = 5VWB99DS38; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -684,7 +686,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = ImageSlideshow_framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "io.zvo.ImageSlideshow-framework"; PRODUCT_NAME = ImageSlideshow; @@ -713,7 +715,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = ImageSlideshow_framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "io.zvo.ImageSlideshow-framework"; PRODUCT_NAME = ImageSlideshow; diff --git a/Example/Podfile b/Example/Podfile index f36da01c..4f62ec06 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -1,4 +1,4 @@ -platform :ios, '10.0' +platform :ios, '13.0' use_frameworks! target 'ImageSlideshow_Example' do diff --git a/ImageSlideshow.podspec b/ImageSlideshow.podspec index db075e96..52d75835 100644 --- a/ImageSlideshow.podspec +++ b/ImageSlideshow.podspec @@ -28,7 +28,7 @@ Image slideshow is a Swift library providing customizable image slideshow with c s.social_media_url = 'https://twitter.com/zvonicek' s.swift_versions = ['4.0', '4.1', '4.2', '5', '5.1', '5.2'] - s.platform = :ios, '8.0' + s.platform = :ios, '13.0' s.requires_arc = true s.subspec 'Core' do |core| @@ -64,7 +64,7 @@ Image slideshow is a Swift library providing customizable image slideshow with c s.subspec 'Kingfisher' do |subspec| subspec.dependency 'ImageSlideshow/Core' subspec.dependency 'Kingfisher', '> 3.0' - subspec.platform = :ios, '10.0' + subspec.platform = :ios, '13.0' subspec.source_files = 'ImageSlideshow/Classes/InputSources/KingfisherSource.swift' end diff --git a/Package.swift b/Package.swift index 3e4f65c9..59e83af7 100644 --- a/Package.swift +++ b/Package.swift @@ -5,7 +5,7 @@ import PackageDescription let package = Package( name: "ImageSlideshow", platforms: [ - .iOS(.v10), + .iOS(.v13), ], products: [ .library( From d02c4e43ec790c08c173203c6e6d1a094d20180a Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Tue, 29 Apr 2025 14:26:03 -0400 Subject: [PATCH 02/17] Update external Library --- Example/Podfile.lock | 53 ++++++++++++++++++++---------------------- ImageSlideshow.podspec | 2 +- Package.resolved | 4 ++-- Package.swift | 6 ++--- 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/Example/Podfile.lock b/Example/Podfile.lock index f652f1a9..f0bdeafa 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,26 +1,25 @@ PODS: - - AFNetworking (3.2.1): - - AFNetworking/NSURLSession (= 3.2.1) - - AFNetworking/Reachability (= 3.2.1) - - AFNetworking/Security (= 3.2.1) - - AFNetworking/Serialization (= 3.2.1) - - AFNetworking/UIKit (= 3.2.1) - - AFNetworking/NSURLSession (3.2.1): + - AFNetworking (4.0.1): + - AFNetworking/NSURLSession (= 4.0.1) + - AFNetworking/Reachability (= 4.0.1) + - AFNetworking/Security (= 4.0.1) + - AFNetworking/Serialization (= 4.0.1) + - AFNetworking/UIKit (= 4.0.1) + - AFNetworking/NSURLSession (4.0.1): - AFNetworking/Reachability - AFNetworking/Security - AFNetworking/Serialization - - AFNetworking/Reachability (3.2.1) - - AFNetworking/Security (3.2.1) - - AFNetworking/Serialization (3.2.1) - - AFNetworking/UIKit (3.2.1): + - AFNetworking/Reachability (4.0.1) + - AFNetworking/Security (4.0.1) + - AFNetworking/Serialization (4.0.1) + - AFNetworking/UIKit (4.0.1): - AFNetworking/NSURLSession - - Alamofire (5.2.1) - - AlamofireImage (4.1.0): - - Alamofire (~> 5.1) - ImageSlideshow (1.9.0): - ImageSlideshow/Core (= 1.9.0) - ImageSlideshow/AFURL (1.9.0): - - AFNetworking (~> 3.0) + - Alamofire (5.10.2) + - AlamofireImage (4.3.0): + - Alamofire (~> 5.8) - ImageSlideshow/Core - ImageSlideshow/Alamofire (1.9.0): - AlamofireImage (~> 4.0) @@ -32,12 +31,10 @@ PODS: - ImageSlideshow/SDWebImage (1.9.0): - ImageSlideshow/Core - SDWebImage (>= 3.7) - - Kingfisher (5.14.0): - - Kingfisher/Core (= 5.14.0) - - Kingfisher/Core (5.14.0) - - SDWebImage (5.8.1): - - SDWebImage/Core (= 5.8.1) - - SDWebImage/Core (5.8.1) + - Kingfisher (8.3.2) + - SDWebImage (5.21.0): + - SDWebImage/Core (= 5.21.0) + - SDWebImage/Core (5.21.0) DEPENDENCIES: - ImageSlideshow (from `../`) @@ -59,13 +56,13 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - AFNetworking: b6f891fdfaed196b46c7a83cf209e09697b94057 - Alamofire: e911732990610fe89af59ac0077f923d72dc3dfd - AlamofireImage: c4a2ba349885fb3064feb74d2e547bd42ce9be10 ImageSlideshow: a90cc3568a325cdf1bd543732a2cfcf6361d0dc1 - Kingfisher: 7b64389a43139c903ec434788344c288217c792d - SDWebImage: e3eae2eda88578db0685a0c88597fdadd9433f05 + AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58 + Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496 + AlamofireImage: 843953fa97bee5f561cf05d83abd759e590b068d + Kingfisher: 0621d0ac0c78fecb19f6dc5303bde2b52abaf2f5 + SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868 -PODFILE CHECKSUM: 46015634277c8c8bfd78d1b363e41ea2dfd179d9 +PODFILE CHECKSUM: 19810162c1a79de96d3684e707a993a0b605e6d7 -COCOAPODS: 1.9.3 +COCOAPODS: 1.16.2 diff --git a/ImageSlideshow.podspec b/ImageSlideshow.podspec index 52d75835..e313d146 100644 --- a/ImageSlideshow.podspec +++ b/ImageSlideshow.podspec @@ -38,7 +38,7 @@ Image slideshow is a Swift library providing customizable image slideshow with c s.subspec 'AFURL' do |subspec| subspec.dependency 'ImageSlideshow/Core' - subspec.dependency 'AFNetworking', '~> 3.0' + subspec.dependency 'AFNetworking', '~> 4.0' subspec.source_files = 'ImageSlideshow/Classes/InputSources/AFURLSource.swift' end diff --git a/Package.resolved b/Package.resolved index 28277c26..316551e6 100644 --- a/Package.resolved +++ b/Package.resolved @@ -24,8 +24,8 @@ "repositoryURL": "https://github.com/onevcat/Kingfisher.git", "state": { "branch": null, - "revision": "349ed06467a6f8a4939bcb83db301542bc84eac9", - "version": "5.13.4" + "revision": "7deda23bbdca612076c5c315003d8638a08ed0f1", + "version": "8.3.2" } }, { diff --git a/Package.swift b/Package.swift index 59e83af7..46566b56 100644 --- a/Package.swift +++ b/Package.swift @@ -22,9 +22,9 @@ let package = Package( targets: ["ImageSlideshowKingfisher"]) ], dependencies: [ - .package(url: "https://github.com/onevcat/Kingfisher.git", from: "5.8.0"), - .package(url: "https://github.com/Alamofire/AlamofireImage.git", from: "4.0.0"), - .package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.1.0") + .package(url: "https://github.com/onevcat/Kingfisher.git", from: "8.3.2"), + .package(url: "https://github.com/Alamofire/AlamofireImage.git", from: "5.10.2"), + .package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.21.0") ], targets: [ .target( From cb571a624e7859e771b05d2c8571c36536fef0d9 Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Tue, 29 Apr 2025 14:26:27 -0400 Subject: [PATCH 03/17] Fix Kingfisher error --- .../InputSources/KingfisherSource.swift | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ImageSlideshow/Classes/InputSources/KingfisherSource.swift b/ImageSlideshow/Classes/InputSources/KingfisherSource.swift index f02394d2..d49b4d59 100644 --- a/ImageSlideshow/Classes/InputSources/KingfisherSource.swift +++ b/ImageSlideshow/Classes/InputSources/KingfisherSource.swift @@ -56,12 +56,14 @@ public class KingfisherSource: NSObject, InputSource { /// - callback: Completion callback with an optional image @objc public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { - imageView.kf.setImage(with: self.url, placeholder: self.placeholder, options: self.options, progressBlock: nil) { result in - switch result { - case .success(let image): - callback(image.image) - case .failure: - callback(self.placeholder) + Task { @MainActor in + imageView.kf.setImage(with: self.url, placeholder: self.placeholder, options: self.options, progressBlock: nil) { result in + switch result { + case .success(let image): + callback(image.image) + case .failure: + callback(self.placeholder) + } } } } @@ -70,6 +72,8 @@ public class KingfisherSource: NSObject, InputSource { /// /// - Parameter imageView: UIImage view with the download task that should be canceled public func cancelLoad(on imageView: UIImageView) { - imageView.kf.cancelDownloadTask() + Task { @MainActor in + imageView.kf.cancelDownloadTask() + } } } From 22c58eafbcb97abc11e2bcada2998c72a39cbdac Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Tue, 29 Apr 2025 14:27:00 -0400 Subject: [PATCH 04/17] Bump to version 1.9.3 --- Example/Podfile.lock | 17 +++++++++-------- ImageSlideshow.podspec | 2 +- README.md | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Example/Podfile.lock b/Example/Podfile.lock index f0bdeafa..eef0f8ee 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -14,21 +14,22 @@ PODS: - AFNetworking/Serialization (4.0.1) - AFNetworking/UIKit (4.0.1): - AFNetworking/NSURLSession - - ImageSlideshow (1.9.0): - - ImageSlideshow/Core (= 1.9.0) - - ImageSlideshow/AFURL (1.9.0): - Alamofire (5.10.2) - AlamofireImage (4.3.0): - Alamofire (~> 5.8) + - ImageSlideshow (1.9.3): + - ImageSlideshow/Core (= 1.9.3) + - ImageSlideshow/AFURL (1.9.3): + - AFNetworking (~> 4.0) - ImageSlideshow/Core - - ImageSlideshow/Alamofire (1.9.0): + - ImageSlideshow/Alamofire (1.9.3): - AlamofireImage (~> 4.0) - ImageSlideshow/Core - - ImageSlideshow/Core (1.9.0) - - ImageSlideshow/Kingfisher (1.9.0): + - ImageSlideshow/Core (1.9.3) + - ImageSlideshow/Kingfisher (1.9.3): - ImageSlideshow/Core - Kingfisher (> 3.0) - - ImageSlideshow/SDWebImage (1.9.0): + - ImageSlideshow/SDWebImage (1.9.3): - ImageSlideshow/Core - SDWebImage (>= 3.7) - Kingfisher (8.3.2) @@ -56,10 +57,10 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - ImageSlideshow: a90cc3568a325cdf1bd543732a2cfcf6361d0dc1 AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58 Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496 AlamofireImage: 843953fa97bee5f561cf05d83abd759e590b068d + ImageSlideshow: 7ec9503e623329cb09a970418a02e42f8ef92827 Kingfisher: 0621d0ac0c78fecb19f6dc5303bde2b52abaf2f5 SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868 diff --git a/ImageSlideshow.podspec b/ImageSlideshow.podspec index e313d146..aa1b5037 100644 --- a/ImageSlideshow.podspec +++ b/ImageSlideshow.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = "ImageSlideshow" - s.version = "1.9.2" + s.version = "1.9.3" s.summary = "Image slideshow written in Swift with circular scrolling, timer and full screen viewer" # This description is used to generate tags and improve search results. diff --git a/README.md b/README.md index 3364d073..6ab094a6 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ ImageSlideshow is available through [CocoaPods](http://cocoapods.org). To instal it, simply add the following line to your Podfile: ```ruby -pod 'ImageSlideshow', '~> 1.9.0' +pod 'ImageSlideshow', '~> 1.9.3' ``` ### Carthage To integrate ImageSlideshow into your Xcode project using Carthage, specify it in your Cartfile: ```ruby -github "zvonicek/ImageSlideshow" ~> 1.9.0 +github "zvonicek/ImageSlideshow" ~> 1.9.3 ``` Carthage does not include InputSources for external providers (due to dependency on those providers) so you need to grab the one you need from `ImageSlideshow/Classes/InputSources` manually. From dd61e90536606d559125e2baa87ab3d9dad7b12b Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Fri, 12 Jun 2026 00:52:03 -0400 Subject: [PATCH 05/17] Drop pre-iOS 13 compatibility code and modernize UIKit usage Remove the Swift 4.2 typealias shims (SwiftSupport.swift), #available guards for iOS 11/13, and legacy API spellings now that the minimum deployment target guarantees them. Set isModalInPresentation directly instead of via KVC. In the zoom transition, look up the key window via connectedScenes and remove the dismiss gesture recognizer from the window it was actually added to rather than re-querying the key window. Co-Authored-By: Claude Fable 5 --- Example/ImageSlideshow/ViewController.swift | 4 +- .../FullScreenSlideshowViewController.swift | 48 ++- .../Classes/Core/ImageSlideshow.swift | 206 ++++++++--- .../Classes/Core/ImageSlideshowItem.swift | 61 +++- .../Classes/Core/PageIndicator.swift | 33 +- .../Classes/Core/SwiftSupport.swift | 9 - .../Core/ZoomAnimatedTransitioning.swift | 334 +++++++++++++----- 7 files changed, 486 insertions(+), 209 deletions(-) diff --git a/Example/ImageSlideshow/ViewController.swift b/Example/ImageSlideshow/ViewController.swift index f4cb7aef..36fa63c3 100644 --- a/Example/ImageSlideshow/ViewController.swift +++ b/Example/ImageSlideshow/ViewController.swift @@ -28,7 +28,7 @@ class ViewController: UIViewController { slideshow.slideshowInterval = 5.0 slideshow.pageIndicatorPosition = .init(horizontal: .center, vertical: .under) - slideshow.contentScaleMode = UIViewContentMode.scaleAspectFill + slideshow.contentScaleMode = .scaleAspectFill slideshow.pageIndicator = UIPageControl.withSlideshowColors() @@ -46,7 +46,7 @@ class ViewController: UIViewController { @objc func didTap() { let fullScreenController = slideshow.presentFullScreenController(from: self) // set the activity indicator for full screen controller (skipping the line will show no activity indicator) - fullScreenController.slideshow.activityIndicator = DefaultActivityIndicator(style: .white, color: nil) + fullScreenController.slideshow.activityIndicator = DefaultActivityIndicator(style: .medium, color: nil) } } diff --git a/ImageSlideshow/Classes/Core/FullScreenSlideshowViewController.swift b/ImageSlideshow/Classes/Core/FullScreenSlideshowViewController.swift index 6aac7426..b38734d8 100644 --- a/ImageSlideshow/Classes/Core/FullScreenSlideshowViewController.swift +++ b/ImageSlideshow/Classes/Core/FullScreenSlideshowViewController.swift @@ -13,16 +13,21 @@ open class FullScreenSlideshowViewController: UIViewController { open var slideshow: ImageSlideshow = { let slideshow = ImageSlideshow() slideshow.zoomEnabled = true - slideshow.contentScaleMode = UIViewContentMode.scaleAspectFit - slideshow.pageIndicatorPosition = PageIndicatorPosition(horizontal: .center, vertical: .bottom) + slideshow.contentScaleMode = UIView.ContentMode.scaleAspectFit + slideshow.pageIndicatorPosition = PageIndicatorPosition( + horizontal: .center, + vertical: .bottom + ) // turns off the timer slideshow.slideshowInterval = 0 - slideshow.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight] + slideshow.autoresizingMask = [ + UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight, + ] return slideshow }() - /// Close button + /// Close button open var closeButton = UIButton() /// Close button frame @@ -34,7 +39,7 @@ open class FullScreenSlideshowViewController: UIViewController { /// Index of initial image open var initialPage: Int = 0 - /// Input sources to + /// Input sources to open var inputs: [InputSource]? /// Background color @@ -53,10 +58,7 @@ open class FullScreenSlideshowViewController: UIViewController { self.init(nibName: nil, bundle: nil) self.modalPresentationStyle = .custom - if #available(iOS 13.0, *) { - // Use KVC to set the value to preserve backwards compatiblity with Xcode < 11 - self.setValue(true, forKey: "modalInPresentation") - } + self.isModalInPresentation = true } override open func viewDidLoad() { @@ -72,8 +74,15 @@ open class FullScreenSlideshowViewController: UIViewController { view.addSubview(slideshow) // close button configuration - closeButton.setImage(UIImage(named: "ic_cross_white", in: .module, compatibleWith: nil), for: UIControlState()) - closeButton.addTarget(self, action: #selector(FullScreenSlideshowViewController.close), for: UIControlEvents.touchUpInside) + closeButton.setImage( + UIImage(named: "ic_cross_white", in: .module, compatibleWith: nil), + for: UIControl.State() + ) + closeButton.addTarget( + self, + action: #selector(FullScreenSlideshowViewController.close), + for: UIControl.Event.touchUpInside + ) view.addSubview(closeButton) } @@ -102,13 +111,16 @@ open class FullScreenSlideshowViewController: UIViewController { open override func viewDidLayoutSubviews() { if !isBeingDismissed { let safeAreaInsets: UIEdgeInsets - if #available(iOS 11.0, *) { - safeAreaInsets = view.safeAreaInsets - } else { - safeAreaInsets = UIEdgeInsets.zero - } - - closeButton.frame = closeButtonFrame ?? CGRect(x: max(10, safeAreaInsets.left), y: max(10, safeAreaInsets.top), width: 40, height: 40) + safeAreaInsets = view.safeAreaInsets + + closeButton.frame = + closeButtonFrame + ?? CGRect( + x: max(10, safeAreaInsets.left), + y: max(10, safeAreaInsets.top), + width: 40, + height: 40 + ) } slideshow.frame = view.frame diff --git a/ImageSlideshow/Classes/Core/ImageSlideshow.swift b/ImageSlideshow/Classes/Core/ImageSlideshow.swift index 936a002e..4c7baac8 100644 --- a/ImageSlideshow/Classes/Core/ImageSlideshow.swift +++ b/ImageSlideshow/Classes/Core/ImageSlideshow.swift @@ -9,32 +9,38 @@ import UIKit @objc /// The delegate protocol informing about image slideshow state changes -public protocol ImageSlideshowDelegate: class { +public protocol ImageSlideshowDelegate: AnyObject { /// Tells the delegate that the current page has changed /// /// - Parameters: /// - imageSlideshow: image slideshow instance /// - page: new page - @objc optional func imageSlideshow(_ imageSlideshow: ImageSlideshow, didChangeCurrentPageTo page: Int) + @objc optional func imageSlideshow( + _ imageSlideshow: ImageSlideshow, + didChangeCurrentPageTo page: Int + ) /// Tells the delegate that the slideshow will begin dragging /// /// - Parameter imageSlideshow: image slideshow instance - @objc optional func imageSlideshowWillBeginDragging(_ imageSlideshow: ImageSlideshow) + @objc optional func imageSlideshowWillBeginDragging( + _ imageSlideshow: ImageSlideshow + ) /// Tells the delegate that the slideshow did end decelerating /// /// - Parameter imageSlideshow: image slideshow instance - @objc optional func imageSlideshowDidEndDecelerating(_ imageSlideshow: ImageSlideshow) + @objc optional func imageSlideshowDidEndDecelerating( + _ imageSlideshow: ImageSlideshow + ) } -/** - Used to represent position of the Page Control - - hidden: Page Control is hidden - - insideScrollView: Page Control is inside image slideshow - - underScrollView: Page Control is under image slideshow - - custom: Custom vertical padding, relative to "insideScrollView" position - */ +/// +/// Used to represent position of the Page Control +/// - hidden: Page Control is hidden +/// - insideScrollView: Page Control is inside image slideshow +/// - underScrollView: Page Control is under image slideshow +/// - custom: Custom vertical padding, relative to "insideScrollView" position public enum PageControlPosition { case hidden case insideScrollView @@ -80,14 +86,20 @@ open class ImageSlideshow: UIView { if let pageIndicator = pageIndicator { addSubview(pageIndicator.view) if let pageIndicator = pageIndicator as? UIControl { - pageIndicator.addTarget(self, action: #selector(pageControlValueChanged), for: .valueChanged) + pageIndicator.addTarget( + self, + action: #selector(pageControlValueChanged), + for: .valueChanged + ) } } setNeedsLayout() } } - open var pageIndicatorPosition: PageIndicatorPosition = PageIndicatorPosition() { + open var pageIndicatorPosition: PageIndicatorPosition = + PageIndicatorPosition() + { didSet { setNeedsLayout() } @@ -108,7 +120,9 @@ open class ImageSlideshow: UIView { case .underScrollView: pageIndicatorPosition = PageIndicatorPosition(vertical: .under) case .custom(let padding): - pageIndicatorPosition = PageIndicatorPosition(vertical: .customUnder(padding: padding-30)) + pageIndicatorPosition = PageIndicatorPosition( + vertical: .customUnder(padding: padding - 30) + ) } } } @@ -119,7 +133,10 @@ open class ImageSlideshow: UIView { if oldValue != currentPage { pageIndicator?.page = currentPage currentPageChanged?(currentPage) - delegate?.imageSlideshow?(self, didChangeCurrentPageTo: currentPage) + delegate?.imageSlideshow?( + self, + didChangeCurrentPageTo: currentPage + ) } } } @@ -199,7 +216,9 @@ open class ImageSlideshow: UIView { open var preload = ImagePreload.all /// Content mode of each image in the slideshow - open var contentScaleMode: UIViewContentMode = UIViewContentMode.scaleAspectFit { + open var contentScaleMode: UIView.ContentMode = + .scaleAspectFit + { didSet { for view in slideshowItems { view.imageView.contentMode = contentScaleMode @@ -212,10 +231,13 @@ open class ImageSlideshow: UIView { fileprivate var isAnimating: Bool = false /// Transitioning delegate to manage the transition to full screen controller - open fileprivate(set) var slideshowTransitioningDelegate: ZoomAnimatedTransitioningDelegate? // swiftlint:disable:this weak_delegate + open fileprivate(set) var slideshowTransitioningDelegate: + ZoomAnimatedTransitioningDelegate? // swiftlint:disable:this weak_delegate private var primaryVisiblePage: Int { - return scrollView.frame.size.width > 0 ? Int(scrollView.contentOffset.x + scrollView.frame.size.width / 2) / Int(scrollView.frame.size.width) : 0 + return scrollView.frame.size.width > 0 + ? Int(scrollView.contentOffset.x + scrollView.frame.size.width / 2) + / Int(scrollView.frame.size.width) : 0 } // MARK: - Life cycle @@ -237,12 +259,15 @@ open class ImageSlideshow: UIView { fileprivate func initialize() { autoresizesSubviews = true clipsToBounds = true - if #available(iOS 13.0, *) { - backgroundColor = .systemBackground - } + backgroundColor = .systemBackground // scroll view configuration - scrollView.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height - 50.0) + scrollView.frame = CGRect( + x: 0, + y: 0, + width: frame.size.width, + height: frame.size.height - 50.0 + ) scrollView.delegate = self scrollView.isPagingEnabled = true scrollView.bounces = true @@ -250,12 +275,12 @@ open class ImageSlideshow: UIView { scrollView.showsVerticalScrollIndicator = false scrollView.autoresizingMask = autoresizingMask if UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft { - scrollView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi)) + scrollView.transform = CGAffineTransform( + rotationAngle: CGFloat(Double.pi) + ) } - if #available(iOS 11.0, *) { - scrollView.contentInsetAdjustmentBehavior = .never - } + scrollView.contentInsetAdjustmentBehavior = .never addSubview(scrollView) if pageIndicator == nil { @@ -286,28 +311,47 @@ open class ImageSlideshow: UIView { pageIndicatorView.isHidden = images.count < 2 var edgeInsets: UIEdgeInsets = UIEdgeInsets.zero - if #available(iOS 11.0, *) { - edgeInsets = safeAreaInsets - } + edgeInsets = safeAreaInsets pageIndicatorView.sizeToFit() - pageIndicatorView.frame = pageIndicatorPosition.indicatorFrame(for: frame, indicatorSize: pageIndicatorView.frame.size, edgeInsets: edgeInsets) + pageIndicatorView.frame = pageIndicatorPosition.indicatorFrame( + for: frame, + indicatorSize: pageIndicatorView.frame.size, + edgeInsets: edgeInsets + ) } } /// updates frame of the scroll view and its inner items func layoutScrollView() { let pageIndicatorViewSize = pageIndicator?.view.frame.size - let scrollViewBottomPadding = pageIndicatorViewSize.flatMap { pageIndicatorPosition.underPadding(for: $0) } ?? 0 - - scrollView.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height - scrollViewBottomPadding) - scrollView.contentSize = CGSize(width: scrollView.frame.size.width * CGFloat(scrollViewImages.count), height: scrollView.frame.size.height) + let scrollViewBottomPadding = + pageIndicatorViewSize.flatMap { + pageIndicatorPosition.underPadding(for: $0) + } ?? 0 + + scrollView.frame = CGRect( + x: 0, + y: 0, + width: frame.size.width, + height: frame.size.height - scrollViewBottomPadding + ) + scrollView.contentSize = CGSize( + width: scrollView.frame.size.width + * CGFloat(scrollViewImages.count), + height: scrollView.frame.size.height + ) for (index, view) in slideshowItems.enumerated() { if !view.zoomInInitially { view.zoomOut() } - view.frame = CGRect(x: scrollView.frame.size.width * CGFloat(index), y: 0, width: scrollView.frame.size.width, height: scrollView.frame.size.height) + view.frame = CGRect( + x: scrollView.frame.size.width * CGFloat(index), + y: 0, + width: scrollView.frame.size.width, + height: scrollView.frame.size.height + ) } setScrollViewPage(scrollViewPage, animated: false) @@ -323,7 +367,12 @@ open class ImageSlideshow: UIView { var i = 0 for image in scrollViewImages { - let item = ImageSlideshowItem(image: image, zoomEnabled: zoomEnabled, activityIndicator: activityIndicator?.create(), maximumScale: maximumScale) + let item = ImageSlideshowItem( + image: image, + zoomEnabled: zoomEnabled, + activityIndicator: activityIndicator?.create(), + maximumScale: maximumScale + ) item.imageView.contentMode = contentScaleMode slideshowItems.append(item) scrollView.addSubview(item) @@ -332,7 +381,15 @@ open class ImageSlideshow: UIView { if circular && (scrollViewImages.count > 1) { scrollViewPage = 1 - scrollView.scrollRectToVisible(CGRect(x: scrollView.frame.size.width, y: 0, width: scrollView.frame.size.width, height: scrollView.frame.size.height), animated: false) + scrollView.scrollRectToVisible( + CGRect( + x: scrollView.frame.size.width, + y: 0, + width: scrollView.frame.size.width, + height: scrollView.frame.size.height + ), + animated: false + ) } else { scrollViewPage = 0 } @@ -350,10 +407,17 @@ open class ImageSlideshow: UIView { item.loadImage() case .fixed(let offset): // if circular scrolling is enabled and image is on the edge, a helper ("dummy") image on the other side needs to be loaded too - let circularEdgeLoad = circular && ((scrollViewPage == 0 && i == totalCount-3) || (scrollViewPage == 0 && i == totalCount-2) || (scrollViewPage == totalCount-2 && i == 1)) + let circularEdgeLoad = + circular + && ((scrollViewPage == 0 && i == totalCount - 3) + || (scrollViewPage == 0 && i == totalCount - 2) + || (scrollViewPage == totalCount - 2 && i == 1)) // load image if page is in range of loadOffset, else release image - let shouldLoad = abs(scrollViewPage-i) <= offset || abs(scrollViewPage-i) > totalCount-offset || circularEdgeLoad + let shouldLoad = + abs(scrollViewPage - i) <= offset + || abs(scrollViewPage - i) > totalCount - offset + || circularEdgeLoad shouldLoad ? item.loadImage() : item.releaseImage() } } @@ -415,7 +479,15 @@ open class ImageSlideshow: UIView { */ open func setScrollViewPage(_ newScrollViewPage: Int, animated: Bool) { if scrollViewPage < scrollViewImages.count { - scrollView.scrollRectToVisible(CGRect(x: scrollView.frame.size.width * CGFloat(newScrollViewPage), y: 0, width: scrollView.frame.size.width, height: scrollView.frame.size.height), animated: animated) + scrollView.scrollRectToVisible( + CGRect( + x: scrollView.frame.size.width * CGFloat(newScrollViewPage), + y: 0, + width: scrollView.frame.size.width, + height: scrollView.frame.size.height + ), + animated: animated + ) setCurrentPageForScrollViewPage(newScrollViewPage) if animated { isAnimating = true @@ -424,13 +496,23 @@ open class ImageSlideshow: UIView { } fileprivate func setTimerIfNeeded() { - if slideshowInterval > 0 && scrollViewImages.count > 1 && slideshowTimer == nil { - slideshowTimer = Timer.scheduledTimer(timeInterval: slideshowInterval, target: self, selector: #selector(ImageSlideshow.slideshowTick(_:)), userInfo: nil, repeats: true) + if slideshowInterval > 0 && scrollViewImages.count > 1 + && slideshowTimer == nil + { + slideshowTimer = Timer.scheduledTimer( + timeInterval: slideshowInterval, + target: self, + selector: #selector(ImageSlideshow.slideshowTick(_:)), + userInfo: nil, + repeats: true + ) } } func slideshowTick(_ timer: Timer) { - let page = scrollView.frame.size.width > 0 ? Int(scrollView.contentOffset.x / scrollView.frame.size.width) : 0 + let page = + scrollView.frame.size.width > 0 + ? Int(scrollView.contentOffset.x / scrollView.frame.size.width) : 0 var nextPage = page + 1 if !circular && page == scrollViewImages.count - 1 { @@ -529,7 +611,8 @@ open class ImageSlideshow: UIView { return } - let newPage = scrollViewPage > 0 ? scrollViewPage - 1 : scrollViewImages.count - 3 + let newPage = + scrollViewPage > 0 ? scrollViewPage - 1 : scrollViewImages.count - 3 setScrollViewPage(newPage, animated: animated) restartTimer() } @@ -540,15 +623,21 @@ open class ImageSlideshow: UIView { - returns: FullScreenSlideshowViewController instance */ @discardableResult - open func presentFullScreenController(from controller: UIViewController, completion: (() -> Void)? = nil) -> FullScreenSlideshowViewController { + open func presentFullScreenController( + from controller: UIViewController, + completion: (() -> Void)? = nil + ) -> FullScreenSlideshowViewController { let fullscreen = FullScreenSlideshowViewController() - fullscreen.pageSelected = {[weak self] (page: Int) in + fullscreen.pageSelected = { [weak self] (page: Int) in self?.setCurrentPage(page, animated: false) } fullscreen.initialPage = currentPage fullscreen.inputs = images - slideshowTransitioningDelegate = ZoomAnimatedTransitioningDelegate(slideshowView: self, slideshowController: fullscreen) + slideshowTransitioningDelegate = ZoomAnimatedTransitioningDelegate( + slideshowView: self, + slideshowController: fullscreen + ) fullscreen.transitioningDelegate = slideshowTransitioningDelegate fullscreen.modalPresentationStyle = .custom controller.present(fullscreen, animated: true, completion: completion) @@ -579,19 +668,30 @@ extension ImageSlideshow: UIScrollViewDelegate { open func scrollViewDidScroll(_ scrollView: UIScrollView) { if circular && (scrollViewImages.count > 1) { - let regularContentOffset = scrollView.frame.size.width * CGFloat(images.count) - - if scrollView.contentOffset.x >= scrollView.frame.size.width * CGFloat(images.count + 1) { - scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x - regularContentOffset, y: 0) + let regularContentOffset = + scrollView.frame.size.width * CGFloat(images.count) + + if scrollView.contentOffset.x >= scrollView.frame.size.width + * CGFloat(images.count + 1) + { + scrollView.contentOffset = CGPoint( + x: scrollView.contentOffset.x - regularContentOffset, + y: 0 + ) } else if scrollView.contentOffset.x <= 0 { - scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x + regularContentOffset, y: 0) + scrollView.contentOffset = CGPoint( + x: scrollView.contentOffset.x + regularContentOffset, + y: 0 + ) } } // Updates the page indicator as the user scrolls (#204). Not called when not dragging to prevent flickers // when interacting with PageControl directly (#376). if scrollView.isDragging { - pageIndicator?.page = currentPageForScrollViewPage(primaryVisiblePage) + pageIndicator?.page = currentPageForScrollViewPage( + primaryVisiblePage + ) } } diff --git a/ImageSlideshow/Classes/Core/ImageSlideshowItem.swift b/ImageSlideshow/Classes/Core/ImageSlideshowItem.swift index 7b2136a8..a7c8d3f4 100644 --- a/ImageSlideshow/Classes/Core/ImageSlideshowItem.swift +++ b/ImageSlideshow/Classes/Core/ImageSlideshowItem.swift @@ -53,7 +53,12 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate { - parameter image: Input Source to load the image - parameter zoomEnabled: holds if it should be possible to zoom-in the image */ - init(image: InputSource, zoomEnabled: Bool, activityIndicator: ActivityIndicatorView? = nil, maximumScale: CGFloat = 2.0) { + init( + image: InputSource, + zoomEnabled: Bool, + activityIndicator: ActivityIndicatorView? = nil, + maximumScale: CGFloat = 2.0 + ) { self.zoomEnabled = zoomEnabled self.image = image self.activityIndicator = activityIndicator @@ -65,14 +70,14 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate { imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] imageView.isAccessibilityElement = true imageView.accessibilityTraits = .image - if #available(iOS 11.0, *) { - imageView.accessibilityIgnoresInvertColors = true - } + imageView.accessibilityIgnoresInvertColors = true imageViewWrapper.clipsToBounds = true imageViewWrapper.isUserInteractionEnabled = true if UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft { - imageView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi)) + imageView.transform = CGAffineTransform( + rotationAngle: CGFloat(Double.pi) + ) } setPictoCenter() @@ -90,12 +95,18 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate { } // tap gesture recognizer - let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(ImageSlideshowItem.tapZoom)) + let tapRecognizer = UITapGestureRecognizer( + target: self, + action: #selector(ImageSlideshowItem.tapZoom) + ) tapRecognizer.numberOfTapsRequired = 2 imageViewWrapper.addGestureRecognizer(tapRecognizer) gestureRecognizer = tapRecognizer - singleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(retryLoadImage)) + singleTapGestureRecognizer = UITapGestureRecognizer( + target: self, + action: #selector(retryLoadImage) + ) singleTapGestureRecognizer!.numberOfTapsRequired = 1 singleTapGestureRecognizer!.isEnabled = false imageViewWrapper.addGestureRecognizer(singleTapGestureRecognizer!) @@ -139,7 +150,7 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate { isLoading = true imageReleased = false activityIndicator?.show() - image.load(to: self.imageView) {[weak self] image in + image.load(to: self.imageView) { [weak self] image in // set image to nil if there was a release request during the image load if let imageRelease = self?.imageReleased, imageRelease { self?.imageView.image = nil @@ -192,18 +203,28 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate { } fileprivate func calculatePictureSize() -> CGSize { - if let image = imageView.image, imageView.contentMode == .scaleAspectFit { + if let image = imageView.image, imageView.contentMode == .scaleAspectFit + { let picSize = image.size let picRatio = picSize.width / picSize.height let screenRatio = screenSize().width / screenSize().height if picRatio > screenRatio { - return CGSize(width: screenSize().width, height: screenSize().width / picSize.width * picSize.height) + return CGSize( + width: screenSize().width, + height: screenSize().width / picSize.width * picSize.height + ) } else { - return CGSize(width: screenSize().height / picSize.height * picSize.width, height: screenSize().height) + return CGSize( + width: screenSize().height / picSize.height * picSize.width, + height: screenSize().height + ) } } else { - return CGSize(width: screenSize().width, height: screenSize().height) + return CGSize( + width: screenSize().width, + height: screenSize().height + ) } } @@ -212,15 +233,23 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate { } fileprivate func setPictoCenter() { - var intendHorizon = (screenSize().width - imageViewWrapper.frame.width ) / 2 - var intendVertical = (screenSize().height - imageViewWrapper.frame.height ) / 2 + var intendHorizon = + (screenSize().width - imageViewWrapper.frame.width) / 2 + var intendVertical = + (screenSize().height - imageViewWrapper.frame.height) / 2 intendHorizon = intendHorizon > 0 ? intendHorizon : 0 intendVertical = intendVertical > 0 ? intendVertical : 0 - contentInset = UIEdgeInsets(top: intendVertical, left: intendHorizon, bottom: intendVertical, right: intendHorizon) + contentInset = UIEdgeInsets( + top: intendVertical, + left: intendHorizon, + bottom: intendVertical, + right: intendHorizon + ) } private func isFullScreen() -> Bool { - return imageViewWrapper.frame.width >= screenSize().width && imageViewWrapper.frame.height >= screenSize().height + return imageViewWrapper.frame.width >= screenSize().width + && imageViewWrapper.frame.height >= screenSize().height } func clearContentInsets() { diff --git a/ImageSlideshow/Classes/Core/PageIndicator.swift b/ImageSlideshow/Classes/Core/PageIndicator.swift index d9863e91..9c49a052 100644 --- a/ImageSlideshow/Classes/Core/PageIndicator.swift +++ b/ImageSlideshow/Classes/Core/PageIndicator.swift @@ -8,7 +8,7 @@ import UIKit /// Cusotm Page Indicator can be used by implementing this protocol -public protocol PageIndicatorView: class { +public protocol PageIndicatorView: AnyObject { /// View of the page indicator var view: UIView { get } @@ -16,10 +16,10 @@ public protocol PageIndicatorView: class { var page: Int { get set } /// Total number of pages of the page indicator - var numberOfPages: Int { get set} + var numberOfPages: Int { get set } } -extension UIPageControl: PageIndicatorView { +extension UIPageControl: @preconcurrency PageIndicatorView { public var view: UIView { return self } @@ -43,20 +43,12 @@ extension UIPageControl: PageIndicatorView { public static func withSlideshowColors() -> UIPageControl { let pageControl = UIPageControl() - if #available(iOS 13.0, *) { - pageControl.currentPageIndicatorTintColor = UIColor { traits in - traits.userInterfaceStyle == .dark ? .white : .lightGray - } - } else { - pageControl.currentPageIndicatorTintColor = .lightGray + pageControl.currentPageIndicatorTintColor = UIColor { traits in + traits.userInterfaceStyle == .dark ? .white : .lightGray } - - if #available(iOS 13.0, *) { - pageControl.pageIndicatorTintColor = UIColor { traits in - traits.userInterfaceStyle == .dark ? .systemGray : .black - } - } else { - pageControl.pageIndicatorTintColor = .black + + pageControl.pageIndicatorTintColor = UIColor { traits in + traits.userInterfaceStyle == .dark ? .systemGray : .black } return pageControl @@ -64,7 +56,7 @@ extension UIPageControl: PageIndicatorView { } /// Page indicator that shows page in numeric style, eg. "5/21" -public class LabelPageIndicator: UILabel, PageIndicatorView { +public class LabelPageIndicator: UILabel, @preconcurrency PageIndicatorView { public var view: UIView { return self } @@ -100,7 +92,10 @@ public class LabelPageIndicator: UILabel, PageIndicatorView { } public override func sizeToFit() { - let maximumString = String(repeating: "8", count: numberOfPages) as NSString - self.frame.size = maximumString.size(withAttributes: [.font: font as Any]) + let maximumString = + String(repeating: "8", count: numberOfPages) as NSString + self.frame.size = maximumString.size(withAttributes: [ + .font: font as Any + ]) } } diff --git a/ImageSlideshow/Classes/Core/SwiftSupport.swift b/ImageSlideshow/Classes/Core/SwiftSupport.swift index 83f024b8..0c669c51 100644 --- a/ImageSlideshow/Classes/Core/SwiftSupport.swift +++ b/ImageSlideshow/Classes/Core/SwiftSupport.swift @@ -7,12 +7,3 @@ import UIKit -#if swift(>=4.2) -public typealias UIViewContentMode = UIView.ContentMode -public typealias UIActivityIndicatorViewStyle = UIActivityIndicatorView.Style -typealias UIControlState = UIControl.State -typealias UIViewAnimationOptions = UIView.AnimationOptions -typealias UIControlEvents = UIControl.Event -typealias UIViewAutoresizing = UIView.AutoresizingMask -#else -#endif diff --git a/ImageSlideshow/Classes/Core/ZoomAnimatedTransitioning.swift b/ImageSlideshow/Classes/Core/ZoomAnimatedTransitioning.swift index 9b29afae..f0abfe33 100644 --- a/ImageSlideshow/Classes/Core/ZoomAnimatedTransitioning.swift +++ b/ImageSlideshow/Classes/Core/ZoomAnimatedTransitioning.swift @@ -9,7 +9,9 @@ import UIKit @objcMembers -open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate { +open class ZoomAnimatedTransitioningDelegate: NSObject, + UIViewControllerTransitioningDelegate +{ /// parent image view used for animated transition open var referenceImageView: UIImageView? /// parent slideshow view used for animated transition @@ -30,7 +32,10 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti - parameter slideshowView: ImageSlideshow instance to animate the transition from - parameter slideshowController: FullScreenViewController instance to animate the transition to */ - public init(slideshowView: ImageSlideshow, slideshowController: FullScreenSlideshowViewController) { + public init( + slideshowView: ImageSlideshow, + slideshowController: FullScreenSlideshowViewController + ) { self.referenceSlideshowView = slideshowView self.referenceSlideshowController = slideshowController @@ -44,7 +49,10 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti - parameter imageView: UIImageView instance to animate the transition from - parameter slideshowController: FullScreenViewController instance to animate the transition to */ - public init(imageView: UIImageView, slideshowController: FullScreenSlideshowViewController) { + public init( + imageView: UIImageView, + slideshowController: FullScreenSlideshowViewController + ) { self.referenceImageView = imageView self.referenceSlideshowController = slideshowController @@ -55,36 +63,59 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti func initialize() { // Pan gesture recognizer for interactive dismiss - gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(ZoomAnimatedTransitioningDelegate.handleSwipe(_:))) + gestureRecognizer = UIPanGestureRecognizer( + target: self, + action: #selector(ZoomAnimatedTransitioningDelegate.handleSwipe(_:)) + ) gestureRecognizer.delegate = self + // Append it to a window otherwise it will be canceled during the transition - UIApplication.shared.keyWindow?.addGestureRecognizer(gestureRecognizer) + let keyWindow = UIApplication.shared.connectedScenes + .compactMap { $0 as? UIWindowScene } + .flatMap { $0.windows } + .first { $0.isKeyWindow } + keyWindow?.addGestureRecognizer(gestureRecognizer) } func handleSwipe(_ gesture: UIPanGestureRecognizer) { - guard let referenceSlideshowController = referenceSlideshowController else { + guard let referenceSlideshowController = referenceSlideshowController + else { return } - let percent = min(max(abs(gesture.translation(in: gesture.view!).y) / 200.0, 0.0), 1.0) + let percent = min( + max(abs(gesture.translation(in: gesture.view!).y) / 200.0, 0.0), + 1.0 + ) if gesture.state == .began { interactionController = UIPercentDrivenInteractiveTransition() - referenceSlideshowController.dismiss(animated: true, completion: nil) + referenceSlideshowController.dismiss( + animated: true, + completion: nil + ) } else if gesture.state == .changed { interactionController?.update(percent) - } else if gesture.state == .ended || gesture.state == .cancelled || gesture.state == .failed { + } else if gesture.state == .ended || gesture.state == .cancelled + || gesture.state == .failed + { let velocity = gesture.velocity(in: referenceSlideshowView) if abs(velocity.y) > 500 { - if let pageSelected = referenceSlideshowController.pageSelected { - pageSelected(referenceSlideshowController.slideshow.currentPage) + if let pageSelected = referenceSlideshowController.pageSelected + { + pageSelected( + referenceSlideshowController.slideshow.currentPage + ) } interactionController?.finish() } else if percent > 0.5 { - if let pageSelected = referenceSlideshowController.pageSelected { - pageSelected(referenceSlideshowController.slideshow.currentPage) + if let pageSelected = referenceSlideshowController.pageSelected + { + pageSelected( + referenceSlideshowController.slideshow.currentPage + ) } interactionController?.finish() @@ -96,9 +127,16 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti } } - open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + open func animationController( + forPresented presented: UIViewController, + presenting: UIViewController, + source: UIViewController + ) -> UIViewControllerAnimatedTransitioning? { if let reference = referenceSlideshowView { - return ZoomInAnimator(referenceSlideshowView: reference, parent: self) + return ZoomInAnimator( + referenceSlideshowView: reference, + parent: self + ) } else if let reference = referenceImageView { return ZoomInAnimator(referenceImageView: reference, parent: self) } else { @@ -106,9 +144,14 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti } } - open func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + open func animationController(forDismissed dismissed: UIViewController) + -> UIViewControllerAnimatedTransitioning? + { if let reference = referenceSlideshowView { - return ZoomOutAnimator(referenceSlideshowView: reference, parent: self) + return ZoomOutAnimator( + referenceSlideshowView: reference, + parent: self + ) } else if let reference = referenceImageView { return ZoomOutAnimator(referenceImageView: reference, parent: self) } else { @@ -116,16 +159,27 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti } } - open func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { + open func interactionControllerForPresentation( + using animator: UIViewControllerAnimatedTransitioning + ) -> UIViewControllerInteractiveTransitioning? { return interactionController } - open func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { + open func interactionControllerForDismissal( + using animator: UIViewControllerAnimatedTransitioning + ) -> UIViewControllerInteractiveTransitioning? { return interactionController } - public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { - return PresentationController(presentedViewController: presented, presenting: presenting) + public func presentationController( + forPresented presented: UIViewController, + presenting: UIViewController?, + source: UIViewController + ) -> UIPresentationController? { + return PresentationController( + presentedViewController: presented, + presenting: presenting + ) } } @@ -137,8 +191,12 @@ private class PresentationController: UIPresentationController { } extension ZoomAnimatedTransitioningDelegate: UIGestureRecognizerDelegate { - public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { - guard let gestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer else { + public func gestureRecognizerShouldBegin( + _ gestureRecognizer: UIGestureRecognizer + ) -> Bool { + guard + let gestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer + else { return false } @@ -146,7 +204,9 @@ extension ZoomAnimatedTransitioningDelegate: UIGestureRecognizerDelegate { return false } - if let currentItem = referenceSlideshowController?.slideshow.currentSlideshowItem, currentItem.isZoomed() { + if let currentItem = referenceSlideshowController?.slideshow + .currentSlideshowItem, currentItem.isZoomed() + { return false } @@ -166,14 +226,21 @@ class ZoomAnimator: NSObject { var referenceSlideshowView: ImageSlideshow? var parent: ZoomAnimatedTransitioningDelegate - init(referenceSlideshowView: ImageSlideshow, parent: ZoomAnimatedTransitioningDelegate) { + init( + referenceSlideshowView: ImageSlideshow, + parent: ZoomAnimatedTransitioningDelegate + ) { self.referenceSlideshowView = referenceSlideshowView - self.referenceImageView = referenceSlideshowView.currentSlideshowItem?.imageView + self.referenceImageView = + referenceSlideshowView.currentSlideshowItem?.imageView self.parent = parent super.init() } - init(referenceImageView: UIImageView, parent: ZoomAnimatedTransitioningDelegate) { + init( + referenceImageView: UIImageView, + parent: ZoomAnimatedTransitioningDelegate + ) { self.referenceImageView = referenceImageView self.parent = parent super.init() @@ -183,32 +250,41 @@ class ZoomAnimator: NSObject { @objcMembers class ZoomInAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning { - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + func transitionDuration( + using transitionContext: UIViewControllerContextTransitioning? + ) -> TimeInterval { return 0.5 } - func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + func animateTransition( + using transitionContext: UIViewControllerContextTransitioning + ) { // Pauses slideshow self.referenceSlideshowView?.pauseTimer() let containerView = transitionContext.containerView - let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)! - - guard let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as? FullScreenSlideshowViewController else { + let fromViewController = transitionContext.viewController( + forKey: UITransitionContextViewControllerKey.from + )! + + guard + let toViewController = transitionContext.viewController( + forKey: UITransitionContextViewControllerKey.to + ) as? FullScreenSlideshowViewController + else { return } - toViewController.view.frame = transitionContext.finalFrame(for: toViewController) + toViewController.view.frame = transitionContext.finalFrame( + for: toViewController + ) let transitionBackgroundView = UIView(frame: containerView.frame) - transitionBackgroundView.backgroundColor = toViewController.backgroundColor + transitionBackgroundView.backgroundColor = + toViewController.backgroundColor containerView.addSubview(transitionBackgroundView) - #if swift(>=4.2) containerView.sendSubviewToBack(transitionBackgroundView) - #else - containerView.sendSubview(toBack: transitionBackgroundView) - #endif let finalFrame = toViewController.view.frame @@ -216,37 +292,64 @@ class ZoomInAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning { var transitionViewFinalFrame = finalFrame if let referenceImageView = referenceImageView { transitionView = UIImageView(image: referenceImageView.image) - transitionView!.contentMode = UIViewContentMode.scaleAspectFill + transitionView!.contentMode = .scaleAspectFill transitionView!.clipsToBounds = true - transitionView!.frame = containerView.convert(referenceImageView.bounds, from: referenceImageView) + transitionView!.frame = containerView.convert( + referenceImageView.bounds, + from: referenceImageView + ) containerView.addSubview(transitionView!) self.parent.referenceSlideshowViewFrame = transitionView!.frame referenceImageView.alpha = 0 if let image = referenceImageView.image { - transitionViewFinalFrame = image.tgr_aspectFitRectForSize(finalFrame.size) + transitionViewFinalFrame = image.tgr_aspectFitRectForSize( + finalFrame.size + ) } } - if let item = toViewController.slideshow.currentSlideshowItem, item.zoomInInitially { - transitionViewFinalFrame.size = CGSize(width: transitionViewFinalFrame.size.width * item.maximumZoomScale, height: transitionViewFinalFrame.size.height * item.maximumZoomScale) + if let item = toViewController.slideshow.currentSlideshowItem, + item.zoomInInitially + { + transitionViewFinalFrame.size = CGSize( + width: transitionViewFinalFrame.size.width + * item.maximumZoomScale, + height: transitionViewFinalFrame.size.height + * item.maximumZoomScale + ) } - let duration: TimeInterval = transitionDuration(using: transitionContext) - - UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0, options: UIViewAnimationOptions.curveLinear, animations: { - fromViewController.view.alpha = 0 - transitionView?.frame = transitionViewFinalFrame - transitionView?.center = CGPoint(x: finalFrame.midX, y: finalFrame.midY) - }, completion: {[ref = self.referenceImageView] _ in - fromViewController.view.alpha = 1 - ref?.alpha = 1 - transitionView?.removeFromSuperview() - transitionBackgroundView.removeFromSuperview() - containerView.addSubview(toViewController.view) - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - }) + let duration: TimeInterval = transitionDuration( + using: transitionContext + ) + + UIView.animate( + withDuration: duration, + delay: 0, + usingSpringWithDamping: 0.7, + initialSpringVelocity: 0, + options: .curveLinear, + animations: { + fromViewController.view.alpha = 0 + transitionView?.frame = transitionViewFinalFrame + transitionView?.center = CGPoint( + x: finalFrame.midX, + y: finalFrame.midY + ) + }, + completion: { [ref = self.referenceImageView] _ in + fromViewController.view.alpha = 1 + ref?.alpha = 1 + transitionView?.removeFromSuperview() + transitionBackgroundView.removeFromSuperview() + containerView.addSubview(toViewController.view) + transitionContext.completeTransition( + !transitionContext.transitionWasCancelled + ) + } + ) } } @@ -254,12 +357,15 @@ class ZoomOutAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning { private var animatorForCurrentTransition: UIViewImplicitlyAnimating? - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + func transitionDuration( + using transitionContext: UIViewControllerContextTransitioning? + ) -> TimeInterval { return 0.25 } - @available(iOS 10.0, *) - func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { + func interruptibleAnimator( + using transitionContext: UIViewControllerContextTransitioning + ) -> UIViewImplicitlyAnimating { // as per documentation, the same object should be returned for the ongoing transition if let animatorForCurrentSession = animatorForCurrentTransition { return animatorForCurrentSession @@ -267,30 +373,53 @@ class ZoomOutAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning { let params = animationParams(using: transitionContext) - let animator = UIViewPropertyAnimator(duration: params.0, curve: .linear, animations: params.1) + let animator = UIViewPropertyAnimator( + duration: params.0, + curve: .linear, + animations: params.1 + ) animator.addCompletion(params.2) animatorForCurrentTransition = animator return animator } - private func animationParams(using transitionContext: UIViewControllerContextTransitioning) -> (TimeInterval, () -> Void, (Any) -> Void) { - let toViewController: UIViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)! - - guard let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as? FullScreenSlideshowViewController else { - fatalError("Transition not used with FullScreenSlideshowViewController") + private func animationParams( + using transitionContext: UIViewControllerContextTransitioning + ) -> (TimeInterval, () -> Void, (UIViewAnimatingPosition) -> Void) { + let toViewController: UIViewController = + transitionContext.viewController( + forKey: UITransitionContextViewControllerKey.to + )! + + guard + let fromViewController = transitionContext.viewController( + forKey: UITransitionContextViewControllerKey.from + ) as? FullScreenSlideshowViewController + else { + fatalError( + "Transition not used with FullScreenSlideshowViewController" + ) } let containerView = transitionContext.containerView var transitionViewInitialFrame: CGRect - if let currentSlideshowItem = fromViewController.slideshow.currentSlideshowItem { + if let currentSlideshowItem = fromViewController.slideshow + .currentSlideshowItem + { if let image = currentSlideshowItem.imageView.image { - transitionViewInitialFrame = image.tgr_aspectFitRectForSize(currentSlideshowItem.imageView.frame.size) + transitionViewInitialFrame = image.tgr_aspectFitRectForSize( + currentSlideshowItem.imageView.frame.size + ) } else { - transitionViewInitialFrame = currentSlideshowItem.imageView.frame + transitionViewInitialFrame = + currentSlideshowItem.imageView.frame } - transitionViewInitialFrame = containerView.convert(transitionViewInitialFrame, from: currentSlideshowItem) + transitionViewInitialFrame = containerView.convert( + transitionViewInitialFrame, + from: currentSlideshowItem + ) } else { transitionViewInitialFrame = fromViewController.slideshow.frame } @@ -299,33 +428,52 @@ class ZoomOutAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning { if let referenceImageView = referenceImageView { referenceImageView.alpha = 0 - let referenceSlideshowViewFrame = containerView.convert(referenceImageView.bounds, from: referenceImageView) + let referenceSlideshowViewFrame = containerView.convert( + referenceImageView.bounds, + from: referenceImageView + ) transitionViewFinalFrame = referenceSlideshowViewFrame // do a frame scaling when AspectFit content mode enabled - if fromViewController.slideshow.currentSlideshowItem?.imageView.image != nil && referenceImageView.contentMode == UIViewContentMode.scaleAspectFit { - transitionViewFinalFrame = containerView.convert(referenceImageView.aspectToFitFrame(), from: referenceImageView) + if fromViewController.slideshow.currentSlideshowItem?.imageView + .image != nil + && referenceImageView.contentMode + == .scaleAspectFit + { + transitionViewFinalFrame = containerView.convert( + referenceImageView.aspectToFitFrame(), + from: referenceImageView + ) } // fixes the problem when the referenceSlideshowViewFrame was shifted during change of the status bar hidden state - if UIApplication.shared.isStatusBarHidden && !toViewController.prefersStatusBarHidden && referenceSlideshowViewFrame.origin.y != parent.referenceSlideshowViewFrame?.origin.y { - transitionViewFinalFrame = transitionViewFinalFrame.offsetBy(dx: 0, dy: 20) + if UIApplication.shared.isStatusBarHidden + && !toViewController.prefersStatusBarHidden + && referenceSlideshowViewFrame.origin.y + != parent.referenceSlideshowViewFrame?.origin.y + { + transitionViewFinalFrame = transitionViewFinalFrame.offsetBy( + dx: 0, + dy: 20 + ) } } else { - transitionViewFinalFrame = referenceSlideshowView?.frame ?? CGRect.zero + transitionViewFinalFrame = + referenceSlideshowView?.frame ?? CGRect.zero } let transitionBackgroundView = UIView(frame: containerView.frame) - transitionBackgroundView.backgroundColor = fromViewController.backgroundColor + transitionBackgroundView.backgroundColor = + fromViewController.backgroundColor containerView.addSubview(transitionBackgroundView) - #if swift(>=4.2) + containerView.sendSubviewToBack(transitionBackgroundView) - #else - containerView.sendSubview(toBack: transitionBackgroundView) - #endif - let transitionView = UIImageView(image: fromViewController.slideshow.currentSlideshowItem?.imageView.image) - transitionView.contentMode = UIViewContentMode.scaleAspectFill + let transitionView = UIImageView( + image: fromViewController.slideshow.currentSlideshowItem?.imageView + .image + ) + transitionView.contentMode = .scaleAspectFill transitionView.clipsToBounds = true transitionView.frame = transitionViewInitialFrame containerView.addSubview(transitionView) @@ -336,13 +484,17 @@ class ZoomOutAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning { transitionBackgroundView.alpha = 0 transitionView.frame = transitionViewFinalFrame } - let completion = { (_: Any) in + let completion: (UIViewAnimatingPosition) -> Void = { _ in let completed = !transitionContext.transitionWasCancelled self.referenceImageView?.alpha = 1 if completed { fromViewController.view.removeFromSuperview() - UIApplication.shared.keyWindow?.removeGestureRecognizer(self.parent.gestureRecognizer) + // remove the recognizer from the window it was added to, which may no longer be key + self.parent.gestureRecognizer.view?.removeGestureRecognizer( + self.parent.gestureRecognizer + ) + // Unpauses slideshow self.referenceSlideshowView?.unpauseTimer() } else { @@ -360,13 +512,11 @@ class ZoomOutAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning { return (duration, animations, completion) } - func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + func animateTransition( + using transitionContext: UIViewControllerContextTransitioning + ) { // Working around iOS 10+ breaking change requiring to use UIPropertyAnimator for proper interactive transition instead of UIView.animate - if #available(iOS 10.0, *) { - interruptibleAnimator(using: transitionContext).startAnimation() - } else { - let params = animationParams(using: transitionContext) - UIView.animate(withDuration: params.0, delay: 0, options: UIViewAnimationOptions(), animations: params.1, completion: params.2) - } + + interruptibleAnimator(using: transitionContext).startAnimation() } } From 7cc92c12cda97d8dec0a8a23f0cd310c4cd0c46a Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Fri, 12 Jun 2026 00:52:13 -0400 Subject: [PATCH 06/17] Adopt main-actor isolation for input sources and indicators Mark InputSource/ActivityIndicator/PageIndicator conformers @preconcurrency with @MainActor-isolated methods. In KingfisherSource, run load/cancel synchronously on the main actor instead of deferring through Task (the deferred cancel could race a newly started load), and report failures with a nil image so ImageSlideshowItem enables the retry gesture again. Bundle.module becomes an immutable static let. Co-Authored-By: Claude Fable 5 --- .../Classes/Core/ActivityIndicator.swift | 17 +++++++------- .../Classes/Core/Bundle+Module.swift | 4 +--- ImageSlideshow/Classes/Core/InputSource.swift | 12 +++++----- .../InputSources/KingfisherSource.swift | 23 ++++++++----------- .../InputSources/SDWebImageSource.swift | 6 ++--- 5 files changed, 28 insertions(+), 34 deletions(-) diff --git a/ImageSlideshow/Classes/Core/ActivityIndicator.swift b/ImageSlideshow/Classes/Core/ActivityIndicator.swift index a0af2009..b6bcff33 100644 --- a/ImageSlideshow/Classes/Core/ActivityIndicator.swift +++ b/ImageSlideshow/Classes/Core/ActivityIndicator.swift @@ -25,7 +25,7 @@ public protocol ActivityIndicatorFactory { } /// Default ActivityIndicatorView implementation for UIActivityIndicatorView -extension UIActivityIndicatorView: ActivityIndicatorView { +extension UIActivityIndicatorView: @preconcurrency ActivityIndicatorView { public var view: UIView { return self } @@ -41,9 +41,9 @@ extension UIActivityIndicatorView: ActivityIndicatorView { /// Default activity indicator factory creating UIActivityIndicatorView instances @objcMembers -open class DefaultActivityIndicator: ActivityIndicatorFactory { +open class DefaultActivityIndicator: @preconcurrency ActivityIndicatorFactory { /// activity indicator style - open var style: UIActivityIndicatorViewStyle + open var style: UIActivityIndicatorView.Style /// activity indicator color open var color: UIColor? @@ -52,18 +52,17 @@ open class DefaultActivityIndicator: ActivityIndicatorFactory { /// /// - style: activity indicator style /// - color: activity indicator color - public init(style: UIActivityIndicatorViewStyle = .gray, color: UIColor? = nil) { + public init( + style: UIActivityIndicatorView.Style = .medium, + color: UIColor? = nil + ) { self.style = style self.color = color } /// create ActivityIndicatorView instance - open func create() -> ActivityIndicatorView { - #if swift(>=4.2) + @MainActor open func create() -> ActivityIndicatorView { let activityIndicator = UIActivityIndicatorView(style: style) - #else - let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: style) - #endif activityIndicator.color = color activityIndicator.hidesWhenStopped = true diff --git a/ImageSlideshow/Classes/Core/Bundle+Module.swift b/ImageSlideshow/Classes/Core/Bundle+Module.swift index 4ad0203f..dd47bf88 100644 --- a/ImageSlideshow/Classes/Core/Bundle+Module.swift +++ b/ImageSlideshow/Classes/Core/Bundle+Module.swift @@ -9,8 +9,6 @@ import Foundation #if !SWIFT_PACKAGE extension Bundle { - static var module: Bundle = { - return Bundle(for: ImageSlideshow.self) - }() + static let module = Bundle(for: ImageSlideshow.self) } #endif diff --git a/ImageSlideshow/Classes/Core/InputSource.swift b/ImageSlideshow/Classes/Core/InputSource.swift index 3689af2a..2ed64098 100644 --- a/ImageSlideshow/Classes/Core/InputSource.swift +++ b/ImageSlideshow/Classes/Core/InputSource.swift @@ -27,7 +27,7 @@ import UIKit /// Input Source to load plain UIImage @objcMembers -open class ImageSource: NSObject, InputSource { +open class ImageSource: NSObject, @preconcurrency InputSource { var image: UIImage /// Initializes a new Image Source with UIImage @@ -48,7 +48,7 @@ open class ImageSource: NSObject, InputSource { } } - public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { + @MainActor public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { imageView.image = image callback(image) } @@ -56,7 +56,7 @@ open class ImageSource: NSObject, InputSource { /// Input Source to load an image from the main bundle @objcMembers -open class BundleImageSource: NSObject, InputSource { +open class BundleImageSource: NSObject, @preconcurrency InputSource { var imageString: String /// Initializes a new Image Source with an image name from the main bundle @@ -66,7 +66,7 @@ open class BundleImageSource: NSObject, InputSource { super.init() } - public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { + @MainActor public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { let image = UIImage(named: imageString) imageView.image = image callback(image) @@ -75,7 +75,7 @@ open class BundleImageSource: NSObject, InputSource { /// Input Source to load an image from a local file path @objcMembers -open class FileImageSource: NSObject, InputSource { +open class FileImageSource: NSObject, @preconcurrency InputSource { var path: String /// Initializes a new Image Source with an image name from the main bundle @@ -85,7 +85,7 @@ open class FileImageSource: NSObject, InputSource { super.init() } - public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { + @MainActor public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { let image = UIImage(contentsOfFile: path) imageView.image = image callback(image) diff --git a/ImageSlideshow/Classes/InputSources/KingfisherSource.swift b/ImageSlideshow/Classes/InputSources/KingfisherSource.swift index d49b4d59..68a5314e 100644 --- a/ImageSlideshow/Classes/InputSources/KingfisherSource.swift +++ b/ImageSlideshow/Classes/InputSources/KingfisherSource.swift @@ -13,7 +13,7 @@ import ImageSlideshow import Kingfisher /// Input Source to image using Kingfisher -public class KingfisherSource: NSObject, InputSource { +public class KingfisherSource: NSObject, @preconcurrency InputSource { /// url to load public var url: URL @@ -54,16 +54,15 @@ public class KingfisherSource: NSObject, InputSource { /// - Parameters: /// - imageView: UIImageView that receives the loaded image /// - callback: Completion callback with an optional image + @MainActor @objc public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { - Task { @MainActor in - imageView.kf.setImage(with: self.url, placeholder: self.placeholder, options: self.options, progressBlock: nil) { result in - switch result { - case .success(let image): - callback(image.image) - case .failure: - callback(self.placeholder) - } + imageView.kf.setImage(with: self.url, placeholder: self.placeholder, options: self.options, progressBlock: nil) { result in + switch result { + case .success(let image): + callback(image.image) + case .failure: + callback(nil) } } } @@ -71,9 +70,7 @@ public class KingfisherSource: NSObject, InputSource { /// Cancel an image download task /// /// - Parameter imageView: UIImage view with the download task that should be canceled - public func cancelLoad(on imageView: UIImageView) { - Task { @MainActor in - imageView.kf.cancelDownloadTask() - } + @MainActor public func cancelLoad(on imageView: UIImageView) { + imageView.kf.cancelDownloadTask() } } diff --git a/ImageSlideshow/Classes/InputSources/SDWebImageSource.swift b/ImageSlideshow/Classes/InputSources/SDWebImageSource.swift index b1c189a9..1d24eac0 100644 --- a/ImageSlideshow/Classes/InputSources/SDWebImageSource.swift +++ b/ImageSlideshow/Classes/InputSources/SDWebImageSource.swift @@ -14,7 +14,7 @@ import SDWebImage /// Input Source to image using SDWebImage @objcMembers -public class SDWebImageSource: NSObject, InputSource { +public class SDWebImageSource: NSObject, @preconcurrency InputSource { /// url to load public var url: URL @@ -43,13 +43,13 @@ public class SDWebImageSource: NSObject, InputSource { } } - public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { + @MainActor public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { imageView.sd_setImage(with: self.url, placeholderImage: self.placeholder, options: [], completed: { (image, _, _, _) in callback(image) }) } - public func cancelLoad(on imageView: UIImageView) { + @MainActor public func cancelLoad(on imageView: UIImageView) { imageView.sd_cancelCurrentImageLoad() } } From 4054a06162b2a47ebb2298ba87e7d10732877ac5 Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Fri, 12 Jun 2026 00:52:13 -0400 Subject: [PATCH 07/17] Migrate Xcode project to Xcode 26 recommended settings Apply the project migration (objectVersion 54, module verifier, script sandboxing, scheme updates) and raise the example deployment target. Release keeps full optimization (-O with whole-module compilation). Co-Authored-By: Claude Fable 5 --- .../ImageSlideshow.xcodeproj/project.pbxproj | 64 ++++++++++++++----- .../xcschemes/ImageSlideshow-Example.xcscheme | 24 +++---- .../ImageSlideshow_framework.xcscheme | 6 +- 3 files changed, 58 insertions(+), 36 deletions(-) diff --git a/Example/ImageSlideshow.xcodeproj/project.pbxproj b/Example/ImageSlideshow.xcodeproj/project.pbxproj index 47cc209f..e209b7ad 100644 --- a/Example/ImageSlideshow.xcodeproj/project.pbxproj +++ b/Example/ImageSlideshow.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -303,9 +303,10 @@ 607FACC81AFB9204008FA782 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0940; + LastUpgradeCheck = 2600; ORGANIZATIONNAME = CocoaPods; TargetAttributes = { 607FACCF1AFB9204008FA782 = { @@ -500,6 +501,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -518,6 +520,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -528,6 +531,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -543,10 +547,11 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.2; }; @@ -556,6 +561,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -574,6 +580,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -584,6 +591,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 = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -592,10 +600,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 4.2; VALIDATE_PRODUCT = YES; }; @@ -608,8 +618,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 5VWB99DS38; INFOPLIST_FILE = ImageSlideshow/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); MODULE_NAME = ExampleApp; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -624,8 +636,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 5VWB99DS38; INFOPLIST_FILE = ImageSlideshow/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); MODULE_NAME = ExampleApp; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -644,8 +658,11 @@ "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -660,8 +677,11 @@ DEVELOPMENT_TEAM = 5VWB99DS38; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -684,10 +704,15 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = ImageSlideshow_framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; PRODUCT_BUNDLE_IDENTIFIER = "io.zvo.ImageSlideshow-framework"; PRODUCT_NAME = ImageSlideshow; SKIP_INSTALL = YES; @@ -713,10 +738,15 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = ImageSlideshow_framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; PRODUCT_BUNDLE_IDENTIFIER = "io.zvo.ImageSlideshow-framework"; PRODUCT_NAME = ImageSlideshow; SKIP_INSTALL = YES; diff --git a/Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow-Example.xcscheme b/Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow-Example.xcscheme index 4218952b..b276b69e 100644 --- a/Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow-Example.xcscheme +++ b/Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow-Example.xcscheme @@ -1,6 +1,6 @@ + + + + @@ -53,17 +62,6 @@ - - - - - - - - - - - - Date: Fri, 12 Jun 2026 00:52:21 -0400 Subject: [PATCH 08/17] Bump to 1.9.4 and align packaging across CocoaPods and SPM Raise the platform floor to iOS 15 in the podspec, Podfile and Package.swift (which requires swift-tools 5.5). Fix the SPM AlamofireImage requirement that pointed at a nonexistent 5.10.2 release, breaking dependency resolution. Keep the Alamofire3 subspec on AlamofireImage 3.x to match its legacy source, align the Kingfisher constraint with SPM (>= 8.3.2), and drop stale subspec platform overrides and a duplicated swift_versions entry. Co-Authored-By: Claude Fable 5 --- Example/Podfile | 2 +- Example/Podfile.lock | 34 +++++++++++++++++----------------- ImageSlideshow.podspec | 12 +++++------- Package.resolved | 12 ++++++------ Package.swift | 8 +++++--- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Example/Podfile b/Example/Podfile index 4f62ec06..30eee49b 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -1,4 +1,4 @@ -platform :ios, '13.0' +platform :ios, '15.0' use_frameworks! target 'ImageSlideshow_Example' do diff --git a/Example/Podfile.lock b/Example/Podfile.lock index eef0f8ee..9429d34c 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -17,25 +17,25 @@ PODS: - Alamofire (5.10.2) - AlamofireImage (4.3.0): - Alamofire (~> 5.8) - - ImageSlideshow (1.9.3): - - ImageSlideshow/Core (= 1.9.3) - - ImageSlideshow/AFURL (1.9.3): + - ImageSlideshow (1.9.4): + - ImageSlideshow/Core (= 1.9.4) + - ImageSlideshow/AFURL (1.9.4): - AFNetworking (~> 4.0) - ImageSlideshow/Core - - ImageSlideshow/Alamofire (1.9.3): + - ImageSlideshow/Alamofire (1.9.4): - AlamofireImage (~> 4.0) - ImageSlideshow/Core - - ImageSlideshow/Core (1.9.3) - - ImageSlideshow/Kingfisher (1.9.3): + - ImageSlideshow/Core (1.9.4) + - ImageSlideshow/Kingfisher (1.9.4): - ImageSlideshow/Core - - Kingfisher (> 3.0) - - ImageSlideshow/SDWebImage (1.9.3): + - Kingfisher (>= 8.3.2) + - ImageSlideshow/SDWebImage (1.9.4): - ImageSlideshow/Core - - SDWebImage (>= 3.7) - - Kingfisher (8.3.2) - - SDWebImage (5.21.0): - - SDWebImage/Core (= 5.21.0) - - SDWebImage/Core (5.21.0) + - SDWebImage (>= 5.1) + - Kingfisher (8.4.0) + - SDWebImage (5.21.1): + - SDWebImage/Core (= 5.21.1) + - SDWebImage/Core (5.21.1) DEPENDENCIES: - ImageSlideshow (from `../`) @@ -60,10 +60,10 @@ SPEC CHECKSUMS: AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58 Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496 AlamofireImage: 843953fa97bee5f561cf05d83abd759e590b068d - ImageSlideshow: 7ec9503e623329cb09a970418a02e42f8ef92827 - Kingfisher: 0621d0ac0c78fecb19f6dc5303bde2b52abaf2f5 - SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868 + ImageSlideshow: d051d22234785c0a2a159e29e84bc15690f1439c + Kingfisher: b14cc47bbfa7a3c150dd12962ee9c86338545629 + SDWebImage: f29024626962457f3470184232766516dee8dfea -PODFILE CHECKSUM: 19810162c1a79de96d3684e707a993a0b605e6d7 +PODFILE CHECKSUM: db0833c2527dff5247b8fa656a5e4839c6e05cc6 COCOAPODS: 1.16.2 diff --git a/ImageSlideshow.podspec b/ImageSlideshow.podspec index aa1b5037..628efde2 100644 --- a/ImageSlideshow.podspec +++ b/ImageSlideshow.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = "ImageSlideshow" - s.version = "1.9.3" + s.version = "1.9.4" s.summary = "Image slideshow written in Swift with circular scrolling, timer and full screen viewer" # This description is used to generate tags and improve search results. @@ -27,8 +27,8 @@ Image slideshow is a Swift library providing customizable image slideshow with c s.source = { :git => "https://github.com/zvonicek/ImageSlideshow.git", :tag => s.version.to_s } s.social_media_url = 'https://twitter.com/zvonicek' - s.swift_versions = ['4.0', '4.1', '4.2', '5', '5.1', '5.2'] - s.platform = :ios, '13.0' + s.swift_versions = ['5', '5.1', '5.2', '5.10', '6.0', '6.1'] + s.platform = :ios, '15.0' s.requires_arc = true s.subspec 'Core' do |core| @@ -51,20 +51,18 @@ Image slideshow is a Swift library providing customizable image slideshow with c s.subspec 'Alamofire' do |subspec| subspec.dependency 'ImageSlideshow/Core' subspec.dependency 'AlamofireImage', '~> 4.0' - subspec.platform = :ios, '10.0' subspec.source_files = 'ImageSlideshow/Classes/InputSources/AlamofireSource.swift' end s.subspec 'SDWebImage' do |subspec| subspec.dependency 'ImageSlideshow/Core' - subspec.dependency 'SDWebImage', '>= 3.7' + subspec.dependency 'SDWebImage', '>= 5.1' subspec.source_files = 'ImageSlideshow/Classes/InputSources/SDWebImageSource.swift' end s.subspec 'Kingfisher' do |subspec| subspec.dependency 'ImageSlideshow/Core' - subspec.dependency 'Kingfisher', '> 3.0' - subspec.platform = :ios, '13.0' + subspec.dependency 'Kingfisher', '>= 8.3.2' subspec.source_files = 'ImageSlideshow/Classes/InputSources/KingfisherSource.swift' end diff --git a/Package.resolved b/Package.resolved index 316551e6..1f5c4102 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/Alamofire/Alamofire.git", "state": { "branch": null, - "revision": "fca036f7aeca07124067cb6e0c12b0ad6359e3d4", - "version": "5.1.0" + "revision": "7595cbcf59809f9977c5f6378500de2ad73b7ddb", + "version": "5.12.0" } }, { @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/Alamofire/AlamofireImage.git", "state": { "branch": null, - "revision": "3e8edbeb75227f8542aa87f90240cf0424d6362f", - "version": "4.1.0" + "revision": "4cf73d601c482b7d77bae47de3ef1b8bcf328ec1", + "version": "4.4.0" } }, { @@ -33,8 +33,8 @@ "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git", "state": { "branch": null, - "revision": "74ae21337c415bb542eb901803f3e84799265c34", - "version": "5.7.2" + "revision": "2de3a496eaf6df9a1312862adcfd54acd73c39c0", + "version": "5.21.7" } } ] diff --git a/Package.swift b/Package.swift index 46566b56..1b9c87f0 100644 --- a/Package.swift +++ b/Package.swift @@ -1,11 +1,13 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "ImageSlideshow", platforms: [ - .iOS(.v13), + .iOS(.v15), + // iOS-only library; declared to satisfy Kingfisher's macOS floor during resolution + .macOS(.v10_15), ], products: [ .library( @@ -23,7 +25,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/onevcat/Kingfisher.git", from: "8.3.2"), - .package(url: "https://github.com/Alamofire/AlamofireImage.git", from: "5.10.2"), + .package(url: "https://github.com/Alamofire/AlamofireImage.git", from: "4.3.0"), .package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.21.0") ], targets: [ From 9589e80b0318bf58827a57351f2f1aa25b6e882e Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Fri, 12 Jun 2026 00:57:14 -0400 Subject: [PATCH 09/17] Adopt main-actor isolation in AFURLSource Give AFURLSource the same treatment as the other input sources: @preconcurrency conformance with a @MainActor-isolated load/cancel, which also fixes the strict-concurrency 'sending non-Sendable closure' errors. Failures now report a nil image, consistent with the other sources, so the retry gesture is enabled. Co-Authored-By: Claude Fable 5 --- ImageSlideshow/Classes/InputSources/AFURLSource.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ImageSlideshow/Classes/InputSources/AFURLSource.swift b/ImageSlideshow/Classes/InputSources/AFURLSource.swift index 2f48cbd5..31639d89 100644 --- a/ImageSlideshow/Classes/InputSources/AFURLSource.swift +++ b/ImageSlideshow/Classes/InputSources/AFURLSource.swift @@ -10,7 +10,7 @@ import AFNetworking /// Input Source to image using AFNetworking @objcMembers -public class AFURLSource: NSObject, InputSource { +public class AFURLSource: NSObject, @preconcurrency InputSource { /// url to load public var url: URL @@ -39,15 +39,15 @@ public class AFURLSource: NSObject, InputSource { } } - public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { + @MainActor public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { imageView.setImageWith(URLRequest(url: url), placeholderImage: self.placeholder, success: { (_, _, image: UIImage) in callback(image) - }, failure: {[placeholder = self.placeholder] _, _, _ in - callback(placeholder) + }, failure: { _, _, _ in + callback(nil) }) } - public func cancelLoad(on imageView: UIImageView) { + @MainActor public func cancelLoad(on imageView: UIImageView) { imageView.cancelImageDownloadTask() } } From ad75fb16ac168a24dc1464f836d51a2f7a1b55a5 Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Fri, 12 Jun 2026 00:57:14 -0400 Subject: [PATCH 10/17] Fix example test build against the current SDK AFNetworking's #import now hits a private modular header, so disable clang modules for that pod and link its system frameworks explicitly via a post_install hook. Turn off user script sandboxing, which blocks the CocoaPods embed-frameworks phase. Co-Authored-By: Claude Fable 5 --- Example/ImageSlideshow.xcodeproj/project.pbxproj | 4 ++-- Example/Podfile | 14 ++++++++++++++ Example/Podfile.lock | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Example/ImageSlideshow.xcodeproj/project.pbxproj b/Example/ImageSlideshow.xcodeproj/project.pbxproj index e209b7ad..81e724ab 100644 --- a/Example/ImageSlideshow.xcodeproj/project.pbxproj +++ b/Example/ImageSlideshow.xcodeproj/project.pbxproj @@ -531,7 +531,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -591,7 +591,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/Example/Podfile b/Example/Podfile index 30eee49b..3ca37dce 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -8,3 +8,17 @@ target 'ImageSlideshow_Example' do pod "ImageSlideshow/SDWebImage", :path => "../" pod "ImageSlideshow/Kingfisher", :path => "../" end + +post_install do |installer| + installer.pods_project.targets.each do |target| + next unless target.name == 'AFNetworking' + target.build_configurations.each do |config| + # netinet6/in6.h became a private modular header in recent SDKs, + # which breaks AFNetworking's direct #import when modules are on. + # Without modules there is no auto-linking, so link the system + # frameworks explicitly. + config.build_settings['CLANG_ENABLE_MODULES'] = 'NO' + config.build_settings['OTHER_LDFLAGS'] = '$(inherited) -framework UIKit -framework WebKit -framework CoreGraphics -framework MobileCoreServices -framework SystemConfiguration -framework Security' + end + end +end diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 9429d34c..4ecc0869 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -64,6 +64,6 @@ SPEC CHECKSUMS: Kingfisher: b14cc47bbfa7a3c150dd12962ee9c86338545629 SDWebImage: f29024626962457f3470184232766516dee8dfea -PODFILE CHECKSUM: db0833c2527dff5247b8fa656a5e4839c6e05cc6 +PODFILE CHECKSUM: effe544cce4fa22f74c620eb62017b44555448d9 COCOAPODS: 1.16.2 From 5942ec52fb4e2d8fa38c30a4b64259c2025f2fc4 Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Fri, 12 Jun 2026 14:03:59 -0400 Subject: [PATCH 11/17] Remove dead code and unify example build settings Delete SwiftSupport.swift (empty since the Swift 4.2 shims were removed) and the Parse subspec with its source, which pinned Parse ~> 1.14 from 2016 and no longer builds. Unify the example project on SWIFT_VERSION 5.0 and deployment target 15.0 to match the Podfile. Co-Authored-By: Claude Fable 5 --- .../ImageSlideshow.xcodeproj/project.pbxproj | 47 +++++++++++++++---- ImageSlideshow.podspec | 6 --- .../Classes/Core/SwiftSupport.swift | 9 ---- .../Classes/InputSources/ParseSource.swift | 35 -------------- Package.swift | 1 - 5 files changed, 37 insertions(+), 61 deletions(-) delete mode 100644 ImageSlideshow/Classes/Core/SwiftSupport.swift delete mode 100644 ImageSlideshow/Classes/InputSources/ParseSource.swift diff --git a/Example/ImageSlideshow.xcodeproj/project.pbxproj b/Example/ImageSlideshow.xcodeproj/project.pbxproj index 81e724ab..e6449141 100644 --- a/Example/ImageSlideshow.xcodeproj/project.pbxproj +++ b/Example/ImageSlideshow.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 43F0FAD42568BAEB008FFD39 /* Bundle+Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F0FAD32568BAEB008FFD39 /* Bundle+Module.swift */; }; 48A9DE9233FBEA3CF63A8E54 /* Pods_ImageSlideshow_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AA07A6EDAC622F1407E6C80 /* Pods_ImageSlideshow_Example.framework */; }; + 5BDEBB22330B8DD8D3360CEA /* Pods_ImageSlideshow_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42AB2570E7B79716B4E68BD6 /* Pods_ImageSlideshow_Tests.framework */; }; 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; }; 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; }; 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; }; @@ -28,7 +29,6 @@ D0E8A9F51D97EB94007EC517 /* UIImage+AspectFit.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9EE1D97EB94007EC517 /* UIImage+AspectFit.swift */; }; D0E8A9F61D97EB94007EC517 /* UIImageView+Tools.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9EF1D97EB94007EC517 /* UIImageView+Tools.swift */; }; D0E8A9F71D97EB94007EC517 /* ZoomAnimatedTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9F01D97EB94007EC517 /* ZoomAnimatedTransitioning.swift */; }; - F539204C210F03610057EFB3 /* SwiftSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = F539204B210F03600057EFB3 /* SwiftSupport.swift */; }; F802998F20CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */; }; F802999020CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */; }; F802999120CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */; }; @@ -47,6 +47,7 @@ /* Begin PBXFileReference section */ 09417F1351C21E0DCE8667BE /* Pods-ImageSlideshow_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageSlideshow_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-ImageSlideshow_Example/Pods-ImageSlideshow_Example.release.xcconfig"; sourceTree = ""; }; 1C4985EDB005E63A830176CE /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; + 42AB2570E7B79716B4E68BD6 /* Pods_ImageSlideshow_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ImageSlideshow_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 43F0FAD32568BAEB008FFD39 /* Bundle+Module.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Bundle+Module.swift"; path = "../../ImageSlideshow/Classes/Core/Bundle+Module.swift"; sourceTree = ""; }; 5FD91AF3667236846934E8B9 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 607FACD01AFB9204008FA782 /* ImageSlideshow_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ImageSlideshow_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -60,7 +61,9 @@ 607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; }; 749E212B852A3FE6757C1D36 /* ImageSlideshow.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = ImageSlideshow.podspec; path = ../ImageSlideshow.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 7766BA4B267A696E6406BE86 /* Pods-ImageSlideshow_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageSlideshow_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ImageSlideshow_Tests/Pods-ImageSlideshow_Tests.debug.xcconfig"; sourceTree = ""; }; 8AA07A6EDAC622F1407E6C80 /* Pods_ImageSlideshow_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ImageSlideshow_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + AFF019CC2ABD57129CAD4420 /* Pods-ImageSlideshow_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageSlideshow_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ImageSlideshow_Tests/Pods-ImageSlideshow_Tests.release.xcconfig"; sourceTree = ""; }; D007954E2043262C0053E25F /* TableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; D0083DCD1EB739E700126B21 /* ActivityIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ActivityIndicator.swift; path = ../../ImageSlideshow/Classes/Core/ActivityIndicator.swift; sourceTree = ""; }; D00C7A2520B4C0A000E5725B /* ic_cross_white@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ic_cross_white@3x.png"; path = "../../../ImageSlideshow/Assets/ic_cross_white@3x.png"; sourceTree = ""; }; @@ -76,7 +79,6 @@ D0E8A9EE1D97EB94007EC517 /* UIImage+AspectFit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImage+AspectFit.swift"; path = "../../ImageSlideshow/Classes/Core/UIImage+AspectFit.swift"; sourceTree = ""; }; D0E8A9EF1D97EB94007EC517 /* UIImageView+Tools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImageView+Tools.swift"; path = "../../ImageSlideshow/Classes/Core/UIImageView+Tools.swift"; sourceTree = ""; }; D0E8A9F01D97EB94007EC517 /* ZoomAnimatedTransitioning.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ZoomAnimatedTransitioning.swift; path = ../../ImageSlideshow/Classes/Core/ZoomAnimatedTransitioning.swift; sourceTree = ""; }; - F539204B210F03600057EFB3 /* SwiftSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftSupport.swift; path = ../../ImageSlideshow/Classes/Core/SwiftSupport.swift; sourceTree = ""; }; F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PageIndicatorPosition.swift; path = ../../ImageSlideshow/Classes/Core/PageIndicatorPosition.swift; sourceTree = ""; }; FD45C56C18E7B8EC08371B86 /* Pods-ImageSlideshow_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageSlideshow_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ImageSlideshow_Example/Pods-ImageSlideshow_Example.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -94,6 +96,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5BDEBB22330B8DD8D3360CEA /* Pods_ImageSlideshow_Tests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -185,6 +188,8 @@ children = ( FD45C56C18E7B8EC08371B86 /* Pods-ImageSlideshow_Example.debug.xcconfig */, 09417F1351C21E0DCE8667BE /* Pods-ImageSlideshow_Example.release.xcconfig */, + 7766BA4B267A696E6406BE86 /* Pods-ImageSlideshow_Tests.debug.xcconfig */, + AFF019CC2ABD57129CAD4420 /* Pods-ImageSlideshow_Tests.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -193,6 +198,7 @@ isa = PBXGroup; children = ( 8AA07A6EDAC622F1407E6C80 /* Pods_ImageSlideshow_Example.framework */, + 42AB2570E7B79716B4E68BD6 /* Pods_ImageSlideshow_Tests.framework */, ); name = Frameworks; sourceTree = ""; @@ -220,7 +226,6 @@ D0B974AF202738F6006217CF /* PageIndicator.swift */, F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */, D00C7A2420B4C05C00E5725B /* Resources */, - F539204B210F03600057EFB3 /* SwiftSupport.swift */, D0E8A9EE1D97EB94007EC517 /* UIImage+AspectFit.swift */, D0E8A9EF1D97EB94007EC517 /* UIImageView+Tools.swift */, D0E8A9F01D97EB94007EC517 /* ZoomAnimatedTransitioning.swift */, @@ -265,6 +270,7 @@ isa = PBXNativeTarget; buildConfigurationList = 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "ImageSlideshow_Tests" */; buildPhases = ( + DE81AFB43501D55E49BBDFDC /* [CP] Check Pods Manifest.lock */, 607FACE11AFB9204008FA782 /* Sources */, 607FACE21AFB9204008FA782 /* Frameworks */, 607FACE31AFB9204008FA782 /* Resources */, @@ -386,7 +392,6 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-ImageSlideshow_Example/Pods-ImageSlideshow_Example-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework", "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", "${BUILT_PRODUCTS_DIR}/AlamofireImage/AlamofireImage.framework", "${BUILT_PRODUCTS_DIR}/ImageSlideshow/ImageSlideshow.framework", @@ -395,7 +400,6 @@ ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AFNetworking.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ImageSlideshow.framework", @@ -425,6 +429,28 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + DE81AFB43501D55E49BBDFDC /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ImageSlideshow_Tests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -461,7 +487,6 @@ F802999120CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */, D0E8A9F51D97EB94007EC517 /* UIImage+AspectFit.swift in Sources */, D0E8A9F11D97EB94007EC517 /* FullScreenSlideshowViewController.swift in Sources */, - F539204C210F03610057EFB3 /* SwiftSupport.swift in Sources */, D0B974B0202738F6006217CF /* PageIndicator.swift in Sources */, D0E8A9F31D97EB94007EC517 /* ImageSlideshowItem.swift in Sources */, ); @@ -547,13 +572,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -600,13 +625,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -649,6 +674,7 @@ }; 607FACF31AFB9204008FA782 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 7766BA4B267A696E6406BE86 /* Pods-ImageSlideshow_Tests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = 5VWB99DS38; @@ -672,6 +698,7 @@ }; 607FACF41AFB9204008FA782 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = AFF019CC2ABD57129CAD4420 /* Pods-ImageSlideshow_Tests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = 5VWB99DS38; diff --git a/ImageSlideshow.podspec b/ImageSlideshow.podspec index 628efde2..f234de1a 100644 --- a/ImageSlideshow.podspec +++ b/ImageSlideshow.podspec @@ -66,12 +66,6 @@ Image slideshow is a Swift library providing customizable image slideshow with c subspec.source_files = 'ImageSlideshow/Classes/InputSources/KingfisherSource.swift' end - s.subspec 'Parse' do |subspec| - subspec.dependency 'ImageSlideshow/Core' - subspec.dependency 'Parse', '~> 1.14' - subspec.source_files = 'ImageSlideshow/Classes/InputSources/ParseSource.swift' - end - s.default_subspec = 'Core' end diff --git a/ImageSlideshow/Classes/Core/SwiftSupport.swift b/ImageSlideshow/Classes/Core/SwiftSupport.swift deleted file mode 100644 index 0c669c51..00000000 --- a/ImageSlideshow/Classes/Core/SwiftSupport.swift +++ /dev/null @@ -1,9 +0,0 @@ -// -// SwiftSupport.swift -// ImageSlideshow -// -// Created by Pierluigi Cifani on 30/07/2018. -// - -import UIKit - diff --git a/ImageSlideshow/Classes/InputSources/ParseSource.swift b/ImageSlideshow/Classes/InputSources/ParseSource.swift deleted file mode 100644 index 8e7acc22..00000000 --- a/ImageSlideshow/Classes/InputSources/ParseSource.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// ParseImageSource.swift -// ImageSlideshow -// -// Created by Jaime Agudo Lopez on 14/01/2017. -// -import Parse - -/// Input Source to image using Parse -public class ParseSource: NSObject, InputSource { - var file: PFFileObject - var placeholder: UIImage? - - /// Initializes a new source with URL and optionally a placeholder - /// - parameter url: a url to be loaded - /// - parameter placeholder: a placeholder used before image is loaded - public init(file: PFFileObject, placeholder: UIImage? = nil) { - self.file = file - self.placeholder = placeholder - super.init() - } - - @objc public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { - imageView.image = self.placeholder - - self.file.getDataInBackground {(data: Data?, _: Error?) in - if let data = data, let image = UIImage(data: data) { - imageView.image = image - callback(image) - } else { - callback(nil) - } - } - } -} diff --git a/Package.swift b/Package.swift index 1b9c87f0..ac07f821 100644 --- a/Package.swift +++ b/Package.swift @@ -41,7 +41,6 @@ let package = Package( "Classes/Core/InputSource.swift", "Classes/Core/PageIndicator.swift", "Classes/Core/PageIndicatorPosition.swift", - "Classes/Core/SwiftSupport.swift", "Classes/Core/UIImage+AspectFit.swift", "Classes/Core/UIImageView+Tools.swift", "Classes/Core/ZoomAnimatedTransitioning.swift", From 352c27e78d94c1d1128f914dd012b1d75bfb56da Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Fri, 12 Jun 2026 14:03:59 -0400 Subject: [PATCH 12/17] Drop AFNetworking from the example app AFNetworking is deprecated upstream and needed a build workaround on current SDKs; the example keeps demonstrating remote loading through AlamofireSource, SDWebImageSource and KingfisherSource. Integrate the test target with CocoaPods so tests can import the framework. Co-Authored-By: Claude Fable 5 --- Example/ImageSlideshow/ViewController.swift | 3 +- Example/Podfile | 15 +------ Example/Podfile.lock | 47 ++++++--------------- 3 files changed, 16 insertions(+), 49 deletions(-) diff --git a/Example/ImageSlideshow/ViewController.swift b/Example/ImageSlideshow/ViewController.swift index 36fa63c3..bb1aedf8 100644 --- a/Example/ImageSlideshow/ViewController.swift +++ b/Example/ImageSlideshow/ViewController.swift @@ -18,7 +18,6 @@ class ViewController: UIViewController { @IBOutlet var slideshow: ImageSlideshow! let localSource = [BundleImageSource(imageString: "img1"), BundleImageSource(imageString: "img2"), BundleImageSource(imageString: "img3"), BundleImageSource(imageString: "img4")] - let afNetworkingSource = [AFURLSource(urlString: "https://images.unsplash.com/photo-1432679963831-2dab49187847?w=1080")!, AFURLSource(urlString: "https://images.unsplash.com/photo-1447746249824-4be4e1b76d66?w=1080")!, AFURLSource(urlString: "https://images.unsplash.com/photo-1463595373836-6e0b0a8ee322?w=1080")!] let alamofireSource = [AlamofireSource(urlString: "https://images.unsplash.com/photo-1432679963831-2dab49187847?w=1080")!, AlamofireSource(urlString: "https://images.unsplash.com/photo-1447746249824-4be4e1b76d66?w=1080")!, AlamofireSource(urlString: "https://images.unsplash.com/photo-1463595373836-6e0b0a8ee322?w=1080")!] let sdWebImageSource = [SDWebImageSource(urlString: "https://images.unsplash.com/photo-1432679963831-2dab49187847?w=1080")!, SDWebImageSource(urlString: "https://images.unsplash.com/photo-1447746249824-4be4e1b76d66?w=1080")!, SDWebImageSource(urlString: "https://images.unsplash.com/photo-1463595373836-6e0b0a8ee322?w=1080")!] let kingfisherSource = [KingfisherSource(urlString: "https://images.unsplash.com/photo-1432679963831-2dab49187847?w=1080")!, KingfisherSource(urlString: "https://images.unsplash.com/photo-1447746249824-4be4e1b76d66?w=1080")!, KingfisherSource(urlString: "https://images.unsplash.com/photo-1463595373836-6e0b0a8ee322?w=1080")!] @@ -36,7 +35,7 @@ class ViewController: UIViewController { slideshow.activityIndicator = DefaultActivityIndicator() slideshow.delegate = self - // can be used with other sample sources as `afNetworkingSource`, `alamofireSource` or `sdWebImageSource` or `kingfisherSource` + // can be used with other sample sources as `alamofireSource`, `sdWebImageSource` or `kingfisherSource` slideshow.setImageInputs(localSource) let recognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.didTap)) diff --git a/Example/Podfile b/Example/Podfile index 3ca37dce..957106bd 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -3,22 +3,11 @@ use_frameworks! target 'ImageSlideshow_Example' do pod "ImageSlideshow", :path => "../" - pod "ImageSlideshow/AFURL", :path => "../" pod "ImageSlideshow/Alamofire", :path => "../" pod "ImageSlideshow/SDWebImage", :path => "../" pod "ImageSlideshow/Kingfisher", :path => "../" -end -post_install do |installer| - installer.pods_project.targets.each do |target| - next unless target.name == 'AFNetworking' - target.build_configurations.each do |config| - # netinet6/in6.h became a private modular header in recent SDKs, - # which breaks AFNetworking's direct #import when modules are on. - # Without modules there is no auto-linking, so link the system - # frameworks explicitly. - config.build_settings['CLANG_ENABLE_MODULES'] = 'NO' - config.build_settings['OTHER_LDFLAGS'] = '$(inherited) -framework UIKit -framework WebKit -framework CoreGraphics -framework MobileCoreServices -framework SystemConfiguration -framework Security' + target 'ImageSlideshow_Tests' do + inherit! :search_paths end - end end diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 4ecc0869..25aa1c37 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,27 +1,9 @@ PODS: - - AFNetworking (4.0.1): - - AFNetworking/NSURLSession (= 4.0.1) - - AFNetworking/Reachability (= 4.0.1) - - AFNetworking/Security (= 4.0.1) - - AFNetworking/Serialization (= 4.0.1) - - AFNetworking/UIKit (= 4.0.1) - - AFNetworking/NSURLSession (4.0.1): - - AFNetworking/Reachability - - AFNetworking/Security - - AFNetworking/Serialization - - AFNetworking/Reachability (4.0.1) - - AFNetworking/Security (4.0.1) - - AFNetworking/Serialization (4.0.1) - - AFNetworking/UIKit (4.0.1): - - AFNetworking/NSURLSession - - Alamofire (5.10.2) - - AlamofireImage (4.3.0): - - Alamofire (~> 5.8) + - Alamofire (5.11.2) + - AlamofireImage (4.4.0): + - Alamofire (~> 5.11) - ImageSlideshow (1.9.4): - ImageSlideshow/Core (= 1.9.4) - - ImageSlideshow/AFURL (1.9.4): - - AFNetworking (~> 4.0) - - ImageSlideshow/Core - ImageSlideshow/Alamofire (1.9.4): - AlamofireImage (~> 4.0) - ImageSlideshow/Core @@ -32,21 +14,19 @@ PODS: - ImageSlideshow/SDWebImage (1.9.4): - ImageSlideshow/Core - SDWebImage (>= 5.1) - - Kingfisher (8.4.0) - - SDWebImage (5.21.1): - - SDWebImage/Core (= 5.21.1) - - SDWebImage/Core (5.21.1) + - Kingfisher (8.9.0) + - SDWebImage (5.21.7): + - SDWebImage/Core (= 5.21.7) + - SDWebImage/Core (5.21.7) DEPENDENCIES: - ImageSlideshow (from `../`) - - ImageSlideshow/AFURL (from `../`) - ImageSlideshow/Alamofire (from `../`) - ImageSlideshow/Kingfisher (from `../`) - ImageSlideshow/SDWebImage (from `../`) SPEC REPOS: trunk: - - AFNetworking - Alamofire - AlamofireImage - Kingfisher @@ -57,13 +37,12 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58 - Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496 - AlamofireImage: 843953fa97bee5f561cf05d83abd759e590b068d - ImageSlideshow: d051d22234785c0a2a159e29e84bc15690f1439c - Kingfisher: b14cc47bbfa7a3c150dd12962ee9c86338545629 - SDWebImage: f29024626962457f3470184232766516dee8dfea + Alamofire: 400275dd1c6d87d95a041861d2a59da4b520a203 + AlamofireImage: 19ec9c0991f52cc7f9ba6a9d4ec782e29bdf6210 + ImageSlideshow: 9778cb0ce8b1f8d14145d4c2934495e632249141 + Kingfisher: 90f3a3c2871a71e01d5493c1c196fc2d3ff132cf + SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf -PODFILE CHECKSUM: effe544cce4fa22f74c620eb62017b44555448d9 +PODFILE CHECKSUM: 958bd53553061c42535e4a018e4bf567b60f6526 COCOAPODS: 1.16.2 From 620dcc97d8984545833abc4db1c91fd9aceb19d6 Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Fri, 12 Jun 2026 14:04:00 -0400 Subject: [PATCH 13/17] Replace placeholder tests with real unit tests Cover the circular paging math (dummy edge pages, wrap-around, non-circular bounds), PageIndicatorPosition frame and padding computation, and the input-source callback contract including the failed-load retry behavior. Co-Authored-By: Claude Fable 5 --- Example/Tests/Tests.swift | 195 +++++++++++++++++++++++++++++++++++--- 1 file changed, 180 insertions(+), 15 deletions(-) diff --git a/Example/Tests/Tests.swift b/Example/Tests/Tests.swift index 66bf1af1..c50577e1 100644 --- a/Example/Tests/Tests.swift +++ b/Example/Tests/Tests.swift @@ -1,28 +1,193 @@ import UIKit import XCTest +@testable import ImageSlideshow -class Tests: XCTestCase { +/// Input source stub that synchronously reports the given image (nil = failure) +private class StubSource: NSObject, @preconcurrency InputSource { + let image: UIImage? - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. + init(image: UIImage?) { + self.image = image + super.init() } - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() + @MainActor func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) { + imageView.image = image + callback(image) } +} + +private func solidImage() -> UIImage { + UIGraphicsBeginImageContext(CGSize(width: 1, height: 1)) + defer { UIGraphicsEndImageContext() } + return UIGraphicsGetImageFromCurrentImageContext()! +} + +@MainActor +class PagingTests: XCTestCase { + + private let width: CGFloat = 300 + + private func makeSlideshow(circular: Bool, count: Int) -> ImageSlideshow { + let slideshow = ImageSlideshow(frame: CGRect(x: 0, y: 0, width: width, height: 200)) + slideshow.circular = circular + slideshow.setImageInputs((0.. Date: Fri, 12 Jun 2026 14:04:00 -0400 Subject: [PATCH 14/17] Add CI workflow building SPM products and running example tests Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..b225fbe3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + +jobs: + spm: + name: SPM build (iOS) + runs-on: macos-15 + steps: + - uses: actions/checkout@v4 + # _Pods.xcodeproj would shadow the Swift package for xcodebuild + - name: Remove CocoaPods development project placeholder + run: rm -rf _Pods.xcodeproj + - name: Build all package products + run: | + xcodebuild -scheme ImageSlideshow-Package \ + -destination 'generic/platform=iOS Simulator' \ + build + + example-tests: + name: Example app tests + runs-on: macos-15 + steps: + - uses: actions/checkout@v4 + - name: Install pods + working-directory: Example + run: pod install + - name: Run tests + working-directory: Example + run: | + DEVICE=$(xcrun simctl list devices available | grep -m1 -oE 'iPhone [^(]+' | sed 's/ *$//') + echo "Using simulator: $DEVICE" + xcodebuild test \ + -workspace ImageSlideshow.xcworkspace \ + -scheme ImageSlideshow-Example \ + -destination "platform=iOS Simulator,name=$DEVICE" \ + CODE_SIGNING_ALLOWED=NO From 2327237d9fdfb19244c3ef7516a62ea9ee9497d4 Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Fri, 12 Jun 2026 14:04:00 -0400 Subject: [PATCH 15/17] Backfill changelog for 1.9.4 Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a44c2d0..53cb571d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Change log +## [1.9.4](https://github.com/zvonicek/ImageSlideshow/releases/tag/1.9.4) (12/06/2026) + +## Breaking + +- Minimum deployment target raised to iOS 15 (CocoaPods and Swift Package Manager) +- Removed the unmaintained `Parse` subspec +- Removed the Swift 4.2 compatibility typealiases (`UIViewContentMode` etc.) + +## New Features + +- Input sources, activity indicators and page indicators adopt main-actor isolation for Swift concurrency + +## Fixes + +- Fixed Swift Package Manager dependency resolution (AlamofireImage requirement pointed at a nonexistent version) +- Kingfisher loads run synchronously on the main actor, fixing a race where a deferred cancel could abort a newly started download +- Failed image loads now report nil so the retry gesture is enabled (KingfisherSource, AFURLSource) +- Interactive dismiss gesture is removed from the window it was added to, fixing a leak when the key window changes + ## [1.6.1](https://github.com/zvonicek/ImageSlideshow/releases/tag/1.6.1) (11/06/2018) ## Fixes From ab7f8a4575eda27a46dd3a3e1578ef9cac39367f Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Sat, 13 Jun 2026 12:57:19 -0400 Subject: [PATCH 16/17] Adopt XcodeGen for the example project Add Example/project.yml as the source of truth for the Xcode project. The generated ImageSlideshow.xcodeproj/ is gitignored (inverse convention): CI installs XcodeGen and runs `xcodegen generate` before `pod install`, and contributors do the same locally. The generated project also fixes a legacy quirk where PageIndicatorPosition.swift was compiled directly into the app and test targets in addition to the framework. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 5 + .gitignore | 3 + .../ImageSlideshow.xcodeproj/project.pbxproj | 828 ------------------ .../contents.xcworkspacedata | 7 - .../xcschemes/ImageSlideshow-Example.xcscheme | 111 --- .../ImageSlideshow_framework.xcscheme | 76 -- Example/project.yml | 87 ++ 7 files changed, 95 insertions(+), 1022 deletions(-) delete mode 100644 Example/ImageSlideshow.xcodeproj/project.pbxproj delete mode 100644 Example/ImageSlideshow.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow-Example.xcscheme delete mode 100644 Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow_framework.xcscheme create mode 100644 Example/project.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b225fbe3..f441fde5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,11 @@ jobs: runs-on: macos-15 steps: - uses: actions/checkout@v4 + - name: Install XcodeGen + run: brew install xcodegen + - name: Generate Xcode project + working-directory: Example + run: xcodegen generate - name: Install pods working-directory: Example run: pod install diff --git a/.gitignore b/.gitignore index 669d819a..9c38ad7b 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ Pods/ # Swift Package Manager .build/ + +# XcodeGen — generated project (regenerated by CI and locally via `xcodegen generate`) +Example/ImageSlideshow.xcodeproj/ diff --git a/Example/ImageSlideshow.xcodeproj/project.pbxproj b/Example/ImageSlideshow.xcodeproj/project.pbxproj deleted file mode 100644 index e6449141..00000000 --- a/Example/ImageSlideshow.xcodeproj/project.pbxproj +++ /dev/null @@ -1,828 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 43F0FAD42568BAEB008FFD39 /* Bundle+Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F0FAD32568BAEB008FFD39 /* Bundle+Module.swift */; }; - 48A9DE9233FBEA3CF63A8E54 /* Pods_ImageSlideshow_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AA07A6EDAC622F1407E6C80 /* Pods_ImageSlideshow_Example.framework */; }; - 5BDEBB22330B8DD8D3360CEA /* Pods_ImageSlideshow_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42AB2570E7B79716B4E68BD6 /* Pods_ImageSlideshow_Tests.framework */; }; - 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; }; - 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; }; - 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; }; - 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; - 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; }; - 607FACEC1AFB9204008FA782 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* Tests.swift */; }; - D007954F2043262C0053E25F /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007954E2043262C0053E25F /* TableViewController.swift */; }; - D0083DCE1EB739E700126B21 /* ActivityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0083DCD1EB739E700126B21 /* ActivityIndicator.swift */; }; - D00C7A2720B4C0A100E5725B /* ic_cross_white@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = D00C7A2520B4C0A000E5725B /* ic_cross_white@3x.png */; }; - D00C7A2820B4C0A100E5725B /* ic_cross_white@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D00C7A2620B4C0A100E5725B /* ic_cross_white@2x.png */; }; - D0B974B0202738F6006217CF /* PageIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B974AF202738F6006217CF /* PageIndicator.swift */; }; - D0E8A9E61D97EB6D007EC517 /* ImageSlideshow_framework.h in Headers */ = {isa = PBXBuildFile; fileRef = D0E8A9E41D97EB6D007EC517 /* ImageSlideshow_framework.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0E8A9F11D97EB94007EC517 /* FullScreenSlideshowViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9EA1D97EB94007EC517 /* FullScreenSlideshowViewController.swift */; }; - D0E8A9F21D97EB94007EC517 /* ImageSlideshow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9EB1D97EB94007EC517 /* ImageSlideshow.swift */; }; - D0E8A9F31D97EB94007EC517 /* ImageSlideshowItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9EC1D97EB94007EC517 /* ImageSlideshowItem.swift */; }; - D0E8A9F41D97EB94007EC517 /* InputSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9ED1D97EB94007EC517 /* InputSource.swift */; }; - D0E8A9F51D97EB94007EC517 /* UIImage+AspectFit.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9EE1D97EB94007EC517 /* UIImage+AspectFit.swift */; }; - D0E8A9F61D97EB94007EC517 /* UIImageView+Tools.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9EF1D97EB94007EC517 /* UIImageView+Tools.swift */; }; - D0E8A9F71D97EB94007EC517 /* ZoomAnimatedTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9F01D97EB94007EC517 /* ZoomAnimatedTransitioning.swift */; }; - F802998F20CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */; }; - F802999020CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */; }; - F802999120CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 607FACC81AFB9204008FA782 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 607FACCF1AFB9204008FA782; - remoteInfo = ImageSlideshow; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 09417F1351C21E0DCE8667BE /* Pods-ImageSlideshow_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageSlideshow_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-ImageSlideshow_Example/Pods-ImageSlideshow_Example.release.xcconfig"; sourceTree = ""; }; - 1C4985EDB005E63A830176CE /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; - 42AB2570E7B79716B4E68BD6 /* Pods_ImageSlideshow_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ImageSlideshow_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 43F0FAD32568BAEB008FFD39 /* Bundle+Module.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Bundle+Module.swift"; path = "../../ImageSlideshow/Classes/Core/Bundle+Module.swift"; sourceTree = ""; }; - 5FD91AF3667236846934E8B9 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; - 607FACD01AFB9204008FA782 /* ImageSlideshow_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ImageSlideshow_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 607FACD71AFB9204008FA782 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - 607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 607FACE51AFB9204008FA782 /* ImageSlideshow_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ImageSlideshow_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; }; - 749E212B852A3FE6757C1D36 /* ImageSlideshow.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = ImageSlideshow.podspec; path = ../ImageSlideshow.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 7766BA4B267A696E6406BE86 /* Pods-ImageSlideshow_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageSlideshow_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ImageSlideshow_Tests/Pods-ImageSlideshow_Tests.debug.xcconfig"; sourceTree = ""; }; - 8AA07A6EDAC622F1407E6C80 /* Pods_ImageSlideshow_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ImageSlideshow_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - AFF019CC2ABD57129CAD4420 /* Pods-ImageSlideshow_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageSlideshow_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ImageSlideshow_Tests/Pods-ImageSlideshow_Tests.release.xcconfig"; sourceTree = ""; }; - D007954E2043262C0053E25F /* TableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; - D0083DCD1EB739E700126B21 /* ActivityIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ActivityIndicator.swift; path = ../../ImageSlideshow/Classes/Core/ActivityIndicator.swift; sourceTree = ""; }; - D00C7A2520B4C0A000E5725B /* ic_cross_white@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ic_cross_white@3x.png"; path = "../../../ImageSlideshow/Assets/ic_cross_white@3x.png"; sourceTree = ""; }; - D00C7A2620B4C0A100E5725B /* ic_cross_white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ic_cross_white@2x.png"; path = "../../../ImageSlideshow/Assets/ic_cross_white@2x.png"; sourceTree = ""; }; - D0B974AF202738F6006217CF /* PageIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PageIndicator.swift; path = ../../ImageSlideshow/Classes/Core/PageIndicator.swift; sourceTree = ""; }; - D0E8A9E21D97EB6D007EC517 /* ImageSlideshow.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ImageSlideshow.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - D0E8A9E41D97EB6D007EC517 /* ImageSlideshow_framework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageSlideshow_framework.h; sourceTree = ""; }; - D0E8A9E51D97EB6D007EC517 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - D0E8A9EA1D97EB94007EC517 /* FullScreenSlideshowViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FullScreenSlideshowViewController.swift; path = ../../ImageSlideshow/Classes/Core/FullScreenSlideshowViewController.swift; sourceTree = ""; }; - D0E8A9EB1D97EB94007EC517 /* ImageSlideshow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageSlideshow.swift; path = ../../ImageSlideshow/Classes/Core/ImageSlideshow.swift; sourceTree = ""; }; - D0E8A9EC1D97EB94007EC517 /* ImageSlideshowItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageSlideshowItem.swift; path = ../../ImageSlideshow/Classes/Core/ImageSlideshowItem.swift; sourceTree = ""; }; - D0E8A9ED1D97EB94007EC517 /* InputSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InputSource.swift; path = ../../ImageSlideshow/Classes/Core/InputSource.swift; sourceTree = ""; }; - D0E8A9EE1D97EB94007EC517 /* UIImage+AspectFit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImage+AspectFit.swift"; path = "../../ImageSlideshow/Classes/Core/UIImage+AspectFit.swift"; sourceTree = ""; }; - D0E8A9EF1D97EB94007EC517 /* UIImageView+Tools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImageView+Tools.swift"; path = "../../ImageSlideshow/Classes/Core/UIImageView+Tools.swift"; sourceTree = ""; }; - D0E8A9F01D97EB94007EC517 /* ZoomAnimatedTransitioning.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ZoomAnimatedTransitioning.swift; path = ../../ImageSlideshow/Classes/Core/ZoomAnimatedTransitioning.swift; sourceTree = ""; }; - F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PageIndicatorPosition.swift; path = ../../ImageSlideshow/Classes/Core/PageIndicatorPosition.swift; sourceTree = ""; }; - FD45C56C18E7B8EC08371B86 /* Pods-ImageSlideshow_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageSlideshow_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ImageSlideshow_Example/Pods-ImageSlideshow_Example.debug.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 607FACCD1AFB9204008FA782 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 48A9DE9233FBEA3CF63A8E54 /* Pods_ImageSlideshow_Example.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 607FACE21AFB9204008FA782 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 5BDEBB22330B8DD8D3360CEA /* Pods_ImageSlideshow_Tests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - D0E8A9DE1D97EB6D007EC517 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 607FACC71AFB9204008FA782 = { - isa = PBXGroup; - children = ( - 607FACF51AFB993E008FA782 /* Podspec Metadata */, - 607FACD21AFB9204008FA782 /* Example for ImageSlideshow */, - 607FACE81AFB9204008FA782 /* Tests */, - D0E8A9E31D97EB6D007EC517 /* ImageSlideshow_framework */, - 607FACD11AFB9204008FA782 /* Products */, - 67EF8AB7524DB4FF7F66A17E /* Pods */, - 88C40B0495D05599E2889C22 /* Frameworks */, - ); - sourceTree = ""; - }; - 607FACD11AFB9204008FA782 /* Products */ = { - isa = PBXGroup; - children = ( - 607FACD01AFB9204008FA782 /* ImageSlideshow_Example.app */, - 607FACE51AFB9204008FA782 /* ImageSlideshow_Tests.xctest */, - D0E8A9E21D97EB6D007EC517 /* ImageSlideshow.framework */, - ); - name = Products; - sourceTree = ""; - }; - 607FACD21AFB9204008FA782 /* Example for ImageSlideshow */ = { - isa = PBXGroup; - children = ( - 607FACD51AFB9204008FA782 /* AppDelegate.swift */, - 607FACD71AFB9204008FA782 /* ViewController.swift */, - D007954E2043262C0053E25F /* TableViewController.swift */, - 607FACD91AFB9204008FA782 /* Main.storyboard */, - 607FACDC1AFB9204008FA782 /* Images.xcassets */, - 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */, - 607FACD31AFB9204008FA782 /* Supporting Files */, - ); - name = "Example for ImageSlideshow"; - path = ImageSlideshow; - sourceTree = ""; - }; - 607FACD31AFB9204008FA782 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 607FACD41AFB9204008FA782 /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 607FACE81AFB9204008FA782 /* Tests */ = { - isa = PBXGroup; - children = ( - 607FACEB1AFB9204008FA782 /* Tests.swift */, - 607FACE91AFB9204008FA782 /* Supporting Files */, - ); - path = Tests; - sourceTree = ""; - }; - 607FACE91AFB9204008FA782 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 607FACEA1AFB9204008FA782 /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 607FACF51AFB993E008FA782 /* Podspec Metadata */ = { - isa = PBXGroup; - children = ( - 749E212B852A3FE6757C1D36 /* ImageSlideshow.podspec */, - 1C4985EDB005E63A830176CE /* README.md */, - 5FD91AF3667236846934E8B9 /* LICENSE */, - ); - name = "Podspec Metadata"; - sourceTree = ""; - }; - 67EF8AB7524DB4FF7F66A17E /* Pods */ = { - isa = PBXGroup; - children = ( - FD45C56C18E7B8EC08371B86 /* Pods-ImageSlideshow_Example.debug.xcconfig */, - 09417F1351C21E0DCE8667BE /* Pods-ImageSlideshow_Example.release.xcconfig */, - 7766BA4B267A696E6406BE86 /* Pods-ImageSlideshow_Tests.debug.xcconfig */, - AFF019CC2ABD57129CAD4420 /* Pods-ImageSlideshow_Tests.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; - 88C40B0495D05599E2889C22 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 8AA07A6EDAC622F1407E6C80 /* Pods_ImageSlideshow_Example.framework */, - 42AB2570E7B79716B4E68BD6 /* Pods_ImageSlideshow_Tests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - D00C7A2420B4C05C00E5725B /* Resources */ = { - isa = PBXGroup; - children = ( - D00C7A2620B4C0A100E5725B /* ic_cross_white@2x.png */, - D00C7A2520B4C0A000E5725B /* ic_cross_white@3x.png */, - ); - path = Resources; - sourceTree = ""; - }; - D0E8A9E31D97EB6D007EC517 /* ImageSlideshow_framework */ = { - isa = PBXGroup; - children = ( - D0083DCD1EB739E700126B21 /* ActivityIndicator.swift */, - 43F0FAD32568BAEB008FFD39 /* Bundle+Module.swift */, - D0E8A9EA1D97EB94007EC517 /* FullScreenSlideshowViewController.swift */, - D0E8A9E41D97EB6D007EC517 /* ImageSlideshow_framework.h */, - D0E8A9EB1D97EB94007EC517 /* ImageSlideshow.swift */, - D0E8A9EC1D97EB94007EC517 /* ImageSlideshowItem.swift */, - D0E8A9E51D97EB6D007EC517 /* Info.plist */, - D0E8A9ED1D97EB94007EC517 /* InputSource.swift */, - D0B974AF202738F6006217CF /* PageIndicator.swift */, - F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */, - D00C7A2420B4C05C00E5725B /* Resources */, - D0E8A9EE1D97EB94007EC517 /* UIImage+AspectFit.swift */, - D0E8A9EF1D97EB94007EC517 /* UIImageView+Tools.swift */, - D0E8A9F01D97EB94007EC517 /* ZoomAnimatedTransitioning.swift */, - ); - path = ImageSlideshow_framework; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - D0E8A9DF1D97EB6D007EC517 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - D0E8A9E61D97EB6D007EC517 /* ImageSlideshow_framework.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 607FACCF1AFB9204008FA782 /* ImageSlideshow_Example */ = { - isa = PBXNativeTarget; - buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "ImageSlideshow_Example" */; - buildPhases = ( - C32710DF8FE75A6D757948CC /* [CP] Check Pods Manifest.lock */, - 607FACCC1AFB9204008FA782 /* Sources */, - 607FACCD1AFB9204008FA782 /* Frameworks */, - 607FACCE1AFB9204008FA782 /* Resources */, - 7EF425DA4D49DBDDA22C665D /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ImageSlideshow_Example; - productName = ImageSlideshow; - productReference = 607FACD01AFB9204008FA782 /* ImageSlideshow_Example.app */; - productType = "com.apple.product-type.application"; - }; - 607FACE41AFB9204008FA782 /* ImageSlideshow_Tests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "ImageSlideshow_Tests" */; - buildPhases = ( - DE81AFB43501D55E49BBDFDC /* [CP] Check Pods Manifest.lock */, - 607FACE11AFB9204008FA782 /* Sources */, - 607FACE21AFB9204008FA782 /* Frameworks */, - 607FACE31AFB9204008FA782 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 607FACE71AFB9204008FA782 /* PBXTargetDependency */, - ); - name = ImageSlideshow_Tests; - productName = Tests; - productReference = 607FACE51AFB9204008FA782 /* ImageSlideshow_Tests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - D0E8A9E11D97EB6D007EC517 /* ImageSlideshow_framework */ = { - isa = PBXNativeTarget; - buildConfigurationList = D0E8A9E91D97EB6D007EC517 /* Build configuration list for PBXNativeTarget "ImageSlideshow_framework" */; - buildPhases = ( - D0E8A9DD1D97EB6D007EC517 /* Sources */, - D0E8A9DE1D97EB6D007EC517 /* Frameworks */, - D0E8A9DF1D97EB6D007EC517 /* Headers */, - D0E8A9E01D97EB6D007EC517 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ImageSlideshow_framework; - productName = ImageSlideshow_framework; - productReference = D0E8A9E21D97EB6D007EC517 /* ImageSlideshow.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 607FACC81AFB9204008FA782 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastSwiftMigration = 0700; - LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 2600; - ORGANIZATIONNAME = CocoaPods; - TargetAttributes = { - 607FACCF1AFB9204008FA782 = { - CreatedOnToolsVersion = 6.3.1; - DevelopmentTeam = 5VWB99DS38; - LastSwiftMigration = 1020; - }; - 607FACE41AFB9204008FA782 = { - CreatedOnToolsVersion = 6.3.1; - DevelopmentTeam = 5VWB99DS38; - LastSwiftMigration = 1020; - TestTargetID = 607FACCF1AFB9204008FA782; - }; - D0E8A9E11D97EB6D007EC517 = { - CreatedOnToolsVersion = 8.0; - DevelopmentTeam = 9X4J83EL7M; - LastSwiftMigration = 0800; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "ImageSlideshow" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - English, - en, - Base, - ); - mainGroup = 607FACC71AFB9204008FA782; - productRefGroup = 607FACD11AFB9204008FA782 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 607FACCF1AFB9204008FA782 /* ImageSlideshow_Example */, - 607FACE41AFB9204008FA782 /* ImageSlideshow_Tests */, - D0E8A9E11D97EB6D007EC517 /* ImageSlideshow_framework */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 607FACCE1AFB9204008FA782 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */, - 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */, - 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 607FACE31AFB9204008FA782 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - D0E8A9E01D97EB6D007EC517 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D00C7A2720B4C0A100E5725B /* ic_cross_white@3x.png in Resources */, - D00C7A2820B4C0A100E5725B /* ic_cross_white@2x.png in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 7EF425DA4D49DBDDA22C665D /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-ImageSlideshow_Example/Pods-ImageSlideshow_Example-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", - "${BUILT_PRODUCTS_DIR}/AlamofireImage/AlamofireImage.framework", - "${BUILT_PRODUCTS_DIR}/ImageSlideshow/ImageSlideshow.framework", - "${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework", - "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ImageSlideshow.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ImageSlideshow_Example/Pods-ImageSlideshow_Example-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - C32710DF8FE75A6D757948CC /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-ImageSlideshow_Example-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - DE81AFB43501D55E49BBDFDC /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-ImageSlideshow_Tests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 607FACCC1AFB9204008FA782 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */, - F802998F20CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */, - D007954F2043262C0053E25F /* TableViewController.swift in Sources */, - 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 607FACE11AFB9204008FA782 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 607FACEC1AFB9204008FA782 /* Tests.swift in Sources */, - F802999020CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - D0E8A9DD1D97EB6D007EC517 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D0E8A9F21D97EB94007EC517 /* ImageSlideshow.swift in Sources */, - D0E8A9F41D97EB94007EC517 /* InputSource.swift in Sources */, - D0E8A9F61D97EB94007EC517 /* UIImageView+Tools.swift in Sources */, - D0E8A9F71D97EB94007EC517 /* ZoomAnimatedTransitioning.swift in Sources */, - D0083DCE1EB739E700126B21 /* ActivityIndicator.swift in Sources */, - 43F0FAD42568BAEB008FFD39 /* Bundle+Module.swift in Sources */, - F802999120CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */, - D0E8A9F51D97EB94007EC517 /* UIImage+AspectFit.swift in Sources */, - D0E8A9F11D97EB94007EC517 /* FullScreenSlideshowViewController.swift in Sources */, - D0B974B0202738F6006217CF /* PageIndicator.swift in Sources */, - D0E8A9F31D97EB94007EC517 /* ImageSlideshowItem.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 607FACE71AFB9204008FA782 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 607FACCF1AFB9204008FA782 /* ImageSlideshow_Example */; - targetProxy = 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 607FACD91AFB9204008FA782 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 607FACDA1AFB9204008FA782 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 607FACDF1AFB9204008FA782 /* Base */, - ); - name = LaunchScreen.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 607FACED1AFB9204008FA782 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - STRING_CATALOG_GENERATE_SYMBOLS = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 607FACEE1AFB9204008FA782 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - STRING_CATALOG_GENERATE_SYMBOLS = YES; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 607FACF01AFB9204008FA782 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = FD45C56C18E7B8EC08371B86 /* Pods-ImageSlideshow_Example.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = 5VWB99DS38; - INFOPLIST_FILE = ImageSlideshow/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MODULE_NAME = ExampleApp; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 607FACF11AFB9204008FA782 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 09417F1351C21E0DCE8667BE /* Pods-ImageSlideshow_Example.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = 5VWB99DS38; - INFOPLIST_FILE = ImageSlideshow/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MODULE_NAME = ExampleApp; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 607FACF31AFB9204008FA782 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7766BA4B267A696E6406BE86 /* Pods-ImageSlideshow_Tests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - DEVELOPMENT_TEAM = 5VWB99DS38; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ImageSlideshow_Example.app/ImageSlideshow_Example"; - }; - name = Debug; - }; - 607FACF41AFB9204008FA782 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = AFF019CC2ABD57129CAD4420 /* Pods-ImageSlideshow_Tests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - DEVELOPMENT_TEAM = 5VWB99DS38; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ImageSlideshow_Example.app/ImageSlideshow_Example"; - }; - name = Release; - }; - D0E8A9E71D97EB6D007EC517 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CODE_SIGN_IDENTITY = ""; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 9X4J83EL7M; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - INFOPLIST_FILE = ImageSlideshow_framework/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; - PRODUCT_BUNDLE_IDENTIFIER = "io.zvo.ImageSlideshow-framework"; - PRODUCT_NAME = ImageSlideshow; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - D0E8A9E81D97EB6D007EC517 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CODE_SIGN_IDENTITY = ""; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 9X4J83EL7M; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - INFOPLIST_FILE = ImageSlideshow_framework/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; - PRODUCT_BUNDLE_IDENTIFIER = "io.zvo.ImageSlideshow-framework"; - PRODUCT_NAME = ImageSlideshow; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "ImageSlideshow" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 607FACED1AFB9204008FA782 /* Debug */, - 607FACEE1AFB9204008FA782 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "ImageSlideshow_Example" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 607FACF01AFB9204008FA782 /* Debug */, - 607FACF11AFB9204008FA782 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "ImageSlideshow_Tests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 607FACF31AFB9204008FA782 /* Debug */, - 607FACF41AFB9204008FA782 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - D0E8A9E91D97EB6D007EC517 /* Build configuration list for PBXNativeTarget "ImageSlideshow_framework" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - D0E8A9E71D97EB6D007EC517 /* Debug */, - D0E8A9E81D97EB6D007EC517 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 607FACC81AFB9204008FA782 /* Project object */; -} diff --git a/Example/ImageSlideshow.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Example/ImageSlideshow.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index c5192855..00000000 --- a/Example/ImageSlideshow.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow-Example.xcscheme b/Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow-Example.xcscheme deleted file mode 100644 index b276b69e..00000000 --- a/Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow-Example.xcscheme +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow_framework.xcscheme b/Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow_framework.xcscheme deleted file mode 100644 index cb379e17..00000000 --- a/Example/ImageSlideshow.xcodeproj/xcshareddata/xcschemes/ImageSlideshow_framework.xcscheme +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/project.yml b/Example/project.yml new file mode 100644 index 00000000..c1699217 --- /dev/null +++ b/Example/project.yml @@ -0,0 +1,87 @@ +# XcodeGen manifest for the example project. +# +# The generated ImageSlideshow.xcodeproj/ is gitignored. +# Regenerate locally with: +# xcodegen generate && pod install +# (pod install is required after generation — XcodeGen wipes the CocoaPods integration.) +# CI runs the same two commands before building. +name: ImageSlideshow +options: + deploymentTarget: + iOS: "15.0" + +settings: + base: + SWIFT_VERSION: "5.0" + # CocoaPods script phases write into the build dir + ENABLE_USER_SCRIPT_SANDBOXING: NO + +targets: + ImageSlideshow_Example: + type: application + platform: iOS + sources: + - ImageSlideshow + settings: + base: + INFOPLIST_FILE: ImageSlideshow/Info.plist + PRODUCT_BUNDLE_IDENTIFIER: "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)" + DEVELOPMENT_TEAM: 5VWB99DS38 + ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon + + ImageSlideshow_Tests: + type: bundle.unit-test + platform: iOS + sources: + - Tests + dependencies: + - target: ImageSlideshow_Example + settings: + base: + INFOPLIST_FILE: Tests/Info.plist + PRODUCT_BUNDLE_IDENTIFIER: "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)" + DEVELOPMENT_TEAM: 5VWB99DS38 + + ImageSlideshow_framework: + type: framework + platform: iOS + sources: + - path: ../ImageSlideshow/Classes/Core + - path: ImageSlideshow_framework + - path: ../ImageSlideshow/Assets/ic_cross_white@2x.png + buildPhase: resources + - path: ../ImageSlideshow/Assets/ic_cross_white@3x.png + buildPhase: resources + settings: + base: + PRODUCT_NAME: ImageSlideshow + PRODUCT_BUNDLE_IDENTIFIER: io.zvo.ImageSlideshow-framework + INFOPLIST_FILE: ImageSlideshow_framework/Info.plist + DEVELOPMENT_TEAM: 9X4J83EL7M + DEFINES_MODULE: YES + SKIP_INSTALL: YES + CURRENT_PROJECT_VERSION: 1 + VERSIONING_SYSTEM: apple-generic + +schemes: + ImageSlideshow-Example: + build: + targets: + ImageSlideshow_Example: all + run: + config: Debug + test: + config: Debug + targets: + - ImageSlideshow_Tests + profile: + config: Release + archive: + config: Release + + ImageSlideshow_framework: + build: + targets: + ImageSlideshow_framework: all + run: + config: Debug From 970cda39c14f1198ea0a153c0722786ff40a380b Mon Sep 17 00:00:00 2001 From: Erwan Masson Date: Sat, 13 Jun 2026 15:16:45 -0400 Subject: [PATCH 17/17] Remove ImageSlideshow_framework target from the example project The framework target produced ImageSlideshow.framework with only Core sources, which shadowed the CocoaPods pod (that also includes the input sources) via xcodebuild implicit dependency resolution. The example app gets the framework from CocoaPods; the standalone target was a legacy artefact and is not needed. Co-Authored-By: Claude Sonnet 4.6 --- Example/project.yml | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/Example/project.yml b/Example/project.yml index c1699217..14ba9d41 100644 --- a/Example/project.yml +++ b/Example/project.yml @@ -42,27 +42,6 @@ targets: PRODUCT_BUNDLE_IDENTIFIER: "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)" DEVELOPMENT_TEAM: 5VWB99DS38 - ImageSlideshow_framework: - type: framework - platform: iOS - sources: - - path: ../ImageSlideshow/Classes/Core - - path: ImageSlideshow_framework - - path: ../ImageSlideshow/Assets/ic_cross_white@2x.png - buildPhase: resources - - path: ../ImageSlideshow/Assets/ic_cross_white@3x.png - buildPhase: resources - settings: - base: - PRODUCT_NAME: ImageSlideshow - PRODUCT_BUNDLE_IDENTIFIER: io.zvo.ImageSlideshow-framework - INFOPLIST_FILE: ImageSlideshow_framework/Info.plist - DEVELOPMENT_TEAM: 9X4J83EL7M - DEFINES_MODULE: YES - SKIP_INSTALL: YES - CURRENT_PROJECT_VERSION: 1 - VERSIONING_SYSTEM: apple-generic - schemes: ImageSlideshow-Example: build: @@ -78,10 +57,3 @@ schemes: config: Release archive: config: Release - - ImageSlideshow_framework: - build: - targets: - ImageSlideshow_framework: all - run: - config: Debug