From e6d5f0f1669184a596edfa268562963fee3933de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AF=92=E6=B1=9F=E5=AD=A4=E5=BD=B1?= Date: Thu, 13 Aug 2026 15:01:27 +0800 Subject: [PATCH 1/8] =?UTF-8?q?chore:=20=E7=A7=BB=E9=99=A4=20Bool=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=A3=80=E6=9F=A5=E8=A7=84=E5=88=99=E5=B9=B6?= =?UTF-8?q?=E7=AE=80=E5=8C=96=E6=8C=87=E7=A4=BA=E5=99=A8=E5=81=8F=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .swiftlint.yml | 9 --------- Sources/STBaseView/STBaseView.swift | 4 ++-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 0aec900..0c07674 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -133,13 +133,4 @@ custom_rules: - "Sources/STMarkdown/Resources/.*" - "Sources/STNetwork/STWebSocket.swift" # DEBUG-only 日志封装层,等同 STLog 豁免 - # Apple 并未禁止 Bool 参数;这里只提示检查调用点是否清晰。 - # 若 true/false 语义由参数标签即可明确,或遵循系统 API 形态,可局部豁免; - # 只有参数代表可能扩展的模式选择时,才优先改为 enum。 - st_avoid_bool_flag_param: - name: "Review Bool flag parameter clarity" - regex: '\b(? Date: Thu, 13 Aug 2026 15:06:11 +0800 Subject: [PATCH 2/8] =?UTF-8?q?refactor:=20=E7=AE=80=E5=8C=96=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E8=BD=ACData=E5=86=99=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/STHUD/STHUD.swift | 2 +- Sources/STNetwork/STHTTPSession.swift | 16 ++++++++-------- Sources/STNetwork/STRequest.swift | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/STHUD/STHUD.swift b/Sources/STHUD/STHUD.swift index 63300f9..a439205 100644 --- a/Sources/STHUD/STHUD.swift +++ b/Sources/STHUD/STHUD.swift @@ -266,7 +266,7 @@ public class STHUD: NSObject { defer { self.theme = previousTheme } let finalTitle = config.isLocalized ? config.title.localized : config.title - let finalDetailText = config.detailText != nil ? (config.isLocalized ? config.detailText!.localized : config.detailText!) : nil + let finalDetailText = config.detailText.map { config.isLocalized ? $0.localized : $0 } let keyWindow = UIApplication.shared.connectedScenes .compactMap { $0 as? UIWindowScene } .first?.windows.first(where: \.isKeyWindow) diff --git a/Sources/STNetwork/STHTTPSession.swift b/Sources/STNetwork/STHTTPSession.swift index 2322c0a..abe4eaa 100644 --- a/Sources/STNetwork/STHTTPSession.swift +++ b/Sources/STNetwork/STHTTPSession.swift @@ -612,22 +612,22 @@ open class STHTTPSession: NSObject { private func buildMultipartBody(boundary: String, files: [STUploadFile], parameters: [String: Any]?) -> Data { var body = Data() - let crlf = "\r\n".data(using: .utf8)! + let crlf = Data("\r\n".utf8) for file in files { - body.append("--\(boundary)\r\n".data(using: .utf8)!) - body.append("Content-Disposition: form-data; name=\"\(file.name)\"; filename=\"\(file.fileName)\"\r\n".data(using: .utf8)!) - body.append("Content-Type: \(file.mimeType)\r\n\r\n".data(using: .utf8)!) + body.append(Data("--\(boundary)\r\n".utf8)) + body.append(Data("Content-Disposition: form-data; name=\"\(file.name)\"; filename=\"\(file.fileName)\"\r\n".utf8)) + body.append(Data("Content-Type: \(file.mimeType)\r\n\r\n".utf8)) body.append(file.data) body.append(crlf) } if let parameters = parameters { for (key, value) in parameters { - body.append("--\(boundary)\r\n".data(using: .utf8)!) - body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!) - body.append("\(value)\r\n".data(using: .utf8)!) + body.append(Data("--\(boundary)\r\n".utf8)) + body.append(Data("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".utf8)) + body.append(Data("\(value)\r\n".utf8)) } } - body.append("--\(boundary)--\r\n".data(using: .utf8)!) + body.append(Data("--\(boundary)--\r\n".utf8)) return body } diff --git a/Sources/STNetwork/STRequest.swift b/Sources/STNetwork/STRequest.swift index 500c2b0..3e21e7b 100644 --- a/Sources/STNetwork/STRequest.swift +++ b/Sources/STNetwork/STRequest.swift @@ -348,8 +348,8 @@ enum STSSEParser { static func parse(buffer: inout Data) -> [STServerSentEvent] { var events: [STServerSentEvent] = [] - let lf = "\n\n".data(using: .utf8)! - let crlf = "\r\n\r\n".data(using: .utf8)! + let lf = Data("\n\n".utf8) + let crlf = Data("\r\n\r\n".utf8) while true { let a = buffer.range(of: lf) let b = buffer.range(of: crlf) From e686e86f10a05b7587aa54c1af2157d6d4ea624b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AF=92=E6=B1=9F=E5=AD=A4=E5=BD=B1?= Date: Thu, 13 Aug 2026 15:09:30 +0800 Subject: [PATCH 3/8] =?UTF-8?q?docs:=20=E4=BF=AE=E6=AD=A3=20README=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E4=BE=9D=E8=B5=96=E7=89=88=E6=9C=AC=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 002c902..cbb4ecc 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ STBaseProject 是整包发布的库(SPM 单一 product),引入即包含全 ```swift dependencies: [ - .package(url: "https://github.com/i-stack/STBaseProject.git", from: "1.5.0") + .package(url: "https://github.com/i-stack/STBaseProject.git", from: "1.3.0") ], targets: [ .target( From a558d59bd7228b9de4a98a3f0ef924db35101465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AF=92=E6=B1=9F=E5=AD=A4=E5=BD=B1?= Date: Thu, 13 Aug 2026 15:14:55 +0800 Subject: [PATCH 4/8] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E5=BC=BA?= =?UTF-8?q?=E5=88=B6=E8=A7=A3=E5=8C=85=E5=92=8C=E6=97=A5=E5=BF=97=E8=BE=93?= =?UTF-8?q?=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用可选绑定替换强制解包,提升安全性 - 将 print 替换为 STLog 统一日志输出 - 简化字典编码遍历逻辑 --- Sources/STBaseView/STBaseView.swift | 18 +++++++++++------- Sources/STConfig/STOrientationManager.swift | 2 +- .../STLocalizable/STLocalizationManager.swift | 4 ++-- Sources/STNetwork/STHTTPSession.swift | 3 +-- Sources/STTimer/STTimeProfiler.swift | 4 ++-- .../STUIKit/STTabBar/STTabBarItemModel.swift | 2 +- .../STUIKit/STTextView/STShimmerTextView.swift | 4 ++-- 7 files changed, 20 insertions(+), 17 deletions(-) diff --git a/Sources/STBaseView/STBaseView.swift b/Sources/STBaseView/STBaseView.swift index a648235..9b11c66 100644 --- a/Sources/STBaseView/STBaseView.swift +++ b/Sources/STBaseView/STBaseView.swift @@ -489,19 +489,23 @@ open class STBaseView: UIView { /// table 模式内部使用的 UITableView;外部通过 st_getTableView() 访问。 private var tableView: UITableView { - if _tableView == nil { - _tableView = self.makeTableView(self.tableViewStyle) - _isInternallyCreatedTableView = true + if let tableView = _tableView { + return tableView } - return _tableView! + let tableView = self.makeTableView(self.tableViewStyle) + _tableView = tableView + _isInternallyCreatedTableView = true + return tableView } /// collection 模式内部使用的 UICollectionView;外部通过 st_getCollectionView() 访问。 private var collectionView: UICollectionView { - if _collectionView == nil { - _collectionView = self.makeCollectionView() + if let collectionView = _collectionView { + return collectionView } - return _collectionView! + let collectionView = self.makeCollectionView() + _collectionView = collectionView + return collectionView } private static func makeDefaultScrollView() -> UIScrollView { diff --git a/Sources/STConfig/STOrientationManager.swift b/Sources/STConfig/STOrientationManager.swift index 6e617d9..8c767ee 100644 --- a/Sources/STConfig/STOrientationManager.swift +++ b/Sources/STConfig/STOrientationManager.swift @@ -35,7 +35,7 @@ public final class STOrientationManager { let targetWindowScene = windowScene ?? self.activeWindowScene() if #available(iOS 16.0, *), let targetWindowScene { targetWindowScene.requestGeometryUpdate(.iOS(interfaceOrientations: orientations)) { error in - print("[STOrientationManager] requestGeometryUpdate failed: \(error.localizedDescription)") + STLog("[STOrientationManager] requestGeometryUpdate failed: \(error.localizedDescription)") } } else { UIDevice.current.setValue(self.preferredOrientation(for: orientations).rawValue, forKey: "orientation") diff --git a/Sources/STLocalizable/STLocalizationManager.swift b/Sources/STLocalizable/STLocalizationManager.swift index 77a8cc7..ec8fad7 100644 --- a/Sources/STLocalizable/STLocalizationManager.swift +++ b/Sources/STLocalizable/STLocalizationManager.swift @@ -40,7 +40,7 @@ public struct STSupportedLanguage { .map { STSupportedLanguage(languageCode: String($0.dropLast(6))) } .sorted { $0.displayName < $1.displayName } } catch { - print("⚠️ STLocalizationManager: 无法读取语言列表: \(error)") + STLog("⚠️ STLocalizationManager: 无法读取语言列表: \(error)") return [] } } @@ -95,7 +95,7 @@ public extension Bundle { static func st_setCustomLanguage(_ languageCode: String) { guard let path = Bundle.main.path(forResource: languageCode, ofType: "lproj"), let bundle = Bundle(path: path) else { - print("⚠️ STLocalizationManager: 未找到语言包 \(languageCode)") + STLog("⚠️ STLocalizationManager: 未找到语言包 \(languageCode)") return } customLanguageBundle = bundle diff --git a/Sources/STNetwork/STHTTPSession.swift b/Sources/STNetwork/STHTTPSession.swift index abe4eaa..70b9c18 100644 --- a/Sources/STNetwork/STHTTPSession.swift +++ b/Sources/STNetwork/STHTTPSession.swift @@ -21,8 +21,7 @@ public final class STParameterEncoder { public static func st_encodeURL(_ parameters: [String: Any]) -> String { var components: [(String, String)] = [] - for key in parameters.keys.sorted(by: <) { - let value = parameters[key]! + for (key, value) in parameters.sorted(by: { $0.key < $1.key }) { components += st_queryComponents(fromKey: key, value: value) } return components.map { "\($0)=\($1)" }.joined(separator: "&") diff --git a/Sources/STTimer/STTimeProfiler.swift b/Sources/STTimer/STTimeProfiler.swift index 673a644..34367e7 100644 --- a/Sources/STTimer/STTimeProfiler.swift +++ b/Sources/STTimer/STTimeProfiler.swift @@ -37,7 +37,7 @@ public class STTimeProfiler { let endTime = CACurrentMediaTime() let duration = endTime - startTime self.startTimes.removeValue(forKey: tag) - let messageText = message != nil ? " - \(message!)" : "" + let messageText = message.map { " - \($0)" } ?? "" let durationText = self.st_formatDuration(duration) STLog("✅ [\(tag)] 耗时: \(durationText)\(messageText)") } @@ -64,7 +64,7 @@ public class STTimeProfiler { STLog("⚠️ [\(tag)] 未找到对应的开始时间,请先调用 st_start(tag:)") return } - let messageText = message != nil ? " - \(message!)" : "" + let messageText = message.map { " - \($0)" } ?? "" let durationText = self.st_formatDuration(elapsed) STLog("⏳ [\(tag)] 当前耗时: \(durationText)\(messageText)") } diff --git a/Sources/STUIKit/STTabBar/STTabBarItemModel.swift b/Sources/STUIKit/STTabBar/STTabBarItemModel.swift index 9a62a22..938140c 100644 --- a/Sources/STUIKit/STTabBar/STTabBarItemModel.swift +++ b/Sources/STUIKit/STTabBar/STTabBarItemModel.swift @@ -339,7 +339,7 @@ public struct STTabBarItemModel { private static func loadImage(named imageName: String, imageSize: CGSize? = nil) -> UIImage? { guard let image = UIImage(named: imageName) else { - print("⚠️ STTabBarItemModel: 图片加载失败 - \(imageName)") + STLog("⚠️ STTabBarItemModel: 图片加载失败 - \(imageName)") return nil } return image.withRenderingMode(.alwaysOriginal) diff --git a/Sources/STUIKit/STTextView/STShimmerTextView.swift b/Sources/STUIKit/STTextView/STShimmerTextView.swift index 6f6b573..93121f5 100644 --- a/Sources/STUIKit/STTextView/STShimmerTextView.swift +++ b/Sources/STUIKit/STTextView/STShimmerTextView.swift @@ -372,8 +372,8 @@ open class STShimmerTextView: UITextView { private func appendStaggeredTokens(for colorRuns: [AnimatingColorRun]) { let revealRuns = self.semanticRevealColorRuns(from: colorRuns) guard !revealRuns.isEmpty else { return } - let start = revealRuns.map(\.range.location).min()! - let end = revealRuns.map { $0.range.location + $0.range.length }.max()! + guard let start = revealRuns.map(\.range.location).min(), + let end = revealRuns.map({ $0.range.location + $0.range.length }).max() else { return } let stagger = (self.characterStaggerInterval > 0 && revealRuns.count > 1) ? self.characterStaggerInterval : 0 let token = AnimatingToken( From 2f5595f75540a4a9f67ff02138fac62452eb6dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AF=92=E6=B1=9F=E5=AD=A4=E5=BD=B1?= Date: Thu, 13 Aug 2026 15:22:29 +0800 Subject: [PATCH 5/8] =?UTF-8?q?style:=20=E7=BB=9F=E4=B8=80=20Swift=20?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=A3=8E=E6=A0=BC=E4=B8=8E=E4=BF=AE=E9=A5=B0?= =?UTF-8?q?=E7=AC=A6=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../STShimmerCursorView.swift | 2 +- .../STShimmerRendererView.swift | 6 +- Sources/STBaseModel/STBaseModel.swift | 18 +-- Sources/STBaseView/STBaseView.swift | 22 ++-- Sources/STBaseView/STRefreshControl.swift | 8 +- .../STBaseViewController.swift | 12 +- Sources/STBaseViewModel/STBaseViewModel.swift | 8 +- Sources/STConfig/STAppearanceManager.swift | 2 +- Sources/STConfig/STBaseConfig.swift | 2 +- Sources/STHUD/STAlertController.swift | 110 ++++++++---------- Sources/STHUD/STHUD.swift | 12 +- Sources/STHUD/STProgressHUD.swift | 12 +- Sources/STHUD/STProgressView.swift | 2 +- .../STLocalizable/STLocalizationManager.swift | 2 +- .../STViewControllerLocalization.swift | 1 - Sources/STMedia/STImage.swift | 3 +- Sources/STMedia/STScanView.swift | 26 ++--- Sources/STNetwork/STHTTPSession.swift | 6 +- .../STNetwork/STHostnameReachability.swift | 2 +- Sources/STNetwork/STNetworkMonitoring.swift | 2 +- Sources/STNetwork/STSSLPinningConfig.swift | 2 +- Sources/STNetwork/STWebSocket.swift | 4 +- Sources/STNetwork/STWebSocketTypes.swift | 2 +- Sources/STSecurity/STAntiDebugMonitor.swift | 2 +- Sources/STSecurity/STCryptoService.swift | 2 +- Sources/STSecurity/STEncrypt.swift | 6 +- Sources/STSecurity/STKeychainHelper.swift | 4 +- Sources/STSecurity/STSecurityConfig.swift | 4 +- Sources/STTools/STColor.swift | 2 +- Sources/STTools/STDate.swift | 2 +- Sources/STTools/STDeviceInfo.swift | 2 +- Sources/STTools/STScrollPerfDiagnostics.swift | 1 - Sources/STTools/UIView+FontRefresh.swift | 2 +- .../STBottomSheetViewController.swift | 20 ++-- Sources/STUIKit/STButton/STBtn.swift | 14 +-- Sources/STUIKit/STButton/STIconBtn.swift | 4 +- .../STButton/STVerificationCodeBtn.swift | 14 +-- .../STGlassCardView/STGlassCardView.swift | 16 +-- Sources/STUIKit/STLabel/STLabel.swift | 12 +- Sources/STUIKit/STLabel/STShimmerLabel.swift | 14 +-- Sources/STUIKit/STLog/STLogFileWriter.swift | 2 +- Sources/STUIKit/STLog/STLogView.swift | 6 +- Sources/STUIKit/STTabBar/STCustomTabBar.swift | 6 +- .../STTabBar/STCustomTabBarController.swift | 12 +- .../STUIKit/STTabBar/STTabBarItemView.swift | 6 +- Sources/STUIKit/STTextField/STTextField.swift | 40 +++---- .../STTextView/STPlaceholderTextView.swift | 16 +-- .../STTextView/STShimmerTextView.swift | 16 +-- Sources/STUIKit/STTextView/STTextView.swift | 30 ++--- Sources/STUIKit/STView/STIBInspectable.swift | 2 +- .../STUIKit/STView/STLiquidGlassView.swift | 6 +- Sources/STUIKit/STView/STView.swift | 4 +- .../STWebView/STBaseWKViewController.swift | 17 +-- 53 files changed, 268 insertions(+), 282 deletions(-) diff --git a/Sources/STAnimation/STShimmerAnimation/STShimmerCursorView.swift b/Sources/STAnimation/STShimmerAnimation/STShimmerCursorView.swift index 5f32264..ce7a678 100644 --- a/Sources/STAnimation/STShimmerAnimation/STShimmerCursorView.swift +++ b/Sources/STAnimation/STShimmerAnimation/STShimmerCursorView.swift @@ -11,7 +11,7 @@ public final class STShimmerCursorView: UIView { private var blinkAnimation: CABasicAnimation? - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) self.backgroundColor = .label self.layer.cornerRadius = 1 diff --git a/Sources/STAnimation/STShimmerAnimation/STShimmerRendererView.swift b/Sources/STAnimation/STShimmerAnimation/STShimmerRendererView.swift index 45185a3..11f4bd4 100644 --- a/Sources/STAnimation/STShimmerAnimation/STShimmerRendererView.swift +++ b/Sources/STAnimation/STShimmerAnimation/STShimmerRendererView.swift @@ -15,7 +15,7 @@ public class STShimmerRendererView: UIView { private var lastHeight: CGFloat = 0 private let cursor = STShimmerCursorView() - private let renderer: STShimmerTextView = STShimmerTextView(usingTextLayoutManager: false) + private let renderer = STShimmerTextView(usingTextLayoutManager: false) private let controller = STShimmerController() weak var delegate: STShimmerRendererViewDelegate? @@ -53,12 +53,12 @@ public class STShimmerRendererView: UIView { self.setup() } - public override func layoutSubviews() { + override public func layoutSubviews() { super.layoutSubviews() self.updateCursor() } - public override var intrinsicContentSize: CGSize { + override public var intrinsicContentSize: CGSize { let size = self.renderer.sizeThatFits( CGSize(width: self.bounds.width, height: .greatestFiniteMagnitude) ) diff --git a/Sources/STBaseModel/STBaseModel.swift b/Sources/STBaseModel/STBaseModel.swift index e6ba4ca..424f43f 100644 --- a/Sources/STBaseModel/STBaseModel.swift +++ b/Sources/STBaseModel/STBaseModel.swift @@ -42,7 +42,7 @@ open class STBaseModel: NSObject { STLog("dealloc: \(String(describing: type(of: self)))", level: .debug) } - public required override init() { + override public required init() { super.init() } @@ -72,16 +72,16 @@ open class STBaseModel: NSObject { self.st_update(from: dictionary) } - open override func value(forUndefinedKey key: String) -> Any? { + override open func value(forUndefinedKey key: String) -> Any? { STLog("Key = \(key) isValueForUndefinedKey", level: .warning) return nil } - open override class func setValue(_ value: Any?, forUndefinedKey key: String) { + override open class func setValue(_ value: Any?, forUndefinedKey key: String) { STLog("Key = \(key) isUndefinedKey", level: .warning) } - open override func setValue(_ value: Any?, forUndefinedKey key: String) { + override open func setValue(_ value: Any?, forUndefinedKey key: String) { STLog("Key = \(key) isUndefinedKey", level: .warning) } @@ -492,7 +492,7 @@ open class STBaseModel: NSObject { } } - open override var description: String { + override open var description: String { if self.st_isFlexibleMode { let className = String(describing: type(of: self)) let keys = self.st_getAllKeys() @@ -518,7 +518,7 @@ open class STBaseModel: NSObject { } /// 模型调试描述 - open override var debugDescription: String { + override open var debugDescription: String { return description } @@ -586,13 +586,13 @@ open class STBaseModel: NSObject { } } - open override func isEqual(_ object: Any?) -> Bool { + override open func isEqual(_ object: Any?) -> Bool { guard let other = object as? STBaseModel else { return false } guard type(of: self) == type(of: other) else { return false } return self.normalizedDictionary().isEqual(other.normalizedDictionary()) } - open override var hash: Int { + override open var hash: Int { return self.normalizedDictionary().hash } @@ -691,7 +691,7 @@ public struct STCodingKeys: CodingKey { // MARK: - 属性类型解析(用于 KVC 类型安全写入) /// 由 `property_getAttributes` 解析出的、与 KVC 写入兼容性相关的属性类型描述。 -fileprivate struct STPropertyType { +private struct STPropertyType { enum Kind { case object(className: String?) // @"NSString" / @"NSArray<...>" / @ (id) case block // @? diff --git a/Sources/STBaseView/STBaseView.swift b/Sources/STBaseView/STBaseView.swift index 9b11c66..82d8ab1 100644 --- a/Sources/STBaseView/STBaseView.swift +++ b/Sources/STBaseView/STBaseView.swift @@ -5,8 +5,8 @@ // Created by 寒江孤影 on 2018/3/14. // -import UIKit import Combine +import UIKit /// 用于 objc_setAssociatedObject 的引用型 key,避免对可变 static var 取地址造成的未定义行为。 private final class STAssociationKey {} @@ -76,7 +76,7 @@ open class STBaseView: UIView { } } - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) self.setupBase() } @@ -88,7 +88,7 @@ open class STBaseView: UIView { self.setupBase() } - required public init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) self.setupBase() } @@ -319,7 +319,7 @@ open class STBaseView: UIView { } } - open override func safeAreaInsetsDidChange() { + override open func safeAreaInsetsDidChange() { super.safeAreaInsetsDidChange() switch self.layoutMode { case .table: @@ -335,7 +335,7 @@ open class STBaseView: UIView { } } - open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + override open func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) guard self.enableAppearanceManagement else { return } let previousStyle = previousTraitCollection?.userInterfaceStyle ?? .unspecified @@ -653,7 +653,7 @@ open class STSection: UIView { self.setupStackView() } - required public init?(coder: NSCoder) { + public required init?(coder: NSCoder) { self.inset = .zero self.spacing = 0 self.stackView = UIStackView() @@ -864,11 +864,11 @@ open class STGradientNavigationBar: UIView { private let gradientLayer = CAGradientLayer() - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) self.setupGradient() } - required public init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) self.setupGradient() } @@ -884,16 +884,16 @@ open class STGradientNavigationBar: UIView { self.gradientLayer.colors = [self.startColor.cgColor, self.endColor.cgColor] } - public override func layoutSubviews() { + override public func layoutSubviews() { super.layoutSubviews() self.gradientLayer.frame = self.bounds } - public override var intrinsicContentSize: CGSize { + override public var intrinsicContentSize: CGSize { return CGSize(width: UIView.noIntrinsicMetric, height: self.height) } - open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + override open func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if self.traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) { self.updateGradientColors() diff --git a/Sources/STBaseView/STRefreshControl.swift b/Sources/STBaseView/STRefreshControl.swift index bedfdf1..f0ac705 100644 --- a/Sources/STBaseView/STRefreshControl.swift +++ b/Sources/STBaseView/STRefreshControl.swift @@ -125,7 +125,7 @@ public final class STRefreshHeaderView: UIView { self.beginRefreshing(scrollView: sv) } - public override func layoutSubviews() { + override public func layoutSubviews() { super.layoutSubviews() let cx = bounds.midX let cy = bounds.midY @@ -347,7 +347,7 @@ public final class STRefreshHeaderView: UIView { self.customImageView.layer.add(anim, forKey: "st_rotation") } - public override func willMove(toSuperview newSuperview: UIView?) { + override public func willMove(toSuperview newSuperview: UIView?) { super.willMove(toSuperview: newSuperview) if newSuperview == nil { self.customImageView.layer.removeAnimation(forKey: "st_rotation") @@ -475,7 +475,7 @@ public final class STLoadMoreFooterView: UIView { } } - public override func layoutSubviews() { + override public func layoutSubviews() { super.layoutSubviews() let cx = bounds.midX let cy = bounds.midY @@ -621,7 +621,7 @@ public final class STLoadMoreFooterView: UIView { self.customImageView.layer.add(anim, forKey: "st_rotation") } - public override func willMove(toSuperview newSuperview: UIView?) { + override public func willMove(toSuperview newSuperview: UIView?) { super.willMove(toSuperview: newSuperview) if newSuperview == nil { self.customImageView.layer.removeAnimation(forKey: "st_rotation") diff --git a/Sources/STBaseViewController/STBaseViewController.swift b/Sources/STBaseViewController/STBaseViewController.swift index 1d4bef0..da3bd71 100644 --- a/Sources/STBaseViewController/STBaseViewController.swift +++ b/Sources/STBaseViewController/STBaseViewController.swift @@ -121,7 +121,7 @@ open class STBaseViewController: UIViewController { } } - open override func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() self.setupNavigationBar() self.setupAppearanceObservation() @@ -130,7 +130,7 @@ open class STBaseViewController: UIViewController { self.st_updateLocalizedTexts() } - open override func viewWillAppear(_ animated: Bool) { + override open func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if let nav = self.navigationController, nav.isNavigationBarHidden != self.prefersSystemNavigationBarHidden { @@ -138,7 +138,7 @@ open class STBaseViewController: UIViewController { } } - open override func viewDidLayoutSubviews() { + override open func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if self.view.subviews.last !== self.navigationBarView { self.view.bringSubviewToFront(self.navigationBarView) @@ -316,7 +316,7 @@ open class STBaseViewController: UIViewController { /// 外观变化回调,子类重写以自定义颜色处理逻辑 open func st_appearanceDidChange(resolvedStyle: UIUserInterfaceStyle) {} - open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + override open func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) guard STAppearanceManager.shared.currentMode == .system else { return } @@ -487,8 +487,8 @@ open class STBaseViewController: UIViewController { @objc open func onRightBtnTap() {} - open override var preferredStatusBarStyle: UIStatusBarStyle { self.statusBarStyle } - open override var prefersStatusBarHidden: Bool { self.statusBarHidden } + override open var preferredStatusBarStyle: UIStatusBarStyle { self.statusBarStyle } + override open var prefersStatusBarHidden: Bool { self.statusBarHidden } } extension STBaseViewController { diff --git a/Sources/STBaseViewModel/STBaseViewModel.swift b/Sources/STBaseViewModel/STBaseViewModel.swift index d46f76f..47aa900 100644 --- a/Sources/STBaseViewModel/STBaseViewModel.swift +++ b/Sources/STBaseViewModel/STBaseViewModel.swift @@ -5,10 +5,10 @@ // Created by 寒江孤影 on 2018/3/14. // -import UIKit import Combine import CryptoKit import Foundation +import UIKit // MARK: - 错误类型枚举 public enum STBaseError: LocalizedError, Equatable { @@ -134,8 +134,8 @@ open class STBaseViewModel: NSObject { public var cacheConfig = STCacheConfig() public var httpSession: STHTTPSessionProviding = STHTTPSession.shared public var requestHeaders = STRequestHeaders() - public var jsonDecoder: JSONDecoder = JSONDecoder() - public var jsonEncoder: JSONEncoder = JSONEncoder() + public var jsonDecoder = JSONDecoder() + public var jsonEncoder = JSONEncoder() public private(set) var cancellables = Set() private let cache = NSCache() @@ -148,7 +148,7 @@ open class STBaseViewModel: NSObject { STLog("🌈 -> \(self) 🌈 ----> 🌈 dealloc") } - public override init() { + override public init() { super.init() self.st_setupBindings() } diff --git a/Sources/STConfig/STAppearanceManager.swift b/Sources/STConfig/STAppearanceManager.swift index 685ce2b..cf1abd5 100644 --- a/Sources/STConfig/STAppearanceManager.swift +++ b/Sources/STConfig/STAppearanceManager.swift @@ -5,8 +5,8 @@ // Created by 寒江孤影 on 2018/3/14. // -import UIKit import Combine +import UIKit /// SDK 统一的外观模式 public enum STAppearanceMode: Equatable { diff --git a/Sources/STConfig/STBaseConfig.swift b/Sources/STConfig/STBaseConfig.swift index 9ef21bf..18c7141 100644 --- a/Sources/STConfig/STBaseConfig.swift +++ b/Sources/STConfig/STBaseConfig.swift @@ -9,7 +9,7 @@ import UIKit public final class STBaseConfig { - public static let shared: STBaseConfig = STBaseConfig() + public static let shared = STBaseConfig() private init() {} diff --git a/Sources/STHUD/STAlertController.swift b/Sources/STHUD/STAlertController.swift index 6cb62ae..55d6b6f 100644 --- a/Sources/STHUD/STAlertController.swift +++ b/Sources/STHUD/STAlertController.swift @@ -13,7 +13,6 @@ public enum STAlertStyle: Int, @unchecked Sendable { } // MARK: - 点击动作后是否自动关闭 -/// Auto-dismiss toggle for tap actions. Prefer this over the legacy `Bool` setter for clearer call-sites. public enum STAlertAutoDismiss: Equatable { case enabled case disabled @@ -63,8 +62,8 @@ public enum STAlertBtnClickType { } public struct STAlertInfo { - var title: TextInfo = TextInfo() - var message: TextInfo = TextInfo() + var title = TextInfo() + var message = TextInfo() var style: STAlertStyle = .alert var buttonActions: [Action] = [] var buttonHandlers: [(Bool, String) -> Void] = [] @@ -93,8 +92,8 @@ open class STAlertController: UIViewController { private var isPresented: Bool = false private var newConstraint: NSLayoutConstraint! - private var backgroundColor: UIColor = UIColor.white - private var alertInfo: STAlertInfo = STAlertInfo() + private var backgroundColor = UIColor.white + private var alertInfo = STAlertInfo() private var actionItems: [STAlertActionItem] = [] private var autoDismissOnAction: Bool = true @@ -129,21 +128,17 @@ open class STAlertController: UIViewController { self.alertInfo = info } - open override func viewDidLoad() { - super.viewDidLoad() - } - - open override func viewWillAppear(_ animated: Bool) { + override open func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.modalPresentationStyle = .overFullScreen } - open override func viewDidAppear(_ animated: Bool) { + override open func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) self.isPresented = true } - open override func viewWillDisappear(_ animated: Bool) { + override open func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) self.isPresented = false } @@ -168,7 +163,6 @@ open class STAlertController: UIViewController { self.messageLabel.text = text } - /// 推荐的新接口:添加统一按钮模型 public func add(item: STAlertActionItem) { self.actionItems.append(item) @@ -239,19 +233,19 @@ open class STAlertController: UIViewController { private func configCustomAlertView() { self.view.addSubview(self.alertView) - self.newConstraint = NSLayoutConstraint.init(item: self.alertView, attribute: .height, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 180) + self.newConstraint = NSLayoutConstraint(item: self.alertView, attribute: .height, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 180) if self.alertInfo.style == .alert { self.view.addConstraints([ - NSLayoutConstraint.init(item: self.alertView, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.alertView, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.alertView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.alertWidth), + NSLayoutConstraint(item: self.alertView, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.alertView, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.alertView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.alertWidth), self.newConstraint ]) } else { self.view.addConstraints([ - NSLayoutConstraint.init(item: self.alertView, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.alertView, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.alertView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.alertWidth), + NSLayoutConstraint(item: self.alertView, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.alertView, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.alertView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.alertWidth), self.newConstraint ]) } @@ -262,30 +256,30 @@ open class STAlertController: UIViewController { self.alertView.addSubview(self.titleLabel) self.alertView.addSubview(self.messageLabel) self.view.addConstraints([ - NSLayoutConstraint.init(item: self.titleLabel, attribute: .top, relatedBy: .equal, toItem: self.alertView, attribute: .top, multiplier: 1, constant: STAlertLayoutConstant.contentTop), - NSLayoutConstraint.init(item: self.titleLabel, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: STAlertLayoutConstant.contentHorizontal), - NSLayoutConstraint.init(item: self.titleLabel, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: -STAlertLayoutConstant.contentHorizontal), + NSLayoutConstraint(item: self.titleLabel, attribute: .top, relatedBy: .equal, toItem: self.alertView, attribute: .top, multiplier: 1, constant: STAlertLayoutConstant.contentTop), + NSLayoutConstraint(item: self.titleLabel, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: STAlertLayoutConstant.contentHorizontal), + NSLayoutConstraint(item: self.titleLabel, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: -STAlertLayoutConstant.contentHorizontal) ]) self.view.addConstraints([ - NSLayoutConstraint.init(item: self.messageLabel, attribute: .top, relatedBy: .equal, toItem: self.titleLabel, attribute: .bottom, multiplier: 1, constant: STAlertLayoutConstant.titleMessageSpacing), - NSLayoutConstraint.init(item: self.messageLabel, attribute: .left, relatedBy: .equal, toItem: self.titleLabel, attribute: .left, multiplier: 1, constant: STAlertLayoutConstant.contentHorizontal), - NSLayoutConstraint.init(item: self.messageLabel, attribute: .right, relatedBy: .equal, toItem: self.titleLabel, attribute: .right, multiplier: 1, constant: -STAlertLayoutConstant.contentHorizontal), + NSLayoutConstraint(item: self.messageLabel, attribute: .top, relatedBy: .equal, toItem: self.titleLabel, attribute: .bottom, multiplier: 1, constant: STAlertLayoutConstant.titleMessageSpacing), + NSLayoutConstraint(item: self.messageLabel, attribute: .left, relatedBy: .equal, toItem: self.titleLabel, attribute: .left, multiplier: 1, constant: STAlertLayoutConstant.contentHorizontal), + NSLayoutConstraint(item: self.messageLabel, attribute: .right, relatedBy: .equal, toItem: self.titleLabel, attribute: .right, multiplier: 1, constant: -STAlertLayoutConstant.contentHorizontal) ]) } else if self.alertInfo.title.text != "" && self.alertInfo.message.text == "" { self.titleLabel.text = self.alertInfo.title.text self.alertView.addSubview(self.titleLabel) self.view.addConstraints([ - NSLayoutConstraint.init(item: self.titleLabel, attribute: .top, relatedBy: .equal, toItem: self.alertView, attribute: .top, multiplier: 1, constant: STAlertLayoutConstant.contentTop), - NSLayoutConstraint.init(item: self.titleLabel, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: STAlertLayoutConstant.contentHorizontal), - NSLayoutConstraint.init(item: self.titleLabel, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: -STAlertLayoutConstant.contentHorizontal), + NSLayoutConstraint(item: self.titleLabel, attribute: .top, relatedBy: .equal, toItem: self.alertView, attribute: .top, multiplier: 1, constant: STAlertLayoutConstant.contentTop), + NSLayoutConstraint(item: self.titleLabel, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: STAlertLayoutConstant.contentHorizontal), + NSLayoutConstraint(item: self.titleLabel, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: -STAlertLayoutConstant.contentHorizontal) ]) } else if self.alertInfo.title.text == "" && self.alertInfo.message.text != "" { self.messageLabel.text = self.alertInfo.message.text self.alertView.addSubview(self.messageLabel) self.view.addConstraints([ - NSLayoutConstraint.init(item: self.messageLabel, attribute: .top, relatedBy: .equal, toItem: self.alertView, attribute: .top, multiplier: 1, constant: STAlertLayoutConstant.contentTop), - NSLayoutConstraint.init(item: self.messageLabel, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: STAlertLayoutConstant.contentHorizontal), - NSLayoutConstraint.init(item: self.messageLabel, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: -STAlertLayoutConstant.contentHorizontal), + NSLayoutConstraint(item: self.messageLabel, attribute: .top, relatedBy: .equal, toItem: self.alertView, attribute: .top, multiplier: 1, constant: STAlertLayoutConstant.contentTop), + NSLayoutConstraint(item: self.messageLabel, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: STAlertLayoutConstant.contentHorizontal), + NSLayoutConstraint(item: self.messageLabel, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: -STAlertLayoutConstant.contentHorizontal) ]) } self.configAlertBtn() @@ -301,7 +295,7 @@ open class STAlertController: UIViewController { } return } - // 兼容旧逻辑 + if self.alertInfo.buttonHandlers.count == 1 { if let handler = self.alertInfo.buttonHandlers.first { handler(true, sender.titleLabel?.text ?? "") @@ -346,16 +340,16 @@ open class STAlertController: UIViewController { btn.addTarget(self, action: #selector(alertButtonClick), for: .touchUpInside) self.alertView.addSubview(btn) self.view.addConstraints([ - NSLayoutConstraint.init(item: self.lineImageH, attribute: .top, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: -STAlertLayoutConstant.buttonHeight), - NSLayoutConstraint.init(item: self.lineImageH, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.lineImageH, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.lineImageH, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.separatorHeight) + NSLayoutConstraint(item: self.lineImageH, attribute: .top, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: -STAlertLayoutConstant.buttonHeight), + NSLayoutConstraint(item: self.lineImageH, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.lineImageH, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.lineImageH, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.separatorHeight) ]) self.view.addConstraints([ - NSLayoutConstraint.init(item: btn, attribute: .top, relatedBy: .equal, toItem: self.lineImageH, attribute: .bottom, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: btn, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: btn, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: btn, attribute: .bottom, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: 0), + NSLayoutConstraint(item: btn, attribute: .top, relatedBy: .equal, toItem: self.lineImageH, attribute: .bottom, multiplier: 1, constant: 0), + NSLayoutConstraint(item: btn, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: 0), + NSLayoutConstraint(item: btn, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: 0), + NSLayoutConstraint(item: btn, attribute: .bottom, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: 0) ]) } else if count == 2 { self.alertView.addSubview(self.lineImageH) @@ -401,28 +395,28 @@ open class STAlertController: UIViewController { rightBtn.addTarget(self, action: #selector(alertButtonClick), for: .touchUpInside) self.alertView.addSubview(rightBtn) self.view.addConstraints([ - NSLayoutConstraint.init(item: self.lineImageH, attribute: .top, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: -STAlertLayoutConstant.buttonHeight), - NSLayoutConstraint.init(item: self.lineImageH, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.lineImageH, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.lineImageH, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.separatorHeight) + NSLayoutConstraint(item: self.lineImageH, attribute: .top, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: -STAlertLayoutConstant.buttonHeight), + NSLayoutConstraint(item: self.lineImageH, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.lineImageH, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.lineImageH, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.separatorHeight) ]) self.view.addConstraints([ - NSLayoutConstraint.init(item: self.lineImageV, attribute: .top, relatedBy: .equal, toItem: self.lineImageH, attribute: .top, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.lineImageV, attribute: .bottom, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.lineImageV, attribute: .centerX, relatedBy: .equal, toItem: self.alertView, attribute: .centerX, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.lineImageV, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.separatorHeight) + NSLayoutConstraint(item: self.lineImageV, attribute: .top, relatedBy: .equal, toItem: self.lineImageH, attribute: .top, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.lineImageV, attribute: .bottom, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.lineImageV, attribute: .centerX, relatedBy: .equal, toItem: self.alertView, attribute: .centerX, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.lineImageV, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.separatorHeight) ]) self.view.addConstraints([ - NSLayoutConstraint.init(item: leftBtn, attribute: .top, relatedBy: .equal, toItem: self.lineImageH, attribute: .top, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: leftBtn, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: leftBtn, attribute: .right, relatedBy: .equal, toItem: self.lineImageV, attribute: .left, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: leftBtn, attribute: .bottom, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: 0), + NSLayoutConstraint(item: leftBtn, attribute: .top, relatedBy: .equal, toItem: self.lineImageH, attribute: .top, multiplier: 1, constant: 0), + NSLayoutConstraint(item: leftBtn, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: 0), + NSLayoutConstraint(item: leftBtn, attribute: .right, relatedBy: .equal, toItem: self.lineImageV, attribute: .left, multiplier: 1, constant: 0), + NSLayoutConstraint(item: leftBtn, attribute: .bottom, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: 0) ]) self.view.addConstraints([ - NSLayoutConstraint.init(item: rightBtn, attribute: .top, relatedBy: .equal, toItem: self.lineImageH, attribute: .bottom, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: rightBtn, attribute: .left, relatedBy: .equal, toItem: self.lineImageV, attribute: .right, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: rightBtn, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: rightBtn, attribute: .bottom, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: 0), + NSLayoutConstraint(item: rightBtn, attribute: .top, relatedBy: .equal, toItem: self.lineImageH, attribute: .bottom, multiplier: 1, constant: 0), + NSLayoutConstraint(item: rightBtn, attribute: .left, relatedBy: .equal, toItem: self.lineImageV, attribute: .right, multiplier: 1, constant: 0), + NSLayoutConstraint(item: rightBtn, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: 0), + NSLayoutConstraint(item: rightBtn, attribute: .bottom, relatedBy: .equal, toItem: self.alertView, attribute: .bottom, multiplier: 1, constant: 0) ]) } self.view.layoutIfNeeded() @@ -511,7 +505,6 @@ open class STAlertController: UIViewController { // MARK: - 统一弹窗入口(系统 / 自定义) public extension STAlertController { - /// 显示系统弹窗(UIAlertController) static func st_showSystemAlert(on presenter: UIViewController, title: String?, message: String?, @@ -520,7 +513,6 @@ public extension STAlertController { let style: UIAlertController.Style = (preferredStyle == .actionSheet) ? .actionSheet : .alert let alert = UIAlertController(title: title, message: message, preferredStyle: style) - // 可选:设置富文本标题/消息 if let title = title, !title.isEmpty { let attributed = NSAttributedString(string: title, attributes: [ .font: UIFont.st_preferredFont(ofSize: 17, forTextStyle: .headline, weight: .medium) diff --git a/Sources/STHUD/STHUD.swift b/Sources/STHUD/STHUD.swift index a439205..f30368f 100644 --- a/Sources/STHUD/STHUD.swift +++ b/Sources/STHUD/STHUD.swift @@ -144,14 +144,14 @@ public struct STHUDConfig { public class STHUD: NSObject { fileprivate var progressHUD: STProgressHUD? - public var theme: STHUDTheme = STHUDTheme() - public static let sharedHUD: STHUD = STHUD() + public var theme = STHUDTheme() + public static let sharedHUD = STHUD() public var defaultIconPosition: STHUDIconPosition = .top - public var hudMode: STProgressHUD.HudMode = STProgressHUD.HudMode.customView + public var hudMode = STProgressHUD.HudMode.customView private var completionHandler: (() -> Void)? - private override init() { + override private init() { super.init() } @@ -274,7 +274,7 @@ public class STHUD: NSObject { if self.progressHUD?.superview != nil { self.progressHUD?.hide(animation: .fade) } - self.progressHUD = STProgressHUD.init(withView: window) + self.progressHUD = STProgressHUD(withView: window) self.configCommonProperty() if let hud = self.progressHUD { window.addSubview(hud) } } @@ -445,7 +445,7 @@ public class STHUD: NSObject { if self.progressHUD?.superview != nil { self.progressHUD?.hide(animation: .fade) } - self.progressHUD = STProgressHUD.init(withView: showInView) + self.progressHUD = STProgressHUD(withView: showInView) self.configCommonProperty() if let hud = self.progressHUD { showInView.addSubview(hud) } } diff --git a/Sources/STHUD/STProgressHUD.swift b/Sources/STHUD/STProgressHUD.swift index 96bac73..069ea90 100644 --- a/Sources/STHUD/STProgressHUD.swift +++ b/Sources/STHUD/STProgressHUD.swift @@ -5,9 +5,9 @@ // Created by 寒江孤影 on 2017/10/14. // -import UIKit -import Foundation import CoreGraphics +import Foundation +import UIKit public protocol STProgressHUDDelegate: AnyObject { func hudWasHidden(_ hud: STProgressHUD) @@ -286,7 +286,7 @@ public class STProgressHUD: UIView { self.hideDelayTimer = timer } - public override func updateConstraints() { + override public func updateConstraints() { let metrics: [String: Any] = ["margin": self.margin] var subviews: [UIView] = [self.topSpacer, self.label, self.detailsLabel, self.button, self.bottomSpacer] if let indicator = self.indicator { @@ -352,7 +352,7 @@ public class STProgressHUD: UIView { super.updateConstraints() } - public override func layoutSubviews() { + override public func layoutSubviews() { if !self.needsUpdateConstraints() { self.updatePaddingConstraints() } @@ -700,7 +700,7 @@ public class STProgressHUDBackgroundView: UIView { self.updateForBackgroundStyle() } - required public init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.isOpaque = false self.style = .blur @@ -709,7 +709,7 @@ public class STProgressHUDBackgroundView: UIView { self.updateForBackgroundStyle() } - public override var intrinsicContentSize: CGSize { .zero } + override public var intrinsicContentSize: CGSize { .zero } private func updateForBackgroundStyle() { if self.style == .liquidGlass { diff --git a/Sources/STHUD/STProgressView.swift b/Sources/STHUD/STProgressView.swift index d76dc9a..7754240 100644 --- a/Sources/STHUD/STProgressView.swift +++ b/Sources/STHUD/STProgressView.swift @@ -5,8 +5,8 @@ // Created by 寒江孤影 on 2017/10/14. // -import UIKit import CoreGraphics +import UIKit class STProgressView: UIView { var progress: Float = 0.0 { diff --git a/Sources/STLocalizable/STLocalizationManager.swift b/Sources/STLocalizable/STLocalizationManager.swift index ec8fad7..a9b63b8 100644 --- a/Sources/STLocalizable/STLocalizationManager.swift +++ b/Sources/STLocalizable/STLocalizationManager.swift @@ -56,7 +56,7 @@ private extension Bundle { static let st_installSwizzle: Void = { guard let original = class_getInstanceMethod(Bundle.self, #selector(Bundle.localizedString(forKey:value:table:))), - let patched = class_getInstanceMethod(Bundle.self, #selector(Bundle.st_patched_localizedString(forKey:value:table:))) + let patched = class_getInstanceMethod(Bundle.self, #selector(Bundle.st_patched_localizedString(forKey:value:table:))) else { return } method_exchangeImplementations(original, patched) }() diff --git a/Sources/STLocalizable/STViewControllerLocalization.swift b/Sources/STLocalizable/STViewControllerLocalization.swift index dfb53b6..c9e9ca1 100644 --- a/Sources/STLocalizable/STViewControllerLocalization.swift +++ b/Sources/STLocalizable/STViewControllerLocalization.swift @@ -61,4 +61,3 @@ public extension STBaseViewController { set { objc_setAssociatedObject(self, &st_navPromptKeyAssociation, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) } } } - diff --git a/Sources/STMedia/STImage.swift b/Sources/STMedia/STImage.swift index d0cfe76..88ae2c8 100644 --- a/Sources/STMedia/STImage.swift +++ b/Sources/STMedia/STImage.swift @@ -224,8 +224,7 @@ extension UIImage { while maxQuality - minQuality > 0.05 { let mid = (minQuality + maxQuality) / 2 if let compressed = image.jpegData(compressionQuality: mid) { - if compressed.count <= maxBytes { data = compressed; minQuality = mid } - else { maxQuality = mid } + if compressed.count <= maxBytes { data = compressed; minQuality = mid } else { maxQuality = mid } } } if data.count > maxBytes { diff --git a/Sources/STMedia/STScanView.swift b/Sources/STMedia/STScanView.swift index cf7cabd..f202efe 100644 --- a/Sources/STMedia/STScanView.swift +++ b/Sources/STMedia/STScanView.swift @@ -26,12 +26,12 @@ public struct STScanViewConfiguration { public var scanLineHeight: CGFloat = 5.0 public var maskAlpha: CGFloat = 0.6 public var borderColor: UIColor = .white - public var cornerColor: UIColor = UIColor(red: 0.110, green: 0.659, blue: 0.894, alpha: 1.0) - public var cornerSize: CGSize = CGSize(width: 15.0, height: 15.0) + public var cornerColor = UIColor(red: 0.110, green: 0.659, blue: 0.894, alpha: 1.0) + public var cornerSize = CGSize(width: 15.0, height: 15.0) public var cornerLineWidth: CGFloat = 4.0 public var tipText: String = "将二维码放入框内,即可自动扫描" public var tipTextColor: UIColor = .white - public var tipTextFont: UIFont = UIFont.systemFont(ofSize: 13) + public var tipTextFont = UIFont.systemFont(ofSize: 13) public var animationDuration: TimeInterval = 1.5 public var animationInterval: TimeInterval = 0.3 public var automaticSafeAreaAdaptation: Bool = true @@ -75,7 +75,7 @@ public class STScanView: UIView { } } - public var configuration: STScanViewConfiguration = STScanViewConfiguration() { + public var configuration = STScanViewConfiguration() { didSet { updateConfiguration() } } @@ -97,23 +97,23 @@ public class STScanView: UIView { stopAnimation() } - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) setupView() } - required public init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupView() } - public override func layoutSubviews() { + override public func layoutSubviews() { super.layoutSubviews() updateScanLineFrame() updateTipLabelFrame() } - public override func safeAreaInsetsDidChange() { + override public func safeAreaInsetsDidChange() { super.safeAreaInsetsDidChange() if self.configuration.automaticSafeAreaAdaptation { setNeedsDisplay() @@ -301,7 +301,7 @@ public class STScanView: UIView { // MARK: - Drawing - public override func draw(_ rect: CGRect) { + override public func draw(_ rect: CGRect) { super.draw(rect) drawScanRect() } @@ -366,13 +366,13 @@ public class STScanView: UIView { let offset = lineWidth / 3.0 let points: [(CGPoint, [(CGFloat, CGFloat)])] = [ (CGPoint(x: scanRect.minX - offset, y: scanRect.minY - offset), - [(0, -lineWidth/2), (cornerSize.width, 0), (0, cornerSize.height)]), + [(0, -lineWidth / 2), (cornerSize.width, 0), (0, cornerSize.height)]), (CGPoint(x: scanRect.maxX + offset, y: scanRect.minY - offset), - [(0, -lineWidth/2), (-cornerSize.width, 0), (0, cornerSize.height)]), + [(0, -lineWidth / 2), (-cornerSize.width, 0), (0, cornerSize.height)]), (CGPoint(x: scanRect.minX - offset, y: scanRect.maxY + offset), - [(0, lineWidth/2), (cornerSize.width, 0), (0, -cornerSize.height)]), + [(0, lineWidth / 2), (cornerSize.width, 0), (0, -cornerSize.height)]), (CGPoint(x: scanRect.maxX + offset, y: scanRect.maxY + offset), - [(0, lineWidth/2), (-cornerSize.width, 0), (0, -cornerSize.height)]) + [(0, lineWidth / 2), (-cornerSize.width, 0), (0, -cornerSize.height)]) ] for (startPoint, offsets) in points { context.move(to: CGPoint(x: startPoint.x + offsets[0].0, y: startPoint.y + offsets[0].1)) diff --git a/Sources/STNetwork/STHTTPSession.swift b/Sources/STNetwork/STHTTPSession.swift index 70b9c18..77bc4e8 100644 --- a/Sources/STNetwork/STHTTPSession.swift +++ b/Sources/STNetwork/STHTTPSession.swift @@ -5,10 +5,10 @@ // Created by 寒江孤影 on 2018/12/10. // -import UIKit -import Network -import Foundation import CryptoKit +import Foundation +import Network +import UIKit public final class STParameterEncoder { diff --git a/Sources/STNetwork/STHostnameReachability.swift b/Sources/STNetwork/STHostnameReachability.swift index 4476dea..e4276b1 100644 --- a/Sources/STNetwork/STHostnameReachability.swift +++ b/Sources/STNetwork/STHostnameReachability.swift @@ -96,7 +96,7 @@ public final class STHostnameReachability { let offlineCodes: Set = [ NSURLErrorNotConnectedToInternet, NSURLErrorNetworkConnectionLost, - NSURLErrorDataNotAllowed, + NSURLErrorDataNotAllowed ] if offlineCodes.contains(nsError.code) { refresh() diff --git a/Sources/STNetwork/STNetworkMonitoring.swift b/Sources/STNetwork/STNetworkMonitoring.swift index b2ac77d..26d05e8 100644 --- a/Sources/STNetwork/STNetworkMonitoring.swift +++ b/Sources/STNetwork/STNetworkMonitoring.swift @@ -5,8 +5,8 @@ // Created by 寒江孤影 on 2018/12/10. // -import UIKit import Network +import UIKit public enum STNetworkStatus: Int, @unchecked Sendable { case WiFi = 0 diff --git a/Sources/STNetwork/STSSLPinningConfig.swift b/Sources/STNetwork/STSSLPinningConfig.swift index ef6a330..733b2b1 100644 --- a/Sources/STNetwork/STSSLPinningConfig.swift +++ b/Sources/STNetwork/STSSLPinningConfig.swift @@ -5,9 +5,9 @@ // Created by 寒江孤影 on 2018/12/10. // +import CryptoKit import Foundation import Security -import CryptoKit public enum STSSLPinningConfigError: Error, LocalizedError { case invalidCertificateData diff --git a/Sources/STNetwork/STWebSocket.swift b/Sources/STNetwork/STWebSocket.swift index 715bd0a..940d5a2 100644 --- a/Sources/STNetwork/STWebSocket.swift +++ b/Sources/STNetwork/STWebSocket.swift @@ -5,9 +5,9 @@ // Created by 寒江孤影 on 2018/12/10. // -import UIKit -import Network import Foundation +import Network +import UIKit public actor STWebSocket { diff --git a/Sources/STNetwork/STWebSocketTypes.swift b/Sources/STNetwork/STWebSocketTypes.swift index 1cc8292..8aeb2ab 100644 --- a/Sources/STNetwork/STWebSocketTypes.swift +++ b/Sources/STNetwork/STWebSocketTypes.swift @@ -5,8 +5,8 @@ // Created by 寒江孤影 on 2018/12/10. // -import Network import Foundation +import Network public enum STWebSocketState: Equatable, Sendable { /// 初始未连接 diff --git a/Sources/STSecurity/STAntiDebugMonitor.swift b/Sources/STSecurity/STAntiDebugMonitor.swift index d9f0adf..076d1c6 100644 --- a/Sources/STSecurity/STAntiDebugMonitor.swift +++ b/Sources/STSecurity/STAntiDebugMonitor.swift @@ -17,7 +17,7 @@ public final class STAntiDebugMonitor { private let config: STAntiDebugConfig private let securityCheck: () -> STSecurityCheckResult - public init(config: STAntiDebugConfig, securityCheck: @escaping () -> STSecurityCheckResult = { STSecurityConfig.shared.st_performSecurityCheck() } ) { + public init(config: STAntiDebugConfig, securityCheck: @escaping () -> STSecurityCheckResult = { STSecurityConfig.shared.st_performSecurityCheck() }) { self.config = config self.securityCheck = securityCheck } diff --git a/Sources/STSecurity/STCryptoService.swift b/Sources/STSecurity/STCryptoService.swift index 7f97e6f..a7d317a 100644 --- a/Sources/STSecurity/STCryptoService.swift +++ b/Sources/STSecurity/STCryptoService.swift @@ -5,9 +5,9 @@ // Created by 寒江孤影 on 2018/12/10. // +import CommonCrypto import CryptoKit import Foundation -import CommonCrypto // MARK: - 加密配置 diff --git a/Sources/STSecurity/STEncrypt.swift b/Sources/STSecurity/STEncrypt.swift index f60affd..aab245d 100644 --- a/Sources/STSecurity/STEncrypt.swift +++ b/Sources/STSecurity/STEncrypt.swift @@ -5,10 +5,10 @@ // Created by 寒江孤影 on 2018/12/22. // -import Security -import Foundation -import CryptoKit import CommonCrypto +import CryptoKit +import Foundation +import Security // MARK: - 哈希算法类型 public enum STHashAlgorithm { diff --git a/Sources/STSecurity/STKeychainHelper.swift b/Sources/STSecurity/STKeychainHelper.swift index 70cf180..5fb56ce 100644 --- a/Sources/STSecurity/STKeychainHelper.swift +++ b/Sources/STSecurity/STKeychainHelper.swift @@ -5,9 +5,9 @@ // Created by 寒江孤影 on 2022/1/15. // -import UIKit -import Security import LocalAuthentication +import Security +import UIKit public enum STKeychainAccessControl { case whenUnlocked diff --git a/Sources/STSecurity/STSecurityConfig.swift b/Sources/STSecurity/STSecurityConfig.swift index a5c343e..057ce32 100644 --- a/Sources/STSecurity/STSecurityConfig.swift +++ b/Sources/STSecurity/STSecurityConfig.swift @@ -6,8 +6,8 @@ // import Darwin -import Security import Foundation +import Security import SystemConfiguration public class STSecurityConfig { @@ -245,6 +245,6 @@ private enum STSecurityConstants { "/usr/lib/substrate/SubstrateBootstrap.dylib", "/usr/lib/substrate/SubstrateLoader.dylib", "/usr/lib/frida/frida-agent.dylib", - "/usr/lib/libcycript.dylib", + "/usr/lib/libcycript.dylib" ] } diff --git a/Sources/STTools/STColor.swift b/Sources/STTools/STColor.swift index 67b9423..09e76ef 100644 --- a/Sources/STTools/STColor.swift +++ b/Sources/STTools/STColor.swift @@ -5,8 +5,8 @@ // Created by 寒江孤影 on 2018/10/9. // -import UIKit import CoreGraphics +import UIKit public extension UIColor { diff --git a/Sources/STTools/STDate.swift b/Sources/STTools/STDate.swift index d34ddf5..3fb0d09 100644 --- a/Sources/STTools/STDate.swift +++ b/Sources/STTools/STDate.swift @@ -200,7 +200,7 @@ public extension String { "dd/MM/yyyy", "yyyy年MM月dd日 HH:mm:ss", "yyyy年MM月dd日 HH:mm", - "yyyy年MM月dd日", + "yyyy年MM月dd日" ] if contains("T") && (contains("Z") || contains("+")) { diff --git a/Sources/STTools/STDeviceInfo.swift b/Sources/STTools/STDeviceInfo.swift index d416f9f..e0043cb 100644 --- a/Sources/STTools/STDeviceInfo.swift +++ b/Sources/STTools/STDeviceInfo.swift @@ -5,10 +5,10 @@ // Created by 寒江孤影 on 2019/02/10. // -import UIKit import Darwin import Network import SystemConfiguration +import UIKit public struct STDeviceInfo { diff --git a/Sources/STTools/STScrollPerfDiagnostics.swift b/Sources/STTools/STScrollPerfDiagnostics.swift index cf4048a..47aea34 100644 --- a/Sources/STTools/STScrollPerfDiagnostics.swift +++ b/Sources/STTools/STScrollPerfDiagnostics.swift @@ -71,4 +71,3 @@ public enum STScrollPerfDiagnostics { #endif } } - diff --git a/Sources/STTools/UIView+FontRefresh.swift b/Sources/STTools/UIView+FontRefresh.swift index 09cec5d..0cadde7 100644 --- a/Sources/STTools/UIView+FontRefresh.swift +++ b/Sources/STTools/UIView+FontRefresh.swift @@ -73,4 +73,4 @@ extension UIView { textView.font = font.withSize(round(font.pointSize * scaleRatio)) } } -} \ No newline at end of file +} diff --git a/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift b/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift index f87609c..b15a953 100644 --- a/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift +++ b/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift @@ -94,14 +94,14 @@ open class STBottomSheetViewController: UIViewController { return abs(self.containerTopConstraint.constant - self.fullOffset) < self.fullOffsetTolerance } - open override func loadView() { + override open func loadView() { let rootView = STBottomSheetRootView() rootView.backgroundColor = .clear rootView.interactiveContentView = self.contentView self.view = rootView } - open override func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = .clear self.setupContentView() @@ -110,7 +110,7 @@ open class STBottomSheetViewController: UIViewController { self.containerTopConstraint.constant = self.hiddenOffset } - open override func viewDidLayoutSubviews() { + override open func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if self.containerTopConstraint.constant > self.hiddenOffset { self.containerTopConstraint.constant = self.hiddenOffset @@ -222,7 +222,7 @@ open class STBottomSheetViewController: UIViewController { self.indicatorView.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor), self.indicatorView.widthAnchor.constraint(equalToConstant: 38), self.indicatorView.heightAnchor.constraint(equalToConstant: 5), - self.indicatorView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 8), + self.indicatorView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 8) ]) self.view.bringSubviewToFront(self.indicatorView) @@ -502,11 +502,11 @@ public class STBottomSheetPresentationController: UIPresentationController { return view }() - public override var frameOfPresentedViewInContainerView: CGRect { + override public var frameOfPresentedViewInContainerView: CGRect { return self.containerView?.bounds ?? .zero } - public override func presentationTransitionWillBegin() { + override public func presentationTransitionWillBegin() { guard let containerView = self.containerView else { return } self.dimmingView.frame = containerView.bounds containerView.insertSubview(self.dimmingView, at: 0) @@ -519,7 +519,7 @@ public class STBottomSheetPresentationController: UIPresentationController { }) } - public override func dismissalTransitionWillBegin() { + override public func dismissalTransitionWillBegin() { guard let transitionCoordinator = self.presentedViewController.transitionCoordinator else { self.dimmingView.alpha = 0 self.dimmingView.removeFromSuperview() @@ -532,7 +532,7 @@ public class STBottomSheetPresentationController: UIPresentationController { }) } - public override func presentationTransitionDidEnd(_ completed: Bool) { + override public func presentationTransitionDidEnd(_ completed: Bool) { super.presentationTransitionDidEnd(completed) if completed { (self.presentedViewController as? STBottomSheetViewController)?.finishPresentationWithoutAnimation() @@ -541,7 +541,7 @@ public class STBottomSheetPresentationController: UIPresentationController { } } - public override func containerViewDidLayoutSubviews() { + override public func containerViewDidLayoutSubviews() { super.containerViewDidLayoutSubviews() self.dimmingView.frame = self.containerView?.bounds ?? .zero self.presentedView?.frame = self.frameOfPresentedViewInContainerView @@ -627,7 +627,7 @@ public class STBottomSheetTransitionAnimator: NSObject, UIViewControllerAnimated public class STBottomSheetTransitionDelegate: NSObject, UIViewControllerTransitioningDelegate { - public override init() { + override public init() { super.init() } diff --git a/Sources/STUIKit/STButton/STBtn.swift b/Sources/STUIKit/STButton/STBtn.swift index 40d1c35..a0f6302 100644 --- a/Sources/STUIKit/STButton/STBtn.swift +++ b/Sources/STUIKit/STButton/STBtn.swift @@ -31,8 +31,8 @@ open class STBtn: UIButton { private var gradientLayer: CAGradientLayer? private var gradientColors: [UIColor]? - private var gradientStartPoint: CGPoint = CGPoint(x: 0, y: 0) - private var gradientEndPoint: CGPoint = CGPoint(x: 1, y: 1) + private var gradientStartPoint = CGPoint(x: 0, y: 0) + private var gradientEndPoint = CGPoint(x: 1, y: 1) private var liquidGlassView: STLiquidGlassView? /// 按 `UIControl.State.rawValue` 存储的 Configuration 背景色,由 `st_setBackgroundColor(_:for:)` 维护。 private var stateBackgroundColors: [UInt: UIColor] = [:] @@ -217,18 +217,18 @@ open class STBtn: UIButton { self.setupButton() } - required public init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.setupButton() } - open override var isHighlighted: Bool { + override open var isHighlighted: Bool { didSet { self.updateLiquidGlassState(animated: true) } } - open override var isEnabled: Bool { + override open var isEnabled: Bool { didSet { self.updateLiquidGlassState(animated: false) } @@ -382,7 +382,7 @@ open class STBtn: UIButton { } } - open override func layoutSubviews() { + override open func layoutSubviews() { super.layoutSubviews() self.updateGradientLayerFrame() self.updateLiquidGlassFrame() @@ -437,7 +437,7 @@ open class STBtn: UIButton { /// - offset: 阴影偏移 /// - radius: 阴影半径 /// - opacity: 阴影透明度 - public override func st_setShadow(color: UIColor = .black, offset: CGSize = CGSize(width: 0, height: 2), radius: CGFloat = 4, opacity: Float = 0.3) { + override public func st_setShadow(color: UIColor = .black, offset: CGSize = CGSize(width: 0, height: 2), radius: CGFloat = 4, opacity: Float = 0.3) { self.layer.shadowColor = color.cgColor self.layer.shadowOffset = offset self.layer.shadowRadius = radius diff --git a/Sources/STUIKit/STButton/STIconBtn.swift b/Sources/STUIKit/STButton/STIconBtn.swift index e7c31ae..9500319 100644 --- a/Sources/STUIKit/STButton/STIconBtn.swift +++ b/Sources/STUIKit/STButton/STIconBtn.swift @@ -180,7 +180,7 @@ open class STIconBtn: STBtn { /// 仅含图片时的默认无障碍文案;可设置以区分不同按钮语义(如"返回"/"更多"),亦可被子类重写本地化。 open var st_fallbackAccessibilityLabel: String = "按钮" - open override var accessibilityLabel: String? { + override open var accessibilityLabel: String? { get { if let explicit = self.st_explicitAccessibilityLabel { return explicit } if let title = self.currentTitle, !title.isEmpty { return title } @@ -192,7 +192,7 @@ open class STIconBtn: STBtn { } } - open override func refineButtonConfiguration(_ button: UIButton, configuration config: inout UIButton.Configuration) { + override open func refineButtonConfiguration(_ button: UIButton, configuration config: inout UIButton.Configuration) { super.refineButtonConfiguration(button, configuration: &config) let icon = self.iconContentInsets diff --git a/Sources/STUIKit/STButton/STVerificationCodeBtn.swift b/Sources/STUIKit/STButton/STVerificationCodeBtn.swift index 5dd0347..63a9f09 100644 --- a/Sources/STUIKit/STButton/STVerificationCodeBtn.swift +++ b/Sources/STUIKit/STButton/STVerificationCodeBtn.swift @@ -42,19 +42,15 @@ open class STVerificationCodeBtn: STBtn { super.init(frame: frame) } - required public init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } - override open func awakeFromNib() { - super.awakeFromNib() - } - public func st_configDone() { self.originTitle = self.title(for: .normal) ?? self.titleLabel?.text } - public func beginTimer() -> Void { + public func beginTimer() { guard Thread.isMainThread else { DispatchQueue.main.async { [weak self] in self?.beginTimer() @@ -82,7 +78,7 @@ open class STVerificationCodeBtn: STBtn { self.timer = timer } - private func timerSelector(_ timer: STTimer) -> Void { + private func timerSelector(_ timer: STTimer) { guard self.timer === timer else { return } guard Thread.isMainThread else { DispatchQueue.main.async { [weak self, weak timer] in @@ -99,12 +95,12 @@ open class STVerificationCodeBtn: STBtn { self.updateCountdownTitle() } - public func invalidTimer() -> Void { + public func invalidTimer() { self.timer?.stop() self.timer = nil } - public func resetCountdown() -> Void { + public func resetCountdown() { self.invalidTimer() self.restoreTimerState() } diff --git a/Sources/STUIKit/STGlassCardView/STGlassCardView.swift b/Sources/STUIKit/STGlassCardView/STGlassCardView.swift index 7a7de7c..e768d02 100644 --- a/Sources/STUIKit/STGlassCardView/STGlassCardView.swift +++ b/Sources/STUIKit/STGlassCardView/STGlassCardView.swift @@ -68,7 +68,7 @@ open class STGlassCardView: UIView { return self.effectView.contentView } - public override func addSubview(_ view: UIView) { + override public func addSubview(_ view: UIView) { if view === self.effectView { super.addSubview(view) } else { @@ -76,7 +76,7 @@ open class STGlassCardView: UIView { } } - public override func insertSubview(_ view: UIView, at index: Int) { + override public func insertSubview(_ view: UIView, at index: Int) { if view === self.effectView { super.insertSubview(view, at: index) } else { @@ -84,7 +84,7 @@ open class STGlassCardView: UIView { } } - public override func insertSubview(_ view: UIView, aboveSubview siblingSubview: UIView) { + override public func insertSubview(_ view: UIView, aboveSubview siblingSubview: UIView) { if view === self.effectView { super.insertSubview(view, aboveSubview: siblingSubview) } else { @@ -92,7 +92,7 @@ open class STGlassCardView: UIView { } } - public override func insertSubview(_ view: UIView, belowSubview siblingSubview: UIView) { + override public func insertSubview(_ view: UIView, belowSubview siblingSubview: UIView) { if view === self.effectView { super.insertSubview(view, belowSubview: siblingSubview) } else { @@ -126,13 +126,13 @@ open class STGlassCardView: UIView { } } - public var borderColor: UIColor? = nil { + public var borderColor: UIColor? { didSet { self.effectView.layer.borderColor = self.borderColor?.resolvedColor(with: self.traitCollection).cgColor } } - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) self.setupView() } @@ -166,7 +166,7 @@ open class STGlassCardView: UIView { } } - open override func layoutSubviews() { + override open func layoutSubviews() { super.layoutSubviews() self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.cornerRadius).cgPath } @@ -185,7 +185,7 @@ open class STGlassCardView: UIView { self.shadowConfig = shadowConfig } - open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + override open func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if self.traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) { self.applyAnimatedShadowStyle(for: self.traitCollection.userInterfaceStyle) diff --git a/Sources/STUIKit/STLabel/STLabel.swift b/Sources/STUIKit/STLabel/STLabel.swift index 5df2d41..a7ae746 100644 --- a/Sources/STUIKit/STLabel/STLabel.swift +++ b/Sources/STUIKit/STLabel/STLabel.swift @@ -139,7 +139,7 @@ open class STLabel: UILabel, STLocalizable { self.adjustsFontForContentSizeCategory = true } - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) self.verticalAlignment = STLabelVerticalAlignment.middle self.adjustsFontForContentSizeCategory = true @@ -152,7 +152,7 @@ open class STLabel: UILabel, STLocalizable { self.updateFontSize() } - public override func layoutSubviews() { + override public func layoutSubviews() { super.layoutSubviews() self.st_updateLiquidGlassCornerRadius() if let glassView = self.subviews.first(where: { $0 is STLiquidGlassView }) { @@ -164,19 +164,19 @@ open class STLabel: UILabel, STLocalizable { self.font = UIFont.st_systemFont(ofSize: self.font.pointSize) } - public override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect { + override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect { // 考虑内边距调整边界 let adjustedBounds = bounds.inset(by: contentEdgeInsets) return super.textRect(forBounds: adjustedBounds, limitedToNumberOfLines: numberOfLines) } - public override func draw(_ rect: CGRect) { + override public func draw(_ rect: CGRect) { // 考虑内边距调整绘制区域 let adjustedRect = rect.inset(by: contentEdgeInsets) super.drawText(in: adjustedRect) } - public override var intrinsicContentSize: CGSize { + override public var intrinsicContentSize: CGSize { // 使用 super 的 intrinsicContentSize 来获取正确的文本尺寸 let originalSize = super.intrinsicContentSize // 如果原始尺寸为零,尝试手动计算 @@ -198,7 +198,7 @@ open class STLabel: UILabel, STLocalizable { height: originalSize.height + contentEdgeInsets.top + contentEdgeInsets.bottom) } - public override func sizeThatFits(_ size: CGSize) -> CGSize { + override public func sizeThatFits(_ size: CGSize) -> CGSize { // 如果可用空间小于内边距,返回最小尺寸 let availableWidth = size.width - contentEdgeInsets.left - contentEdgeInsets.right let availableHeight = size.height - contentEdgeInsets.top - contentEdgeInsets.bottom diff --git a/Sources/STUIKit/STLabel/STShimmerLabel.swift b/Sources/STUIKit/STLabel/STShimmerLabel.swift index e3fdbc4..2f55ff5 100644 --- a/Sources/STUIKit/STLabel/STShimmerLabel.swift +++ b/Sources/STUIKit/STLabel/STShimmerLabel.swift @@ -18,7 +18,7 @@ public class STShimmerLabel: STLabel { didSet { self.updateGradient() } } - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) self.setup() } @@ -28,28 +28,28 @@ public class STShimmerLabel: STLabel { self.setup() } - public override func layoutSubviews() { + override public func layoutSubviews() { super.layoutSubviews() self.updateFrames() } - public override var text: String? { + override public var text: String? { didSet { self.updateTextMask() } } - public override var attributedText: NSAttributedString? { + override public var attributedText: NSAttributedString? { didSet { self.updateTextMask() } } - public override var font: UIFont! { + override public var font: UIFont! { didSet { self.updateTextMask() } } - public override var textAlignment: NSTextAlignment { + override public var textAlignment: NSTextAlignment { didSet { self.updateTextMask() } } - public override var numberOfLines: Int { + override public var numberOfLines: Int { didSet { self.updateTextMask() } } diff --git a/Sources/STUIKit/STLog/STLogFileWriter.swift b/Sources/STUIKit/STLog/STLogFileWriter.swift index 6563eb4..1a0fd2c 100644 --- a/Sources/STUIKit/STLog/STLogFileWriter.swift +++ b/Sources/STUIKit/STLog/STLogFileWriter.swift @@ -110,7 +110,7 @@ final class STLogFileWriter: STLogHandler { } } - private func enumerateNewestRecords(skip: Int, limit: Int, levels: Set,searchText: String?) -> [STLogRecord] { + private func enumerateNewestRecords(skip: Int, limit: Int, levels: Set, searchText: String?) -> [STLogRecord] { let normalizedSearch = searchText?.lowercased() var matched: [STLogRecord] = [] var skipped = 0 diff --git a/Sources/STUIKit/STLog/STLogView.swift b/Sources/STUIKit/STLog/STLogView.swift index 4aa56f0..476d37f 100644 --- a/Sources/STUIKit/STLog/STLogView.swift +++ b/Sources/STUIKit/STLog/STLogView.swift @@ -138,14 +138,14 @@ open class STLogView: UIView { NotificationCenter.default.removeObserver(self) } - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) self.configUI() self.setupNotifications() self.loadInitialLogs() } - required public init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) self.configUI() self.setupNotifications() @@ -161,7 +161,7 @@ open class STLogView: UIView { self.updateLiquidGlassBackground() } - open override func layoutSubviews() { + override open func layoutSubviews() { super.layoutSubviews() self.st_updateLiquidGlassCornerRadius() } diff --git a/Sources/STUIKit/STTabBar/STCustomTabBar.swift b/Sources/STUIKit/STTabBar/STCustomTabBar.swift index c3d2c7c..3f9f657 100644 --- a/Sources/STUIKit/STTabBar/STCustomTabBar.swift +++ b/Sources/STUIKit/STTabBar/STCustomTabBar.swift @@ -43,11 +43,11 @@ public class STCustomTabBar: UIView { private var selectedIndex: Int = 0 private var itemViews: [STTabBarItemView] = [] private var itemModels: [STTabBarItemModel] = [] - private var config: STTabBarConfig = STTabBarConfig() + private var config = STTabBarConfig() private var heightConstraint: NSLayoutConstraint? private var topBorderHeightConstraint: NSLayoutConstraint? - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) self.setupUI() } @@ -255,7 +255,7 @@ public class STCustomTabBar: UIView { return view }() - private lazy var topBorderView: UIView = UIView() + private lazy var topBorderView = UIView() } extension STCustomTabBar { diff --git a/Sources/STUIKit/STTabBar/STCustomTabBarController.swift b/Sources/STUIKit/STTabBar/STCustomTabBarController.swift index d7160e7..14a4878 100644 --- a/Sources/STUIKit/STTabBar/STCustomTabBarController.swift +++ b/Sources/STUIKit/STTabBar/STCustomTabBarController.swift @@ -13,7 +13,7 @@ open class STCustomTabBarController: UITabBarController { private var isCustomTabBarVisible: Bool = false private var customTabBarItems: [STTabBarItemModel] = [] - private var customTabBarConfig: STTabBarConfig = STTabBarConfig() + private var customTabBarConfig = STTabBarConfig() private var hasInstalledCustomTabBar: Bool = false private var lastAppliedAdditionalBottomInset: CGFloat = 0 @@ -21,12 +21,12 @@ open class STCustomTabBarController: UITabBarController { return !self.shouldUseSystemTabBar() && !self.customTabBarItems.isEmpty } - open override func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() self.applyPreferredTabBarMode() } - open override func viewDidLayoutSubviews() { + override open func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() self.st_syncCustomTabBarSafeAreaAndZOrder() } @@ -151,12 +151,12 @@ open class STCustomTabBarController: UITabBarController { } // MARK: - 重写系统方法 - open override func setViewControllers(_ viewControllers: [UIViewController]?, animated: Bool) { + override open func setViewControllers(_ viewControllers: [UIViewController]?, animated: Bool) { super.setViewControllers(viewControllers, animated: animated) self.applyPreferredTabBarMode() } - open override var selectedIndex: Int { + override open var selectedIndex: Int { didSet { if self.isCustomTabBarVisible { self.customTabBar.setSelectedIndex(self.selectedIndex) @@ -164,7 +164,7 @@ open class STCustomTabBarController: UITabBarController { } } - open override var selectedViewController: UIViewController? { + override open var selectedViewController: UIViewController? { didSet { if self.isCustomTabBarVisible, let selectedVC = self.selectedViewController { if let index = viewControllers?.firstIndex(of: selectedVC) { diff --git a/Sources/STUIKit/STTabBar/STTabBarItemView.swift b/Sources/STUIKit/STTabBar/STTabBarItemView.swift index f698ef8..1503379 100644 --- a/Sources/STUIKit/STTabBar/STTabBarItemView.swift +++ b/Sources/STUIKit/STTabBar/STTabBarItemView.swift @@ -26,7 +26,7 @@ public class STTabBarItemView: UIView { private var initialConstraints: [NSLayoutConstraint] = [] private var lastEffectiveBarHeightUsed: CGFloat = -1 - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) self.setupUI() } @@ -36,7 +36,7 @@ public class STTabBarItemView: UIView { self.setupUI() } - public override func layoutSubviews() { + override public func layoutSubviews() { super.layoutSubviews() guard let model = self.itemModel, model.displayMode == .imageAndText else { return } let eff = self.effectiveBarHeightForImageTextLayout() @@ -380,7 +380,7 @@ public class STTabBarItemView: UIView { self.tapAction?() } - public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + override public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else { return } guard var model = self.itemModel else { return } diff --git a/Sources/STUIKit/STTextField/STTextField.swift b/Sources/STUIKit/STTextField/STTextField.swift index d3382db..9d4c4fb 100644 --- a/Sources/STUIKit/STTextField/STTextField.swift +++ b/Sources/STUIKit/STTextField/STTextField.swift @@ -25,7 +25,7 @@ public extension STTextFieldDelegate { open class STTextField: UITextField { open var textIsCheck: Bool = false - weak open var cusDelegate: STTextFieldDelegate? + open weak var cusDelegate: STTextFieldDelegate? private var contentInsetLeft: CGFloat = 0 private var contentInsetRight: CGFloat = 0 @@ -142,12 +142,12 @@ open class STTextField: UITextField { } } - public override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) self.config() } - required public init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) self.config() } @@ -156,34 +156,34 @@ open class STTextField: UITextField { self.removeSecureTextEntryObserver() } - open override func deleteBackward() { + override open func deleteBackward() { super.deleteBackward() if let delegate = self.cusDelegate { delegate.st_textFieldBackwardKeyPressed(textField: self) } } - open override func textRect(forBounds bounds: CGRect) -> CGRect { - let inset = CGRect.init(x: bounds.origin.x + self.contentInsetLeft, y: bounds.origin.y, width: bounds.size.width - self.contentInsetLeft - self.contentInsetRight, height: bounds.size.height) + override open func textRect(forBounds bounds: CGRect) -> CGRect { + let inset = CGRect(x: bounds.origin.x + self.contentInsetLeft, y: bounds.origin.y, width: bounds.size.width - self.contentInsetLeft - self.contentInsetRight, height: bounds.size.height) return inset } - open override func editingRect(forBounds bounds: CGRect) -> CGRect { - let inset = CGRect.init(x: bounds.origin.x + self.contentInsetLeft, y: bounds.origin.y, width: bounds.size.width - self.contentInsetLeft - self.contentInsetRight, height: bounds.size.height) + override open func editingRect(forBounds bounds: CGRect) -> CGRect { + let inset = CGRect(x: bounds.origin.x + self.contentInsetLeft, y: bounds.origin.y, width: bounds.size.width - self.contentInsetLeft - self.contentInsetRight, height: bounds.size.height) return inset } - open override func leftViewRect(forBounds bounds: CGRect) -> CGRect { + override open func leftViewRect(forBounds bounds: CGRect) -> CGRect { if let newView = self.leftView { let frame = newView.frame let x = bounds.origin.x let y = (bounds.size.height - frame.size.height) / 2.0 - return CGRect.init(x: x, y: y, width: frame.size.width, height: frame.size.height) + return CGRect(x: x, y: y, width: frame.size.width, height: frame.size.height) } return CGRect.zero } - open override func rightViewRect(forBounds bounds: CGRect) -> CGRect { + override open func rightViewRect(forBounds bounds: CGRect) -> CGRect { if let newView = self.rightView { let frame = newView.frame let x = bounds.width - frame.width @@ -193,7 +193,7 @@ open class STTextField: UITextField { return CGRect.zero } - open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { if let rightView = self.rightView { let rightViewFrame = self.rightViewRect(forBounds: self.bounds) if rightViewFrame.contains(point) { @@ -206,7 +206,7 @@ open class STTextField: UITextField { return super.hitTest(point, with: event) } - open override func layoutSubviews() { + override open func layoutSubviews() { super.layoutSubviews() self.st_updateLiquidGlassCornerRadius() if self.isPasswordToggleEnabled, let container = self.rightView, let button = self.passwordToggleButton { @@ -229,17 +229,17 @@ open class STTextField: UITextField { self.addTarget(self, action: #selector(st_textFieldEditingChanged(textField:)), for: .editingChanged) } - public func setTextInsets(left: CGFloat, right: CGFloat) -> Void { + public func setTextInsets(left: CGFloat, right: CGFloat) { self.contentInsetLeft = max(0, left) self.contentInsetRight = max(0, right) self.setNeedsLayout() } - public func config(textLimitCount: Int) -> Void { + public func config(textLimitCount: Int) { self.maxTextCount = textLimitCount } - public func configAttributed(textColor: UIColor) -> Void { + public func configAttributed(textColor: UIColor) { if let attributedText = self.attributedPlaceholder { let placeholderAttributedString = NSMutableAttributedString(attributedString: attributedText) placeholderAttributedString.addAttribute(.foregroundColor, value: textColor, range: NSRange(location: 0, length: placeholderAttributedString.length)) @@ -247,9 +247,9 @@ open class STTextField: UITextField { } } - public func configAttributed(text: String, textColor: UIColor) -> Void { + public func configAttributed(text: String, textColor: UIColor) { if !text.isEmpty { - let placeholderAttributedString = NSMutableAttributedString(attributedString: NSAttributedString.init(string: text)) + let placeholderAttributedString = NSMutableAttributedString(attributedString: NSAttributedString(string: text)) placeholderAttributedString.addAttribute(.foregroundColor, value: textColor, range: NSRange(location: 0, length: placeholderAttributedString.length)) self.attributedPlaceholder = placeholderAttributedString } @@ -310,7 +310,7 @@ open class STTextField: UITextField { /// 设置isSecureTextEntry的KVO监听 private func setupSecureTextEntryObserver() { self.removeSecureTextEntryObserver() - self.secureTextEntryObserver = self.observe(\.isSecureTextEntry, options: [.old, .new]) { [weak self] textField, change in + self.secureTextEntryObserver = self.observe(\.isSecureTextEntry, options: [.old, .new]) { [weak self] _, change in guard let strongSelf = self, strongSelf.isPasswordToggleEnabled else { return } if let oldValue = change.oldValue, let newValue = change.newValue, !oldValue && newValue { @@ -359,7 +359,7 @@ open class STTextField: UITextField { guard let button = self.passwordToggleButton else { return } self.savaText = self.text ?? "" self.isChangingSecureTextEntry = true - self.isSecureTextEntry = !self.isSecureTextEntry + self.isSecureTextEntry.toggle() button.isSelected = !self.isSecureTextEntry // 延迟重置标志,确保文本变化事件能正确处理 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { diff --git a/Sources/STUIKit/STTextView/STPlaceholderTextView.swift b/Sources/STUIKit/STTextView/STPlaceholderTextView.swift index 4a61009..6d8ca62 100644 --- a/Sources/STUIKit/STTextView/STPlaceholderTextView.swift +++ b/Sources/STUIKit/STTextView/STPlaceholderTextView.swift @@ -66,7 +66,7 @@ open class STPlaceholderTextView: UITextView { } } - @objc dynamic open var placeholderFont: UIFont = UIFont.st_systemFont(ofSize: 16) { + @objc open dynamic var placeholderFont = UIFont.st_systemFont(ofSize: 16) { didSet { self.placeholderLabel.font = self.placeholderFont if !self.isApplyingDefaultPlaceholderFont { @@ -131,21 +131,21 @@ open class STPlaceholderTextView: UITextView { } } - open override var text: String! { + override open var text: String! { didSet { self.updatePlaceholderVisibility() self.notifyPlaceholderTextDidChange() } } - open override var attributedText: NSAttributedString! { + override open var attributedText: NSAttributedString! { didSet { self.updatePlaceholderVisibility() self.notifyPlaceholderTextDidChange() } } - open override var font: UIFont? { + override open var font: UIFont? { didSet { if self.shouldFollowTextViewFontForPlaceholder { self.applyDefaultPlaceholderFont() @@ -154,7 +154,7 @@ open class STPlaceholderTextView: UITextView { } } - open override var bounds: CGRect { + override open var bounds: CGRect { didSet { if oldValue.size.width != self.bounds.size.width { self.layoutPlaceholderLabel() @@ -163,7 +163,7 @@ open class STPlaceholderTextView: UITextView { } } - open override var textContainerInset: UIEdgeInsets { + override open var textContainerInset: UIEdgeInsets { didSet { guard !self.isUpdatingTextContainerInset else { return } self.contentInsetsStorage = self.textContainerInset @@ -172,7 +172,7 @@ open class STPlaceholderTextView: UITextView { } } - public override init(frame: CGRect, textContainer: NSTextContainer?) { + override public init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) self.configPlaceholderTextView() } @@ -182,7 +182,7 @@ open class STPlaceholderTextView: UITextView { self.configPlaceholderTextView() } - open override func layoutSubviews() { + override open func layoutSubviews() { super.layoutSubviews() self.st_updateLiquidGlassCornerRadius() self.layoutPlaceholderLabel() diff --git a/Sources/STUIKit/STTextView/STShimmerTextView.swift b/Sources/STUIKit/STTextView/STShimmerTextView.swift index 93121f5..f0a7a79 100644 --- a/Sources/STUIKit/STTextView/STShimmerTextView.swift +++ b/Sources/STUIKit/STTextView/STShimmerTextView.swift @@ -61,13 +61,13 @@ open class STShimmerTextView: UITextView { private var _lineFadeBaseLayer: CALayer? /// 最终目标态的 attributed text(全不透明),不含任何动画中间状态的 alpha 值。 /// 供外部做 "已渲染前缀" 比较时使用,避免因动画过渡期 alpha < 1 导致前缀比较误判。 - private var _baseAttributedText: NSMutableAttributedString = NSMutableAttributedString() + private var _baseAttributedText = NSMutableAttributedString() private var _isLineFadeAnimating: Bool = false open var defaultTextAttributes: [NSAttributedString.Key: Any] { return [ .font: self.font ?? UIFont.st_systemFont(ofSize: 16), - .foregroundColor: self.textColor ?? UIColor.label, + .foregroundColor: self.textColor ?? UIColor.label ] } @@ -79,7 +79,7 @@ open class STShimmerTextView: UITextView { (self.displayLink != nil && !self.animatingTokens.isEmpty) || self._isLineFadeAnimating } - public override init(frame: CGRect, textContainer: NSTextContainer?) { + override public init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) self.setup() } @@ -118,7 +118,7 @@ open class STShimmerTextView: UITextView { } } - open override func layoutSubviews() { + override open func layoutSubviews() { super.layoutSubviews() guard let mask = _lineFadeMaskLayer else { return } CATransaction.begin() @@ -669,7 +669,7 @@ open class STShimmerTextView: UITextView { let mask = CALayer() mask.actions = [ "bounds": null, "position": null, - "frame": null, "sublayerTransform": null, "transition": null, + "frame": null, "sublayerTransform": null, "transition": null ] let base = CALayer() base.backgroundColor = UIColor.black.cgColor @@ -775,12 +775,12 @@ open class STShimmerTextView: UITextView { anim.fromValue = [ NSNumber(value: 0), NSNumber(value: Double(fromFadeStart)), - NSNumber(value: 1), + NSNumber(value: 1) ] anim.toValue = [ NSNumber(value: 0), NSNumber(value: Double(fadeStart)), - NSNumber(value: 1), + NSNumber(value: 1) ] anim.fillMode = .both anim.isRemovedOnCompletion = true @@ -808,7 +808,7 @@ open class STShimmerTextView: UITextView { } /// 子类可重写:禁止系统长按复制/粘贴菜单,仅使用自定义 popupMenuItems(如 Bajoseek 回复区) - open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { + override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { if self.suppressSystemTextMenu { return false } diff --git a/Sources/STUIKit/STTextView/STTextView.swift b/Sources/STUIKit/STTextView/STTextView.swift index 6c196e7..d4cb16d 100644 --- a/Sources/STUIKit/STTextView/STTextView.swift +++ b/Sources/STUIKit/STTextView/STTextView.swift @@ -32,7 +32,7 @@ public typealias STTextViewHeightChangeUserActionsBlock = (_ oldHeight: CGFloat, @IBDesignable open class STTextView: STPlaceholderTextView { - weak open var cusDelegate: STTextViewDelegate? + open weak var cusDelegate: STTextViewDelegate? open var shouldPreventResigningFirstResponder: (() -> Bool)? open var shouldLimitTextCount: Bool = true @@ -113,7 +113,7 @@ open class STTextView: STPlaceholderTextView { return lineCount } - open var maxTextHeight: CGFloat = CGFloat.greatestFiniteMagnitude { + open var maxTextHeight = CGFloat.greatestFiniteMagnitude { didSet { self.updateHeightIfNeeded(notify: true, animated: false) } @@ -141,19 +141,19 @@ open class STTextView: STPlaceholderTextView { } } - public override var font: UIFont? { + override public var font: UIFont? { didSet { self.updateHeightIfNeeded(notify: true, animated: false) } } - public override var textColor: UIColor? { + override public var textColor: UIColor? { didSet { self.typingAttributes[.foregroundColor] = self.textColor ?? UIColor.label } } - public override var bounds: CGRect { + override public var bounds: CGRect { didSet { if oldValue.size.width != self.bounds.size.width { self.updateHeightIfNeeded(notify: true, animated: false) @@ -161,7 +161,7 @@ open class STTextView: STPlaceholderTextView { } } - public override var contentSize: CGSize { + override public var contentSize: CGSize { didSet { guard oldValue != self.contentSize else { return } let animated = self.window != nil && self.isFirstResponder && self.animateHeightChange @@ -169,14 +169,14 @@ open class STTextView: STPlaceholderTextView { } } - public override var intrinsicContentSize: CGSize { + override public var intrinsicContentSize: CGSize { if self.heightConstraint != nil { return CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric) } return CGSize(width: UIView.noIntrinsicMetric, height: self.calculatedHeight()) } - public override init(frame: CGRect, textContainer: NSTextContainer?) { + override public init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) self.config() } @@ -186,40 +186,40 @@ open class STTextView: STPlaceholderTextView { self.config() } - open override func layoutSubviews() { + override open func layoutSubviews() { super.layoutSubviews() self.updateHeightConstraintIfNeeded() } - open override func didMoveToSuperview() { + override open func didMoveToSuperview() { super.didMoveToSuperview() self.updateHeightConstraintIfNeeded() self.updateHeightIfNeeded(notify: false, animated: false) } @discardableResult - open override func resignFirstResponder() -> Bool { + override open func resignFirstResponder() -> Bool { if self.shouldPreventResigningFirstResponder?() == true { return false } return super.resignFirstResponder() } - open override func sizeThatFits(_ size: CGSize) -> CGSize { + override open func sizeThatFits(_ size: CGSize) -> CGSize { let fittingHeight = self.fittingContentHeight(for: size.width) let height = self.clampedHeight(for: fittingHeight) return CGSize(width: size.width, height: height) } - open override func sizeToFit() { + override open func sizeToFit() { self.bounds.size.height = self.calculatedHeight() } - open override func st_placeholderTextDidChange() { + override open func st_placeholderTextDidChange() { self.handleTextChange() } - open override func st_placeholderHeightAffectingChange() { + override open func st_placeholderHeightAffectingChange() { self.updateHeightIfNeeded(notify: true, animated: false) } diff --git a/Sources/STUIKit/STView/STIBInspectable.swift b/Sources/STUIKit/STView/STIBInspectable.swift index 0fdbb85..2c987c9 100644 --- a/Sources/STUIKit/STView/STIBInspectable.swift +++ b/Sources/STUIKit/STView/STIBInspectable.swift @@ -192,7 +192,7 @@ extension NSLayoutConstraint { } // MARK: - 生命周期方法 - open override func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() if _autoConstant && !_isAdapted { _originalConstant = self.constant diff --git a/Sources/STUIKit/STView/STLiquidGlassView.swift b/Sources/STUIKit/STView/STLiquidGlassView.swift index 8bf2911..bf3478d 100644 --- a/Sources/STUIKit/STView/STLiquidGlassView.swift +++ b/Sources/STUIKit/STView/STLiquidGlassView.swift @@ -5,8 +5,8 @@ // Created by 寒江孤影 on 2026/4/27. // -import UIKit import ObjectiveC +import UIKit @IBDesignable open class STLiquidGlassView: UIView { @@ -50,7 +50,7 @@ open class STLiquidGlassView: UIView { private let highlightLayer = CAGradientLayer() private let borderLayer = CAShapeLayer() - public override init(frame: CGRect) { + override public init(frame: CGRect) { self.effectView = STLiquidGlassView.makeEffectView() super.init(frame: frame) self.setupView() @@ -62,7 +62,7 @@ open class STLiquidGlassView: UIView { self.setupView() } - open override func layoutSubviews() { + override open func layoutSubviews() { super.layoutSubviews() self.effectView.frame = self.bounds self.updateLayerFrames() diff --git a/Sources/STUIKit/STView/STView.swift b/Sources/STUIKit/STView/STView.swift index bfd3f82..3a6e56a 100644 --- a/Sources/STUIKit/STView/STView.swift +++ b/Sources/STUIKit/STView/STView.swift @@ -127,7 +127,7 @@ open class STView: UIView { } } - open override func layoutSubviews() { + override open func layoutSubviews() { super.layoutSubviews() self.st_updateLiquidGlassCornerRadius() } @@ -332,7 +332,7 @@ public extension UIView { let animation = CAKeyframeAnimation(keyPath: "transform.translation.x") animation.timingFunction = CAMediaTimingFunction(name: .linear) animation.duration = duration - animation.values = [-intensity, intensity, -intensity, intensity, -intensity/2, intensity/2, -intensity/4, intensity/4, 0] + animation.values = [-intensity, intensity, -intensity, intensity, -intensity / 2, intensity / 2, -intensity / 4, intensity / 4, 0] layer.add(animation, forKey: "shake") DispatchQueue.main.asyncAfter(deadline: .now() + duration) { diff --git a/Sources/STUIKit/STWebView/STBaseWKViewController.swift b/Sources/STUIKit/STWebView/STBaseWKViewController.swift index fbeb8fc..01114b5 100644 --- a/Sources/STUIKit/STWebView/STBaseWKViewController.swift +++ b/Sources/STUIKit/STWebView/STBaseWKViewController.swift @@ -4,6 +4,7 @@ // // Created by 寒江孤影 on 2020/12/31. // + import WebKit import StoreKit @@ -55,8 +56,8 @@ public struct STWebViewConfig { var applicationNameForUserAgent: String? var customUserAgent: String? var websiteDataStore: WKWebsiteDataStore = .default() - var preferences: WKPreferences = WKPreferences() - var userContentController: WKUserContentController = WKUserContentController() + var preferences = WKPreferences() + var userContentController = WKUserContentController() public init(allowsInlineMediaPlayback: Bool = true, mediaTypesRequiringUserActionForPlayback: WKAudiovisualMediaTypes = [], @@ -97,7 +98,7 @@ public protocol STWebViewMessageHandler: AnyObject { open class STBaseWKViewController: STBaseViewController { open var webInfo: STWebInfo? - open var webViewConfig: STWebViewConfig = STWebViewConfig() + open var webViewConfig = STWebViewConfig() open var messageHandler: STWebViewMessageHandler? private var wkConfig: WKWebViewConfiguration? private var progressObserver: NSKeyValueObservation? @@ -117,7 +118,7 @@ open class STBaseWKViewController: STBaseViewController { self.webInfo = nil } - open override func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() self.st_setupWebView() self.st_setupUI() @@ -163,7 +164,7 @@ open class STBaseWKViewController: STBaseViewController { self.wkWebView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), self.wkWebView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), self.wkWebView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), - self.wkWebView.topAnchor.constraint(equalTo: self.contentTopAnchor), + self.wkWebView.topAnchor.constraint(equalTo: self.contentTopAnchor) ]) } @@ -222,8 +223,8 @@ open class STBaseWKViewController: STBaseViewController { private func st_setupProgressView() { self.view.addSubview(self.progressView) self.view.addConstraints([ - NSLayoutConstraint.init(item: self.progressView, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1, constant: 0), - NSLayoutConstraint.init(item: self.progressView, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.progressView, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1, constant: 0), + NSLayoutConstraint(item: self.progressView, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1, constant: 0) ]) self.st_addProgressObserver() } @@ -512,7 +513,7 @@ extension STBaseWKViewController: WKUIDelegate, WKNavigationDelegate, WKScriptMe } private func st_updateTitle() { - self.wkWebView.evaluateJavaScript("document.title") { [weak self] result, error in + self.wkWebView.evaluateJavaScript("document.title") { [weak self] result, _ in guard let self = self else { return } if let text = result as? String, !text.isEmpty { self.st_setTitle(text) From 4efb90d131da4669ac2111e32801a368da804c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AF=92=E6=B1=9F=E5=AD=A4=E5=BD=B1?= Date: Thu, 13 Aug 2026 15:59:34 +0800 Subject: [PATCH 6/8] =?UTF-8?q?refactor:=20=E6=B6=88=E9=99=A4=E5=BC=BA?= =?UTF-8?q?=E5=88=B6=E8=A7=A3=E5=8C=85=E5=B9=B6=E7=BB=9F=E4=B8=80=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E8=AF=AD=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将仅作命名空间的结构体改为枚举,防止实例化 - 将约束属性改为可选并在激活时 compactMap - 重构 STHTTPSession 生命周期,支持惰性重建并修复循环引用 - 为父类 IUO 重写属性添加 swiftlint 豁免 - 调整属性 getter/setter 顺序与冗余 rawValue --- Sources/STBaseView/STBaseView.swift | 10 ++-- Sources/STHUD/STAlertController.swift | 12 ++-- Sources/STMedia/STImage.swift | 16 +++--- Sources/STNetwork/STHTTPSession.swift | 47 +++++++++++++--- Sources/STSecurity/STEncrypt.swift | 2 +- Sources/STSecurity/STKeychainHelper.swift | 2 +- Sources/STSecurity/STSecurityModels.swift | 8 +-- Sources/STTimer/STTimeProfiler.swift | 20 +++---- Sources/STTools/STData.swift | 2 +- Sources/STTools/STDeviceInfo.swift | 26 ++++----- .../STBottomSheetViewController.swift | 56 ++++++++++++------- Sources/STUIKit/STButton/STBtn.swift | 20 +++---- Sources/STUIKit/STLabel/STLabel.swift | 20 +++---- Sources/STUIKit/STLabel/STShimmerLabel.swift | 1 + .../STTabBar/STTabBarMixedSupport.swift | 2 +- Sources/STUIKit/STTextField/STTextField.swift | 2 +- .../STTextView/STPlaceholderTextView.swift | 4 +- Sources/STUIKit/STView/STIBInspectable.swift | 44 +++++++-------- .../STUIKit/STView/STLiquidGlassView.swift | 2 +- Sources/STUIKit/STView/STView.swift | 18 +++--- .../STWebView/STBaseWKViewController.swift | 5 ++ 21 files changed, 187 insertions(+), 132 deletions(-) diff --git a/Sources/STBaseView/STBaseView.swift b/Sources/STBaseView/STBaseView.swift index 82d8ab1..b5a5563 100644 --- a/Sources/STBaseView/STBaseView.swift +++ b/Sources/STBaseView/STBaseView.swift @@ -639,10 +639,10 @@ open class STSection: UIView { } private let stackView: UIStackView // 持有 stackView 的 4 条边约束引用,便于改 inset 时直接改 constant,避免约束泄漏 - private var topConstraint: NSLayoutConstraint! - private var leadingConstraint: NSLayoutConstraint! - private var trailingConstraint: NSLayoutConstraint! - private var bottomConstraint: NSLayoutConstraint! + private var topConstraint: NSLayoutConstraint? + private var leadingConstraint: NSLayoutConstraint? + private var trailingConstraint: NSLayoutConstraint? + private var bottomConstraint: NSLayoutConstraint? public init(inset: UIEdgeInsets = .zero, spacing: CGFloat = 0) { self.inset = inset @@ -673,7 +673,7 @@ open class STSection: UIView { self.leadingConstraint = self.stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: self.inset.left) self.trailingConstraint = self.stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -self.inset.right) self.bottomConstraint = self.stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -self.inset.bottom) - NSLayoutConstraint.activate([self.topConstraint, self.leadingConstraint, self.trailingConstraint, self.bottomConstraint]) + NSLayoutConstraint.activate([self.topConstraint, self.leadingConstraint, self.trailingConstraint, self.bottomConstraint].compactMap { $0 }) } /// Add multiple views (arranged) to this section (chainable) diff --git a/Sources/STHUD/STAlertController.swift b/Sources/STHUD/STAlertController.swift index 55d6b6f..386d82e 100644 --- a/Sources/STHUD/STAlertController.swift +++ b/Sources/STHUD/STAlertController.swift @@ -46,7 +46,7 @@ public struct STAlertActionItem { } // MARK: - 布局常量 -private struct STAlertLayoutConstant { +private enum STAlertLayoutConstant { static let alertWidth: CGFloat = 270 static let buttonHeight: CGFloat = 44 static let separatorHeight: CGFloat = 0.5 @@ -91,7 +91,7 @@ public struct STAlertInfo { open class STAlertController: UIViewController { private var isPresented: Bool = false - private var newConstraint: NSLayoutConstraint! + private var newConstraint: NSLayoutConstraint? private var backgroundColor = UIColor.white private var alertInfo = STAlertInfo() private var actionItems: [STAlertActionItem] = [] @@ -240,14 +240,14 @@ open class STAlertController: UIViewController { NSLayoutConstraint(item: self.alertView, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1, constant: 0), NSLayoutConstraint(item: self.alertView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.alertWidth), self.newConstraint - ]) + ].compactMap { $0 }) } else { self.view.addConstraints([ NSLayoutConstraint(item: self.alertView, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0), NSLayoutConstraint(item: self.alertView, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: 0), NSLayoutConstraint(item: self.alertView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: STAlertLayoutConstant.alertWidth), self.newConstraint - ]) + ].compactMap { $0 }) } if self.alertInfo.title.text != "" && self.alertInfo.message.text != "" { @@ -421,9 +421,9 @@ open class STAlertController: UIViewController { } self.view.layoutIfNeeded() if self.alertInfo.message.text != "" { - self.newConstraint.constant = self.messageLabel.frame.maxY + 54 + self.newConstraint?.constant = self.messageLabel.frame.maxY + 54 } else if self.alertInfo.title.text != "" { - self.newConstraint.constant = self.titleLabel.frame.maxY + 54 + self.newConstraint?.constant = self.titleLabel.frame.maxY + 54 } UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() diff --git a/Sources/STMedia/STImage.swift b/Sources/STMedia/STImage.swift index 88ae2c8..b190d43 100644 --- a/Sources/STMedia/STImage.swift +++ b/Sources/STMedia/STImage.swift @@ -20,14 +20,14 @@ public enum STImageError: LocalizedError { } public enum STImageFormat: String, CaseIterable { - case png = "png" - case gif = "gif" - case jpeg = "jpeg" - case tiff = "tiff" - case webp = "webp" - case heic = "heic" - case heif = "heif" - case undefined = "undefined" + case png + case gif + case jpeg + case tiff + case webp + case heic + case heif + case undefined public var mimeType: String { return "image/\(rawValue)" } public var fileExtension: String { return rawValue } diff --git a/Sources/STNetwork/STHTTPSession.swift b/Sources/STNetwork/STHTTPSession.swift index 77bc4e8..c18cb84 100644 --- a/Sources/STNetwork/STHTTPSession.swift +++ b/Sources/STNetwork/STHTTPSession.swift @@ -10,7 +10,7 @@ import Foundation import Network import UIKit -public final class STParameterEncoder { +public enum STParameterEncoder { public enum EncodingType { case url @@ -126,7 +126,11 @@ open class STHTTPSession: NSObject { public let interceptor: STInterceptor? public let eventMonitor: STCompositeEventMonitor - private var urlSession: URLSession! + private let urlSessionConfiguration: URLSessionConfiguration + /// 底层 URLSession。init 中立即创建,避免 deinit 触发 lazy 初始化时把正在析构的 + /// self 注册为新 session 的 delegate(生命周期逃逸)。使用 Optional 存储: + /// st_invalidate() 后置 nil,下次请求经 session 访问器惰性重建。 + private var urlSession: URLSession? private let delegateQueue: OperationQueue private let stateLock = NSLock() private var requestsByTaskID: [Int: STRequest] = [:] @@ -156,6 +160,7 @@ open class STHTTPSession: NSObject { eventMonitors: [STEventMonitor] = [], sslPinningConfig: STSSLPinningConfig = STSSLPinningConfig(enabled: false) ) { + self.urlSessionConfiguration = configuration self.defaultRequestConfig = defaultRequestConfig self.defaultRequestHeaders = defaultRequestHeaders self.interceptor = interceptor @@ -177,11 +182,35 @@ open class STHTTPSession: NSObject { self.delegateQueue = queue super.init() - self.urlSession = URLSession(configuration: configuration, delegate: self, delegateQueue: self.delegateQueue) + self.urlSession = URLSession(configuration: self.urlSessionConfiguration, delegate: self, delegateQueue: self.delegateQueue) } deinit { - self.urlSession.invalidateAndCancel() + // 直接读取 Optional 存储,避免析构期触发 session 访问器的惰性重建。 + self.urlSession?.invalidateAndCancel() + } + + /// 返回当前可用的 URLSession;若已被 st_invalidate() 销毁则重建。 + /// 读取/创建/赋值与 st_invalidate() 经 stateLock 互斥,避免并发首次重建 + /// 产生多个 session,或取得刚被置空的旧 session。 + private var session: URLSession { + self.withStateLock { + if let session = self.urlSession { + return session + } + let session = URLSession(configuration: self.urlSessionConfiguration, delegate: self, delegateQueue: self.delegateQueue) + self.urlSession = session + return session + } + } + + /// 显式销毁底层 URLSession 并释放其对 self 的 delegate 强引用, + /// 打破 self ⇄ session 循环引用。调用后再次发起请求会重建一个新的 session。 + public func st_invalidate() { + self.withStateLock { + self.urlSession?.invalidateAndCancel() + self.urlSession = nil + } } @discardableResult @@ -370,7 +399,7 @@ open class STHTTPSession: NSObject { } request.urlRequest = adapted - let task = self.urlSession.dataTask(with: adapted) + let task = self.session.dataTask(with: adapted) request.task = task let restart: () -> Void = { [weak self] in Task { await self?.executeData(request, initial: initial, interceptor: interceptor, config: config) } @@ -428,7 +457,7 @@ open class STHTTPSession: NSObject { } request.urlRequest = adapted - let task = self.urlSession.uploadTask(with: adapted, from: body) + let task = self.session.uploadTask(with: adapted, from: body) request.task = task let restart: () -> Void = { [weak self] in Task { await self?.executeUpload(request, initial: initial, body: body, interceptor: interceptor, config: config) } @@ -483,9 +512,9 @@ open class STHTTPSession: NSObject { let task: URLSessionDownloadTask if let resumeData = resumeData { - task = self.urlSession.downloadTask(withResumeData: resumeData) + task = self.session.downloadTask(withResumeData: resumeData) } else { - task = self.urlSession.downloadTask(with: adapted) + task = self.session.downloadTask(with: adapted) } request.task = task let restart: () -> Void = { [weak self, weak request] in @@ -542,7 +571,7 @@ open class STHTTPSession: NSObject { } request.urlRequest = adapted - let task = self.urlSession.dataTask(with: adapted) + let task = self.session.dataTask(with: adapted) request.task = task let restart: () -> Void = { [weak self, weak request] in Task { diff --git a/Sources/STSecurity/STEncrypt.swift b/Sources/STSecurity/STEncrypt.swift index aab245d..564ccf9 100644 --- a/Sources/STSecurity/STEncrypt.swift +++ b/Sources/STSecurity/STEncrypt.swift @@ -280,7 +280,7 @@ public extension Data { } // MARK: - 加密工具类 -public struct STEncryptionUtils { +public enum STEncryptionUtils { /// 生成随机密钥 /// - Parameter length: 密钥长度(字节) diff --git a/Sources/STSecurity/STKeychainHelper.swift b/Sources/STSecurity/STKeychainHelper.swift index 5fb56ce..ec8c9ae 100644 --- a/Sources/STSecurity/STKeychainHelper.swift +++ b/Sources/STSecurity/STKeychainHelper.swift @@ -114,7 +114,7 @@ public enum STKeychainError: Error, LocalizedError { } } -public class STKeychainHelper { +public enum STKeychainHelper { private static let service = Bundle.main.bundleIdentifier ?? "com.STBaseProject.app" private static let accessGroup: String? = nil // 可以设置为 App Group 标识符 diff --git a/Sources/STSecurity/STSecurityModels.swift b/Sources/STSecurity/STSecurityModels.swift index 1cd8a6c..2d8fe44 100644 --- a/Sources/STSecurity/STSecurityModels.swift +++ b/Sources/STSecurity/STSecurityModels.swift @@ -138,8 +138,8 @@ public enum STSecurityIssue: String, Codable { // MARK: - 安全严重程度 public enum STSecuritySeverity: String, Codable { - case low = "low" - case medium = "medium" - case high = "high" - case critical = "critical" + case low + case medium + case high + case critical } diff --git a/Sources/STTimer/STTimeProfiler.swift b/Sources/STTimer/STTimeProfiler.swift index 34367e7..fd3f5e3 100644 --- a/Sources/STTimer/STTimeProfiler.swift +++ b/Sources/STTimer/STTimeProfiler.swift @@ -8,14 +8,14 @@ import Foundation import QuartzCore -public class STTimeProfiler { +public enum STTimeProfiler { private static let lock = NSLock() private static var startTimes: [String: CFTimeInterval] = [:] /// 开始计时 /// - Parameter tag: 计时任务标识,用于区分不同的计时任务 - public class func st_start(tag: String = "default") { + public static func st_start(tag: String = "default") { self.lock.lock() defer { self.lock.unlock() } let startTime = CACurrentMediaTime() @@ -27,7 +27,7 @@ public class STTimeProfiler { /// - Parameters: /// - tag: 计时任务标识,默认为 "default" /// - message: 自定义消息,会显示在耗时信息中 - public class func st_end(tag: String = "default", message: String? = nil) { + public static func st_end(tag: String = "default", message: String? = nil) { self.lock.lock() defer { self.lock.unlock() } guard let startTime = self.startTimes[tag] else { @@ -45,7 +45,7 @@ public class STTimeProfiler { /// 获取当前耗时(不结束计时) /// - Parameter tag: 计时任务标识,默认为 "default" /// - Returns: 耗时(秒),如果未找到开始时间则返回 nil - public class func st_elapsedTime(tag: String = "default") -> Double? { + public static func st_elapsedTime(tag: String = "default") -> Double? { self.lock.lock() defer { self.lock.unlock() } guard let startTime = self.startTimes[tag] else { @@ -59,7 +59,7 @@ public class STTimeProfiler { /// - Parameters: /// - tag: 计时任务标识,默认为 "default" /// - message: 自定义消息 - public class func st_logElapsed(tag: String = "default", message: String? = nil) { + public static func st_logElapsed(tag: String = "default", message: String? = nil) { guard let elapsed = self.st_elapsedTime(tag: tag) else { STLog("⚠️ [\(tag)] 未找到对应的开始时间,请先调用 st_start(tag:)") return @@ -76,7 +76,7 @@ public class STTimeProfiler { /// - block: 要执行的代码块 /// - Returns: 代码块的返回值 @discardableResult - public class func st_measure(tag: String = "default", message: String? = nil, block: () throws -> T) rethrows -> T { + public static func st_measure(tag: String = "default", message: String? = nil, block: () throws -> T) rethrows -> T { self.st_start(tag: tag) defer { self.st_end(tag: tag, message: message) @@ -89,7 +89,7 @@ public class STTimeProfiler { /// - tag: 计时任务标识,默认为 "default" /// - message: 自定义消息 /// - block: 要执行的异步代码块 - public class func st_measureAsync(tag: String = "default", message: String? = nil, block: @escaping () async throws -> Void) { + public static func st_measureAsync(tag: String = "default", message: String? = nil, block: @escaping () async throws -> Void) { self.st_start(tag: tag) Task { do { @@ -102,7 +102,7 @@ public class STTimeProfiler { } /// 清除所有计时任务 - public class func st_clearAll() { + public static func st_clearAll() { self.lock.lock() defer { self.lock.unlock() } self.startTimes.removeAll() @@ -111,7 +111,7 @@ public class STTimeProfiler { /// 清除指定标签的计时任务 /// - Parameter tag: 计时任务标识 - public class func st_clear(tag: String) { + public static func st_clear(tag: String) { self.lock.lock() defer { self.lock.unlock() } self.startTimes.removeValue(forKey: tag) @@ -121,7 +121,7 @@ public class STTimeProfiler { /// 格式化耗时显示 /// - Parameter duration: 耗时(秒) /// - Returns: 格式化后的字符串 - private class func st_formatDuration(_ duration: Double) -> String { + private static func st_formatDuration(_ duration: Double) -> String { if duration < 0.001 { // 小于1毫秒,显示微秒 return String(format: "%.2f μs", duration * 1_000_000) diff --git a/Sources/STTools/STData.swift b/Sources/STTools/STData.swift index 510c1ea..1001a85 100644 --- a/Sources/STTools/STData.swift +++ b/Sources/STTools/STData.swift @@ -401,7 +401,7 @@ public extension String { } -public struct STDataUtils { +public enum STDataUtils { /// 创建随机数据 /// - Parameter length: 数据长度 /// - Returns: 随机数据 diff --git a/Sources/STTools/STDeviceInfo.swift b/Sources/STTools/STDeviceInfo.swift index e0043cb..a44c214 100644 --- a/Sources/STTools/STDeviceInfo.swift +++ b/Sources/STTools/STDeviceInfo.swift @@ -10,7 +10,7 @@ import Network import SystemConfiguration import UIKit -public struct STDeviceInfo { +public enum STDeviceInfo { public struct STAppInfo: Sendable { public let version: String @@ -592,24 +592,24 @@ public enum STDeviceType: String, Sendable { } public enum STNetworkConnectionType: String, Sendable { - case wifi = "wifi" - case cellular = "cellular" - case ethernet = "ethernet" - case unknown = "unknown" + case wifi + case cellular + case ethernet + case unknown } public enum STDevicePerformanceLevel: String, Sendable { - case low = "low" - case medium = "medium" - case high = "high" + case low + case medium + case high } public enum STThermalState: String, Sendable { - case nominal = "nominal" - case fair = "fair" - case serious = "serious" - case critical = "critical" - case unknown = "unknown" + case nominal + case fair + case serious + case critical + case unknown fileprivate init(_ state: ProcessInfo.ThermalState) { switch state { diff --git a/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift b/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift index b15a953..26af693 100644 --- a/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift +++ b/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift @@ -57,7 +57,25 @@ open class STBottomSheetViewController: UIViewController { return nil } - private var containerTopConstraint: NSLayoutConstraint! + private var containerTopConstraint: NSLayoutConstraint? + + /// setupContentView() 建立的容器顶部约束;访问前确保视图已加载。 + /// 公开入口(snapToPreferredHeight() 等)若在视图加载前被调用,直接以 0 + /// 参与手势/动画距离判断会产生静默错误吸附,因此这里强制加载视图并校验不变量。 + private var sheetTopConstraint: NSLayoutConstraint { + if let constraint = self.containerTopConstraint { + return constraint + } + // 视图尚未加载(公开入口在 loadView 前被调用)属正常状态:先强制加载视图, + // viewDidLoad 会调用 setupContentView() 建立约束。若加载后仍未建立,才是不变量破坏。 + // 注意不能在加载前调用 assertionFailure(),否则 Debug 下会直接终止、跳过视图加载, + // 造成 Debug/Release 行为不一致。 + _ = self.view + guard let constraint = self.containerTopConstraint else { + fatalError("STBottomSheetViewController: 视图加载后 containerTopConstraint 仍未建立,请检查 setupContentView()") + } + return constraint + } private var containerHeight: CGFloat { let height = self.view.bounds.height @@ -91,7 +109,7 @@ open class STBottomSheetViewController: UIViewController { private let fullOffsetTolerance: CGFloat = 24 private var isFullScreen: Bool { - return abs(self.containerTopConstraint.constant - self.fullOffset) < self.fullOffsetTolerance + return abs(self.sheetTopConstraint.constant - self.fullOffset) < self.fullOffsetTolerance } override open func loadView() { @@ -107,13 +125,13 @@ open class STBottomSheetViewController: UIViewController { self.setupContentView() self.setupPanGesture() self.setupContent() - self.containerTopConstraint.constant = self.hiddenOffset + self.sheetTopConstraint.constant = self.hiddenOffset } override open func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() - if self.containerTopConstraint.constant > self.hiddenOffset { - self.containerTopConstraint.constant = self.hiddenOffset + if self.sheetTopConstraint.constant > self.hiddenOffset { + self.sheetTopConstraint.constant = self.hiddenOffset } } @@ -128,7 +146,7 @@ open class STBottomSheetViewController: UIViewController { } public func bottomSheetScrollViewDidScroll(_ scrollView: UIScrollView) { - let currentOffset = self.containerTopConstraint.constant + let currentOffset = self.sheetTopConstraint.constant if currentOffset > self.fullOffset + self.fullOffsetTolerance && scrollView.contentOffset.y > 0 { self.logScrollDiagnostics( event: "lockScrollBeforeFull", @@ -149,7 +167,7 @@ open class STBottomSheetViewController: UIViewController { // 无主动触摸时(isDragging=false)说明是上一次手势的橡皮筋惯性, // 同样不移动 sheet,只重置 contentOffset 吸收回弹。 if !self.isSheetPanning && scrollView.isDragging { - self.containerTopConstraint.constant -= scrollView.contentOffset.y + self.sheetTopConstraint.constant -= scrollView.contentOffset.y } scrollView.contentOffset = .zero } else { @@ -158,7 +176,7 @@ open class STBottomSheetViewController: UIViewController { // callback was triggered by our own reset inside pullDownFromTop — // snapping here would undo that movement and create an oscillation. if currentOffset > self.fullOffset && scrollView.contentOffset.y > 0 { - self.containerTopConstraint.constant = self.fullOffset + self.sheetTopConstraint.constant = self.fullOffset } self.logScrollDiagnostics( event: "scroll", @@ -172,18 +190,18 @@ open class STBottomSheetViewController: UIViewController { func prepareForPresentationTransition() { self.view.layoutIfNeeded() - self.containerTopConstraint.constant = self.hiddenOffset + self.sheetTopConstraint.constant = self.hiddenOffset self.view.layoutIfNeeded() } func finishPresentationWithoutAnimation() { self.view.layoutIfNeeded() - self.containerTopConstraint.constant = self.partialOffset + self.sheetTopConstraint.constant = self.partialOffset self.view.layoutIfNeeded() } func animatePresentationTransition(duration: TimeInterval, completion: @escaping () -> Void) { - self.containerTopConstraint.constant = self.partialOffset + self.sheetTopConstraint.constant = self.partialOffset UIView.animate( withDuration: duration, delay: 0, @@ -196,7 +214,7 @@ open class STBottomSheetViewController: UIViewController { } func animateDismissalTransition(duration: TimeInterval, completion: @escaping () -> Void) { - self.containerTopConstraint.constant = self.hiddenOffset + self.sheetTopConstraint.constant = self.hiddenOffset UIView.animate(withDuration: duration, delay: 0, options: .curveEaseIn, animations: { self.view.layoutIfNeeded() }, completion: { _ in @@ -215,7 +233,7 @@ open class STBottomSheetViewController: UIViewController { self.contentView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), self.contentView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), bottomConstraint - ]) + ].compactMap { $0 }) self.contentView.addSubview(self.indicatorView) NSLayoutConstraint.activate([ @@ -256,9 +274,9 @@ open class STBottomSheetViewController: UIViewController { gesture.setTranslation(.zero, in: self.view) return } - let newConstant = self.containerTopConstraint.constant + translation.y + let newConstant = self.sheetTopConstraint.constant + translation.y if newConstant >= self.fullOffset { - self.containerTopConstraint.constant = newConstant + self.sheetTopConstraint.constant = newConstant // Prevent scroll view rubber-band from doubling the sheet movement if newConstant > self.fullOffset { self.contentScrollView?.contentOffset = .zero @@ -280,7 +298,7 @@ open class STBottomSheetViewController: UIViewController { } private func finishPanGesture(velocity: CGPoint) { - let currentOffset = self.containerTopConstraint.constant + let currentOffset = self.sheetTopConstraint.constant self.logDiagnostics( "finishPan velocityY=\(self.diagnosticValue(velocity.y)) currentOffset=\(self.diagnosticValue(currentOffset)) fullOffset=\(self.diagnosticValue(self.fullOffset)) partialOffset=\(self.diagnosticValue(self.partialOffset)) hiddenOffset=\(self.diagnosticValue(self.hiddenOffset))" ) @@ -321,8 +339,8 @@ open class STBottomSheetViewController: UIViewController { } private func animateToOffset(_ offset: CGFloat, velocity: CGFloat = 0) { - let distance = abs(offset - self.containerTopConstraint.constant) - self.containerTopConstraint.constant = offset + let distance = abs(offset - self.sheetTopConstraint.constant) + self.sheetTopConstraint.constant = offset self.logDiagnostics( "animateToOffset target=\(self.diagnosticValue(offset)) fullOffset=\(self.diagnosticValue(self.fullOffset)) partialOffset=\(self.diagnosticValue(self.partialOffset)) hiddenOffset=\(self.diagnosticValue(self.hiddenOffset))" ) @@ -440,7 +458,7 @@ open class STBottomSheetViewController: UIViewController { event, gesture.state.rawValue, "\(self.isFullScreen)", - self.diagnosticValue(self.containerTopConstraint.constant), + self.diagnosticValue(self.sheetTopConstraint.constant), self.diagnosticValue(self.fullOffset), self.diagnosticValue(translation.y), self.diagnosticValue(velocity.y), diff --git a/Sources/STUIKit/STButton/STBtn.swift b/Sources/STUIKit/STButton/STBtn.swift index a0f6302..6edda91 100644 --- a/Sources/STUIKit/STButton/STBtn.swift +++ b/Sources/STUIKit/STButton/STBtn.swift @@ -7,7 +7,7 @@ import UIKit -private struct STBtnLocalizationKey { +private enum STBtnLocalizationKey { static var localizedTitleKey: UInt8 = 0 static var localizedSelectedTitleKey: UInt8 = 1 } @@ -123,24 +123,24 @@ open class STBtn: UIButton { } @IBInspectable open var borderWidth: CGFloat { - set { - self.layer.borderWidth = newValue - } get { return self.layer.borderWidth } + set { + self.layer.borderWidth = newValue + } } @IBInspectable open var cornerRadius: CGFloat { + get { + return self.layer.cornerRadius + } set { self.layer.cornerRadius = newValue self.updateGradientLayerCornerRadius() self.updateLiquidGlassCornerRadius() self.setNeedsUpdateConfiguration() } - get { - return self.layer.cornerRadius - } } @IBInspectable open var clipsContentToBounds: Bool { @@ -153,13 +153,13 @@ open class STBtn: UIButton { } @IBInspectable open var borderColor: UIColor? { - set { - self.layer.borderColor = newValue?.cgColor - } get { guard let color = self.layer.borderColor else { return nil } return UIColor(cgColor: color) } + set { + self.layer.borderColor = newValue?.cgColor + } } /// 它只在开启时读取当前字号、用项目字体重建一个同字号的 `UIFont`,用于统一品牌字体。 diff --git a/Sources/STUIKit/STLabel/STLabel.swift b/Sources/STUIKit/STLabel/STLabel.swift index a7ae746..0b3cd1a 100644 --- a/Sources/STUIKit/STLabel/STLabel.swift +++ b/Sources/STUIKit/STLabel/STLabel.swift @@ -7,7 +7,7 @@ import UIKit -private struct STLabelLocalizationKey { +private enum STLabelLocalizationKey { static var localizedTextKey: UInt8 = 0 } @@ -68,13 +68,13 @@ open class STLabel: UILabel, STLocalizable { } @IBInspectable open var cornerRadius: CGFloat { + get { + return layer.cornerRadius + } set { self.layer.cornerRadius = newValue self.st_updateLiquidGlassCornerRadius() } - get { - return layer.cornerRadius - } } @IBInspectable open var clipsContentToBounds: Bool { @@ -87,22 +87,22 @@ open class STLabel: UILabel, STLocalizable { } @IBInspectable open var borderWidth: CGFloat { - set { - self.layer.borderWidth = newValue > 0 ? newValue : 0 - } get { return layer.borderWidth } + set { + self.layer.borderWidth = newValue > 0 ? newValue : 0 + } } @IBInspectable open var borderColor: UIColor? { - set { - self.layer.borderColor = newValue?.cgColor - } get { guard let color = self.layer.borderColor else { return nil } return UIColor(cgColor: color) } + set { + self.layer.borderColor = newValue?.cgColor + } } @IBInspectable open var isLiquidGlassEnabled: Bool = false { diff --git a/Sources/STUIKit/STLabel/STShimmerLabel.swift b/Sources/STUIKit/STLabel/STShimmerLabel.swift index 2f55ff5..d530f45 100644 --- a/Sources/STUIKit/STLabel/STShimmerLabel.swift +++ b/Sources/STUIKit/STLabel/STShimmerLabel.swift @@ -41,6 +41,7 @@ public class STShimmerLabel: STLabel { didSet { self.updateTextMask() } } + // swiftlint:disable:next implicitly_unwrapped_optional // UILabel 父类签名 override public var font: UIFont! { didSet { self.updateTextMask() } } diff --git a/Sources/STUIKit/STTabBar/STTabBarMixedSupport.swift b/Sources/STUIKit/STTabBar/STTabBarMixedSupport.swift index 6cff647..c7d8218 100644 --- a/Sources/STUIKit/STTabBar/STTabBarMixedSupport.swift +++ b/Sources/STUIKit/STTabBar/STTabBarMixedSupport.swift @@ -9,7 +9,7 @@ import UIKit // MARK: - 混合 TabBar 支持 /// 支持系统 UITabBarItem 和自定义 STTabBarItemModel 混用的工具类 -public class STTabBarMixedSupport { +public enum STTabBarMixedSupport { /// 混合 TabBar Item 类型 public enum MixedTabBarItem { diff --git a/Sources/STUIKit/STTextField/STTextField.swift b/Sources/STUIKit/STTextField/STTextField.swift index 9d4c4fb..a00cc96 100644 --- a/Sources/STUIKit/STTextField/STTextField.swift +++ b/Sources/STUIKit/STTextField/STTextField.swift @@ -7,7 +7,7 @@ import UIKit -private struct STTextFieldLocalizationKey { +private enum STTextFieldLocalizationKey { static var localizedPlaceholderKey: UInt8 = 0 } diff --git a/Sources/STUIKit/STTextView/STPlaceholderTextView.swift b/Sources/STUIKit/STTextView/STPlaceholderTextView.swift index 6d8ca62..10bd94f 100644 --- a/Sources/STUIKit/STTextView/STPlaceholderTextView.swift +++ b/Sources/STUIKit/STTextView/STPlaceholderTextView.swift @@ -7,7 +7,7 @@ import UIKit -private struct STPlaceholderTextViewLocalizationKey { +private enum STPlaceholderTextViewLocalizationKey { static var localizedPlaceholderKey: UInt8 = 0 } @@ -131,6 +131,7 @@ open class STPlaceholderTextView: UITextView { } } + // swiftlint:disable:next implicitly_unwrapped_optional // UITextView 父类签名 override open var text: String! { didSet { self.updatePlaceholderVisibility() @@ -138,6 +139,7 @@ open class STPlaceholderTextView: UITextView { } } + // swiftlint:disable:next implicitly_unwrapped_optional // UITextView 父类签名 override open var attributedText: NSAttributedString! { didSet { self.updatePlaceholderVisibility() diff --git a/Sources/STUIKit/STView/STIBInspectable.swift b/Sources/STUIKit/STView/STIBInspectable.swift index 2c987c9..3263d15 100644 --- a/Sources/STUIKit/STView/STIBInspectable.swift +++ b/Sources/STUIKit/STView/STIBInspectable.swift @@ -20,7 +20,7 @@ public enum STConstraintAdaptType { extension NSLayoutConstraint { - private struct AssociatedKeys { + private enum AssociatedKeys { static var autoConstantKey: UInt8 = 0 static var adaptTypeKey: UInt8 = 1 static var originalConstantKey: UInt8 = 2 @@ -71,6 +71,9 @@ extension NSLayoutConstraint { /// 是否启用自动适配(IBInspectable) @IBInspectable open var autoConstant: Bool { + get { + return _autoConstant + } set { _autoConstant = newValue if newValue && !_isAdapted { @@ -81,13 +84,21 @@ extension NSLayoutConstraint { _isAdapted = false } } - get { - return _autoConstant - } } /// 适配类型(IBInspectable) @IBInspectable open var adaptType: Int { + get { + switch _adaptType { + case .width: return 0 + case .height: return 1 + case .both: return 2 + case .spacing: return 3 + case .margin: return 4 + case .fontSize: return 5 + case .custom: return 2 + } + } set { let type: STConstraintAdaptType switch newValue { @@ -104,21 +115,16 @@ extension NSLayoutConstraint { self.adaptConstraintIfNeeded() } } - get { - switch _adaptType { - case .width: return 0 - case .height: return 1 - case .both: return 2 - case .spacing: return 3 - case .margin: return 4 - case .fontSize: return 5 - case .custom: return 2 - } - } } /// 自定义适配比例(IBInspectable) @IBInspectable open var customAdaptRatio: CGFloat { + get { + if case .custom(let ratio) = _adaptType { + return ratio + } + return 1.0 + } set { _adaptType = .custom(newValue) @@ -126,12 +132,6 @@ extension NSLayoutConstraint { self.adaptConstraintIfNeeded() } } - get { - if case .custom(let ratio) = _adaptType { - return ratio - } - return 1.0 - } } /// 执行约束适配 @@ -202,7 +202,7 @@ extension NSLayoutConstraint { } // MARK: - 批量约束适配工具 -public struct STConstraintAdapter { +public enum STConstraintAdapter { /// 批量适配约束 /// - Parameter constraints: 约束数组 diff --git a/Sources/STUIKit/STView/STLiquidGlassView.swift b/Sources/STUIKit/STView/STLiquidGlassView.swift index bf3478d..4efb1df 100644 --- a/Sources/STUIKit/STView/STLiquidGlassView.swift +++ b/Sources/STUIKit/STView/STLiquidGlassView.swift @@ -135,7 +135,7 @@ open class STLiquidGlassView: UIView { } } -private struct STLiquidGlassAssociationKey { +private enum STLiquidGlassAssociationKey { static var viewKey: UInt8 = 0 } diff --git a/Sources/STUIKit/STView/STView.swift b/Sources/STUIKit/STView/STView.swift index 3a6e56a..65cca19 100644 --- a/Sources/STUIKit/STView/STView.swift +++ b/Sources/STUIKit/STView/STView.swift @@ -62,13 +62,13 @@ public struct STGradientConfig { open class STView: UIView { @IBInspectable open var cornerRadius: CGFloat { + get { + return self.layer.cornerRadius + } set { self.layer.cornerRadius = newValue self.st_updateLiquidGlassCornerRadius() } - get { - return self.layer.cornerRadius - } } @IBInspectable open var clipsContentToBounds: Bool { @@ -81,22 +81,22 @@ open class STView: UIView { } @IBInspectable open var borderWidth: CGFloat { - set { - self.layer.borderWidth = newValue > 0 ? newValue : 0 - } get { return self.layer.borderWidth } + set { + self.layer.borderWidth = newValue > 0 ? newValue : 0 + } } @IBInspectable open var borderColor: UIColor? { - set { - self.layer.borderColor = newValue?.cgColor - } get { guard let color = self.layer.borderColor else { return nil } return UIColor(cgColor: color) } + set { + self.layer.borderColor = newValue?.cgColor + } } @IBInspectable open var isLiquidGlassEnabled: Bool = false { diff --git a/Sources/STUIKit/STWebView/STBaseWKViewController.swift b/Sources/STUIKit/STWebView/STBaseWKViewController.swift index 01114b5..8d3a4c3 100644 --- a/Sources/STUIKit/STWebView/STBaseWKViewController.swift +++ b/Sources/STUIKit/STWebView/STBaseWKViewController.swift @@ -444,25 +444,30 @@ open class STBaseWKViewController: STBaseViewController { } extension STBaseWKViewController: WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler { + // swiftlint:disable:next implicitly_unwrapped_optional // WKNavigationDelegate 协议签名 open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { self.st_updateLoadState(.loading) } + // swiftlint:disable:next implicitly_unwrapped_optional // WKNavigationDelegate 协议签名 open func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { self.st_updateLoadState(.loading) self.st_updateTitle() } + // swiftlint:disable:next implicitly_unwrapped_optional // WKNavigationDelegate 协议签名 open func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { self.st_updateLoadState(.loaded) self.st_updateTitle() } + // swiftlint:disable:next implicitly_unwrapped_optional // WKNavigationDelegate 协议签名 open func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { self.st_handleLoadError(error) self.st_updateTitle() } + // swiftlint:disable:next implicitly_unwrapped_optional // WKNavigationDelegate 协议签名 open func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { self.st_handleLoadError(error) } From 1919d99bf77c83556ff9b55a655f4626e2e64b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AF=92=E6=B1=9F=E5=AD=A4=E5=BD=B1?= Date: Thu, 13 Aug 2026 16:41:01 +0800 Subject: [PATCH 7/8] =?UTF-8?q?ci(swiftlint):=20=E5=90=AF=E7=94=A8=20--str?= =?UTF-8?q?ict=20=E5=B9=B6=E6=B8=85=E7=90=86=E8=A7=84=E5=88=99=E8=B1=81?= =?UTF-8?q?=E5=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/swift.yml | 14 ++++++---- .swiftlint.yml | 23 +++++++++------ Sources/STBaseModel/STBaseModel.swift | 12 ++++---- Sources/STBaseView/STBaseView.swift | 5 +++- Sources/STHUD/STAlertController.swift | 11 ++++---- Sources/STHUD/STProgressHUD.swift | 6 +--- Sources/STMedia/STScanView.swift | 28 +++++++++---------- Sources/STMedia/STScreenshot.swift | 2 +- Sources/STNetwork/STHTTPSession.swift | 9 ++---- Sources/STSecurity/STEncrypt.swift | 20 ++++++------- Sources/STTools/STDeviceAdapter.swift | 6 +--- Sources/STTools/STDictionary.swift | 6 ++-- Sources/STTools/STJSONValue.swift | 1 - .../STBottomSheetViewController.swift | 16 +++++++++-- .../STButton/STVerificationCodeBtn.swift | 2 +- Sources/STUIKit/STLabel/STShimmerLabel.swift | 1 - Sources/STUIKit/STLog/STLogManager.swift | 20 ++++++------- .../STUIKit/STTabBar/STTabBarItemView.swift | 5 ++-- .../STTabBar/STTabBarMixedSupport.swift | 12 +++----- .../STTextView/STPlaceholderTextView.swift | 2 -- .../STTextView/STShimmerTextView.swift | 15 +++++----- Sources/STUIKit/STView/STIBInspectable.swift | 6 ++-- Sources/STUIKit/STView/STView.swift | 20 ++++++------- .../STWebView/STBaseWKViewController.swift | 11 ++------ 24 files changed, 121 insertions(+), 132 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 2a6c180..2ae61d8 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -30,12 +30,14 @@ jobs: brew install swiftlint fi swiftlint version - # 不加 --strict:warning 不阻断 CI,仅 .swiftlint.yml 中明确为 error 级别的规则会失败构建。 - # 待存量 warning 清零后可改为 --strict 提升门槛。 - swiftlint --reporter github-actions-logging + # --strict:所有 warning 提升为 error。已清零规则(force_unwrapping、modifier_order、 + # convenience_type、computed_accessors_order 等)一旦回归即阻断构建。 + # missing_docs 存量未清零,已从 opt_in_rules 移入 disabled_rules(见 .swiftlint.yml), + # 补齐文档后恢复并继续由 --strict 守护。 + swiftlint --strict --reporter github-actions-logging - name: Resolve SPM dependencies - run: xcodebuild -resolvePackageDependencies -scheme STBaseProject-Package + run: xcodebuild -resolvePackageDependencies -scheme STBaseProject - name: Build (iOS Simulator) with compile log run: | @@ -43,7 +45,7 @@ jobs: # 不使用增量构建缓存,确保日志完整。 rm -rf ~/Library/Developer/Xcode/DerivedData xcodebuild \ - -scheme STBaseProject-Package \ + -scheme STBaseProject \ -destination 'generic/platform=iOS Simulator' \ clean build | tee xcodebuild.log @@ -51,7 +53,7 @@ jobs: run: | # analyzer_rules 仅在 `swiftlint analyze` 下执行;普通 `swiftlint lint` 不会跑。 # 需完整编译日志(上方 Build 步骤产出 xcodebuild.log)。 - swiftlint analyze \ + swiftlint analyze --strict \ --compiler-log-path xcodebuild.log \ --reporter github-actions-logging diff --git a/.swiftlint.yml b/.swiftlint.yml index 0c07674..d3a4694 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -25,8 +25,7 @@ disabled_rules: # 注意:line_length 是默认开启规则,不在 disabled_rules 中关闭, # 直接在下方 line_length: 配置块生效(置于 disabled_rules 会导致同名配置块被忽略) - force_try # 由 st_no_force_try_outside_markdown 精准限制,允许 STMarkdown 静态正则 - - blanket_disable_command # 基础库大量历史 disable 注释,不卡"禁用过多/需 re-enable"风格 - - superfluous_disable_command # 同上:保留历史 disable 豁免,不因区域内未触发而告警 + - missing_docs # 存量 882 个公开 API 缺文档,暂不纳入 --strict 门槛;文档补齐专项后再恢复 opt_in_rules opt_in_rules: - empty_count @@ -59,7 +58,7 @@ opt_in_rules: - redundant_string_enum_value - sorted_imports - toggle_bool - - missing_docs # ★ 公开 API 缺文档报警(先 warning 观察存量,后续可收紧) + - computed_accessors_order # === 公共基础库 Bug Prevention(第一批,低风险高价值)=== - weak_delegate # ★ delegate 必须为 weak,否则循环引用 - discarded_notification_center_observer # ★ block observer token 应被持有,便于按生命周期移除 @@ -74,11 +73,11 @@ analyzer_rules: - unused_import - unused_declaration -# 公开 API 文档缺失检查:先 warning 观察存量,待清零后可改为 error 收紧。 -# 仅检查 public 级别(open/internal/private 豁免),避免内部实现噪音。 -# CI 不使用 --strict,因此当前 warning 不阻断;使用 --strict 时会提升为 error。 -missing_docs: - warning: public +# 公开 API 文档缺失检查:存量 882 个未清零,暂移出 opt_in_rules(见 disabled_rules), +# 待文档补齐专项后再恢复并重新纳入 --strict 门槛。仅检查 public 级别。 +# 恢复方式:从 disabled_rules 移回 opt_in_rules,并重新启用下方配置块: +# missing_docs: +# warning: public # === 规则参数化 === line_length: @@ -113,6 +112,14 @@ nesting: # === 自定义规则 === custom_rules: + st_no_swiftlint_disable: + name: "SwiftLint disable comments are forbidden" + regex: 'swiftlint\s*:\s*disable(?:\s|:|$)' + match_kinds: + - comment + message: "禁止使用 swiftlint:disable 规避规则;请修复真实问题或调整项目级规则配置。" + severity: error + st_no_force_try_outside_markdown: name: "try! outside STMarkdown is forbidden" regex: '\\btry!' diff --git a/Sources/STBaseModel/STBaseModel.swift b/Sources/STBaseModel/STBaseModel.swift index 424f43f..f0c1e81 100644 --- a/Sources/STBaseModel/STBaseModel.swift +++ b/Sources/STBaseModel/STBaseModel.swift @@ -707,11 +707,9 @@ private struct STPropertyType { // attributes 形如:T@"NSString",&,N,V_name // 第一段以 'T' 开头,描述类型编码。 var typeEncoding = "" - for component in attributes.split(separator: ",") { - if component.first == "T" { - typeEncoding = String(component.dropFirst()) - break - } + for component in attributes.split(separator: ",") where component.first == "T" { + typeEncoding = String(component.dropFirst()) + break } self.kind = STPropertyType.parseKind(typeEncoding) switch self.kind { @@ -766,7 +764,7 @@ private struct STPropertyType { } } - /// 把传入值尝试转换为属性接受的形式;不兼容时返回 nil。 + // 把传入值尝试转换为属性接受的形式;不兼容时返回 nil。 func coerce(_ value: Any) -> Any? { switch kind { case .object(let className): @@ -799,7 +797,7 @@ private struct STPropertyType { return value } } - + private static func coerceObject(_ value: Any, expectedClassName: String?) -> Any? { guard let className = expectedClassName else { return value } let resolvedClass: AnyClass? = NSClassFromString(className) diff --git a/Sources/STBaseView/STBaseView.swift b/Sources/STBaseView/STBaseView.swift index b5a5563..f2f9ee7 100644 --- a/Sources/STBaseView/STBaseView.swift +++ b/Sources/STBaseView/STBaseView.swift @@ -572,7 +572,10 @@ extension STBaseView { self.tableViewStyle = style if self._tableView != nil, self._isInternallyCreatedTableView { #if DEBUG - assertionFailure("STBaseView.st_tableViewStyle(_:) called after the internal tableView was created. All table configuration (delegate/dataSource/cell registration/pull-to-refresh/load-more) will be lost and must be re-applied.") + assertionFailure( + "STBaseView.st_tableViewStyle(_:) called after the internal tableView was created. " + + "All table configuration (delegate/dataSource/cell registration/pull-to-refresh/load-more) will be lost and must be re-applied." + ) #endif self.st_removePullToRefresh() self.st_removeLoadMore() diff --git a/Sources/STHUD/STAlertController.swift b/Sources/STHUD/STAlertController.swift index 386d82e..bff6f2c 100644 --- a/Sources/STHUD/STAlertController.swift +++ b/Sources/STHUD/STAlertController.swift @@ -184,7 +184,6 @@ open class STAlertController: UIViewController { /// 是否在点击动作后自动关闭,默认 true @available(*, deprecated, renamed: "setAutoDismiss(_:)") - // swiftlint:disable:next st_avoid_bool_flag_param public func setAutoDismissOnAction(_ enabled: Bool) { self.autoDismissOnAction = enabled } @@ -250,7 +249,7 @@ open class STAlertController: UIViewController { ].compactMap { $0 }) } - if self.alertInfo.title.text != "" && self.alertInfo.message.text != "" { + if !self.alertInfo.title.text.isEmpty && !self.alertInfo.message.text.isEmpty { self.titleLabel.text = self.alertInfo.title.text self.messageLabel.text = self.alertInfo.message.text self.alertView.addSubview(self.titleLabel) @@ -265,7 +264,7 @@ open class STAlertController: UIViewController { NSLayoutConstraint(item: self.messageLabel, attribute: .left, relatedBy: .equal, toItem: self.titleLabel, attribute: .left, multiplier: 1, constant: STAlertLayoutConstant.contentHorizontal), NSLayoutConstraint(item: self.messageLabel, attribute: .right, relatedBy: .equal, toItem: self.titleLabel, attribute: .right, multiplier: 1, constant: -STAlertLayoutConstant.contentHorizontal) ]) - } else if self.alertInfo.title.text != "" && self.alertInfo.message.text == "" { + } else if !self.alertInfo.title.text.isEmpty && self.alertInfo.message.text.isEmpty { self.titleLabel.text = self.alertInfo.title.text self.alertView.addSubview(self.titleLabel) self.view.addConstraints([ @@ -273,7 +272,7 @@ open class STAlertController: UIViewController { NSLayoutConstraint(item: self.titleLabel, attribute: .left, relatedBy: .equal, toItem: self.alertView, attribute: .left, multiplier: 1, constant: STAlertLayoutConstant.contentHorizontal), NSLayoutConstraint(item: self.titleLabel, attribute: .right, relatedBy: .equal, toItem: self.alertView, attribute: .right, multiplier: 1, constant: -STAlertLayoutConstant.contentHorizontal) ]) - } else if self.alertInfo.title.text == "" && self.alertInfo.message.text != "" { + } else if self.alertInfo.title.text.isEmpty && !self.alertInfo.message.text.isEmpty { self.messageLabel.text = self.alertInfo.message.text self.alertView.addSubview(self.messageLabel) self.view.addConstraints([ @@ -420,9 +419,9 @@ open class STAlertController: UIViewController { ]) } self.view.layoutIfNeeded() - if self.alertInfo.message.text != "" { + if !self.alertInfo.message.text.isEmpty { self.newConstraint?.constant = self.messageLabel.frame.maxY + 54 - } else if self.alertInfo.title.text != "" { + } else if !self.alertInfo.title.text.isEmpty { self.newConstraint?.constant = self.titleLabel.frame.maxY + 54 } UIView.animate(withDuration: 0.3) { diff --git a/Sources/STHUD/STProgressHUD.swift b/Sources/STHUD/STProgressHUD.swift index 069ea90..68f51ca 100644 --- a/Sources/STHUD/STProgressHUD.swift +++ b/Sources/STHUD/STProgressHUD.swift @@ -172,7 +172,6 @@ public class STProgressHUD: UIView { @available(*, deprecated, renamed: "show(addedToView:animation:)") @discardableResult - // swiftlint:disable:next st_avoid_bool_flag_param public class func show(addedToView view: UIView, animated: Bool) -> STProgressHUD { return show(addedToView: view, animation: animated ? .fade : .none) } @@ -187,7 +186,6 @@ public class STProgressHUD: UIView { @available(*, deprecated, renamed: "hide(addedToView:animation:)") @discardableResult - // swiftlint:disable:next st_avoid_bool_flag_param public class func hide(addedToView view: UIView, animated: Bool) -> Bool { guard let hud = hudForView(view) else { return false } hud.removeFromSuperViewOnHide = true @@ -205,7 +203,6 @@ public class STProgressHUD: UIView { } @available(*, deprecated, renamed: "show(animation:)") - // swiftlint:disable:next st_avoid_bool_flag_param public func show(animated: Bool) { self.showCore(animated: animated) } @@ -216,7 +213,6 @@ public class STProgressHUD: UIView { } @available(*, deprecated, renamed: "hide(animation:)") - // swiftlint:disable:next st_avoid_bool_flag_param public func hide(animated: Bool) { self.hideCore(animated: animated) } @@ -226,7 +222,6 @@ public class STProgressHUD: UIView { } @available(*, deprecated, renamed: "hide(animation:afterDelay:)") - // swiftlint:disable:next st_avoid_bool_flag_param public func hide(animated: Bool, afterDelay delay: TimeInterval) { self.hideCore(animation: animated ? self.animationType.stHUDAnimation : .none, afterDelay: delay) } @@ -615,6 +610,7 @@ private extension STProgressHUD { func unregisterFromNotifications() { #if !os(tvOS) + // 与 registerForNotifications() 配对的注销方法,观察者生命周期由注册/注销配对管理。 NotificationCenter.default.removeObserver(self) #endif } diff --git a/Sources/STMedia/STScanView.swift b/Sources/STMedia/STScanView.swift index f202efe..15c41c7 100644 --- a/Sources/STMedia/STScanView.swift +++ b/Sources/STMedia/STScanView.swift @@ -275,20 +275,20 @@ public class STScanView: UIView { var newFrame = scanLineView.frame newFrame.origin.y = endY scanLineView.frame = newFrame - } - ) { [weak self] _ in - guard let self, !self.isAnimationStopped else { return } - UIView.animate(withDuration: 0.2, animations: { - scanLineView.alpha = 0 - }) { _ in - guard !self.isAnimationStopped else { return } - let item = DispatchWorkItem { [weak self] in - self?.startAnimation() - } - self.animationStartWorkItem = item - DispatchQueue.main.asyncAfter(deadline: .now() + self.configuration.animationInterval, execute: item) - } - } + }, + completion: { [weak self] _ in + guard let self, !self.isAnimationStopped else { return } + UIView.animate(withDuration: 0.2, animations: { + scanLineView.alpha = 0 + }, completion: { _ in + guard !self.isAnimationStopped else { return } + let item = DispatchWorkItem { [weak self] in + self?.startAnimation() + } + self.animationStartWorkItem = item + DispatchQueue.main.asyncAfter(deadline: .now() + self.configuration.animationInterval, execute: item) + }) + }) } private func stopAnimation() { diff --git a/Sources/STMedia/STScreenshot.swift b/Sources/STMedia/STScreenshot.swift index 5095afb..6361916 100644 --- a/Sources/STMedia/STScreenshot.swift +++ b/Sources/STMedia/STScreenshot.swift @@ -10,7 +10,7 @@ import UIKit public final class STScreenshot: NSObject { @MainActor - private class func captureData() -> Data { + private static func captureData() -> Data { guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return Data() } diff --git a/Sources/STNetwork/STHTTPSession.swift b/Sources/STNetwork/STHTTPSession.swift index c18cb84..d990a1f 100644 --- a/Sources/STNetwork/STHTTPSession.swift +++ b/Sources/STNetwork/STHTTPSession.swift @@ -679,7 +679,6 @@ open class STHTTPSession: NSObject { } // MARK: - 任务注册 - private func register( _ request: STRequest, task: URLSessionTask, @@ -842,11 +841,9 @@ extension STHTTPSession: URLSessionDelegate, URLSessionDataDelegate, URLSessionT let serverCertificates = self.serverCertificates(from: serverTrust) if hasCertificatePins { - for serverCertificate in serverCertificates { - if self.sslPinningConfig.certificates.contains(serverCertificate) { - completionHandler(.useCredential, URLCredential(trust: serverTrust)) - return - } + for serverCertificate in serverCertificates where self.sslPinningConfig.certificates.contains(serverCertificate) { + completionHandler(.useCredential, URLCredential(trust: serverTrust)) + return } } diff --git a/Sources/STSecurity/STEncrypt.swift b/Sources/STSecurity/STEncrypt.swift index 564ccf9..9bc0c74 100644 --- a/Sources/STSecurity/STEncrypt.swift +++ b/Sources/STSecurity/STEncrypt.swift @@ -85,11 +85,11 @@ public extension String { return st_hmac(key: key, algorithm: .sha512) } - /// AES-256-GCM 加密 - /// - Parameters: - /// - key: 密钥字符串 - /// - nonce: 随机数(可选,自动生成) - /// - Returns: 加密结果,包含密文、随机数和认证标签 + // AES-256-GCM 加密 + // - Parameters: + // - key: 密钥字符串 + // - nonce: 随机数(可选,自动生成) + // - Returns: 加密结果,包含密文、随机数和认证标签 func st_encryptAES256GCM(key: String, nonce: AES.GCM.Nonce? = nil) throws -> (ciphertext: Data, nonce: AES.GCM.Nonce, tag: Data) { let keyData = Data(key.utf8) guard keyData.count == 32 else { @@ -201,11 +201,11 @@ public extension Data { } } - /// AES-256-GCM 加密 - /// - Parameters: - /// - key: 密钥数据 - /// - nonce: 随机数(可选,自动生成) - /// - Returns: 加密结果,包含密文、随机数和认证标签 + // AES-256-GCM 加密 + // - Parameters: + // - key: 密钥数据 + // - nonce: 随机数(可选,自动生成) + // - Returns: 加密结果,包含密文、随机数和认证标签 func st_encryptAES256GCM(key: Data, nonce: AES.GCM.Nonce? = nil) throws -> (ciphertext: Data, nonce: AES.GCM.Nonce, tag: Data) { guard key.count == 32 else { throw STCryptoError.invalidKey diff --git a/Sources/STTools/STDeviceAdapter.swift b/Sources/STTools/STDeviceAdapter.swift index a4b769d..1fb0539 100644 --- a/Sources/STTools/STDeviceAdapter.swift +++ b/Sources/STTools/STDeviceAdapter.swift @@ -307,11 +307,7 @@ public final class STDeviceAdapter: STDeviceAdapting { @available(iOS, introduced: 13.0) private static var fallbackMainScreenBounds: CGRect { assertMainThread() - #if swift(>=5.9) - if #available(iOS 16.0, *) { - // 继续使用 UIScreen.main;Apple 并未提供无 scene 场景下的等价替代。 - } - #endif + // 无 scene 场景下 UIScreen.main 仍是唯一可用的屏幕尺寸来源。 return UIScreen.main.bounds } diff --git a/Sources/STTools/STDictionary.swift b/Sources/STTools/STDictionary.swift index 7da0dc6..4eff7d9 100644 --- a/Sources/STTools/STDictionary.swift +++ b/Sources/STTools/STDictionary.swift @@ -280,10 +280,8 @@ public extension Dictionary where Value: Equatable { differences[key] = value } } - for (key, value) in other { - if self[key] == nil { - differences[key] = value - } + for (key, value) in other where self[key] == nil { + differences[key] = value } return differences } diff --git a/Sources/STTools/STJSONValue.swift b/Sources/STTools/STJSONValue.swift index 007e30d..a116f93 100644 --- a/Sources/STTools/STJSONValue.swift +++ b/Sources/STTools/STJSONValue.swift @@ -96,7 +96,6 @@ public enum STJSONValue: Codable { } } - /// 获取布尔值 public var boolValue: Bool? { switch self { case .bool(let value): return value diff --git a/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift b/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift index 26af693..333ee61 100644 --- a/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift +++ b/Sources/STUIKit/STBottomSheet/STBottomSheetViewController.swift @@ -282,7 +282,10 @@ open class STBottomSheetViewController: UIViewController { self.contentScrollView?.contentOffset = .zero } self.logDiagnostics( - "sheetOffsetChanged translationY=\(self.diagnosticValue(translation.y)) velocityY=\(self.diagnosticValue(velocity.y)) newOffset=\(self.diagnosticValue(newConstant)) fullOffset=\(self.diagnosticValue(self.fullOffset))" + "sheetOffsetChanged translationY=\(self.diagnosticValue(translation.y)) " + + "velocityY=\(self.diagnosticValue(velocity.y)) " + + "newOffset=\(self.diagnosticValue(newConstant)) " + + "fullOffset=\(self.diagnosticValue(self.fullOffset))" ) gesture.setTranslation(.zero, in: self.view) } @@ -300,7 +303,11 @@ open class STBottomSheetViewController: UIViewController { private func finishPanGesture(velocity: CGPoint) { let currentOffset = self.sheetTopConstraint.constant self.logDiagnostics( - "finishPan velocityY=\(self.diagnosticValue(velocity.y)) currentOffset=\(self.diagnosticValue(currentOffset)) fullOffset=\(self.diagnosticValue(self.fullOffset)) partialOffset=\(self.diagnosticValue(self.partialOffset)) hiddenOffset=\(self.diagnosticValue(self.hiddenOffset))" + "finishPan velocityY=\(self.diagnosticValue(velocity.y)) " + + "currentOffset=\(self.diagnosticValue(currentOffset)) " + + "fullOffset=\(self.diagnosticValue(self.fullOffset)) " + + "partialOffset=\(self.diagnosticValue(self.partialOffset)) " + + "hiddenOffset=\(self.diagnosticValue(self.hiddenOffset))" ) if velocity.y > 600 { if currentOffset < self.partialOffset - 50 { @@ -342,7 +349,10 @@ open class STBottomSheetViewController: UIViewController { let distance = abs(offset - self.sheetTopConstraint.constant) self.sheetTopConstraint.constant = offset self.logDiagnostics( - "animateToOffset target=\(self.diagnosticValue(offset)) fullOffset=\(self.diagnosticValue(self.fullOffset)) partialOffset=\(self.diagnosticValue(self.partialOffset)) hiddenOffset=\(self.diagnosticValue(self.hiddenOffset))" + "animateToOffset target=\(self.diagnosticValue(offset)) " + + "fullOffset=\(self.diagnosticValue(self.fullOffset)) " + + "partialOffset=\(self.diagnosticValue(self.partialOffset)) " + + "hiddenOffset=\(self.diagnosticValue(self.hiddenOffset))" ) // 将手势速度归一化为 spring initialVelocity(单位:总位移/秒),上限 30 防止过度弹跳 let springVelocity: CGFloat = distance > 1 ? min(abs(velocity) / distance, 30) : 0 diff --git a/Sources/STUIKit/STButton/STVerificationCodeBtn.swift b/Sources/STUIKit/STButton/STVerificationCodeBtn.swift index 63a9f09..eb2f53c 100644 --- a/Sources/STUIKit/STButton/STVerificationCodeBtn.swift +++ b/Sources/STUIKit/STButton/STVerificationCodeBtn.swift @@ -19,7 +19,7 @@ open class STVerificationCodeBtn: STBtn { @IBInspectable open var titleSuffix: String = "" /// Countdown interval time - @IBInspectable open var interval: TimeInterval = 1 { + @IBInspectable open var interval: Double = 1 { didSet { guard self.interval <= 0 else { return } self.interval = oldValue > 0 ? oldValue : 1 diff --git a/Sources/STUIKit/STLabel/STShimmerLabel.swift b/Sources/STUIKit/STLabel/STShimmerLabel.swift index d530f45..2f55ff5 100644 --- a/Sources/STUIKit/STLabel/STShimmerLabel.swift +++ b/Sources/STUIKit/STLabel/STShimmerLabel.swift @@ -41,7 +41,6 @@ public class STShimmerLabel: STLabel { didSet { self.updateTextMask() } } - // swiftlint:disable:next implicitly_unwrapped_optional // UILabel 父类签名 override public var font: UIFont! { didSet { self.updateTextMask() } } diff --git a/Sources/STUIKit/STLog/STLogManager.swift b/Sources/STUIKit/STLog/STLogManager.swift index 1835056..7a945d4 100644 --- a/Sources/STUIKit/STLog/STLogManager.swift +++ b/Sources/STUIKit/STLog/STLogManager.swift @@ -160,7 +160,7 @@ public final class STLogManager { /// cloudBatchSize: 20 /// )) /// ``` - public class func bootstrap(_ configuration: Configuration) { + public static func bootstrap(_ configuration: Configuration) { self.mutateConfiguration { $0 = configuration } self.shared.queue.async { self.shared.rebuildHandlers() @@ -178,7 +178,7 @@ public final class STLogManager { /// ) /// STLogManager.setCloudTransport(transport) /// ``` - public class func setCloudTransport(_ transport: STLogCloudTransport?) { + public static func setCloudTransport(_ transport: STLogCloudTransport?) { self.mutateConfiguration { $0.cloudTransport = transport } self.shared.queue.async { self.shared.rebuildHandlers() @@ -186,7 +186,7 @@ public final class STLogManager { } /// 创建一个带默认 label / metadata 的 logger。 - public class func makeLogger(label: String, metadata: STLogger.Metadata = [:]) -> STLogger { + public static func makeLogger(label: String, metadata: STLogger.Metadata = [:]) -> STLogger { STLogger(label: label, metadata: metadata) } @@ -210,31 +210,31 @@ public final class STLogManager { } } - public class func flush() { + public static func flush() { self.shared.queue.async { self.shared.handlers.forEach { $0.flush() } } } /// 当前正在写入的活动日志文件路径。 - public class func logFilePath() -> String { + public static func logFilePath() -> String { STLogFileWriter.shared.activeFilePath } /// 当前文件和归档文件列表,按读取优先级返回。 - public class func allLogFilePaths() -> [String] { + public static func allLogFilePaths() -> [String] { STLogFileWriter.shared.allLogFilePaths() } /// 清空内存和本地持久化日志。 - public class func clearAllLogs() { + public static func clearAllLogs() { self.shared.queue.sync { self.shared.memoryBuffer.removeAll() STLogFileWriter.shared.clearAllLogs() } } - public class func recentRecords(limit: Int) -> [STLogRecord] { + public static func recentRecords(limit: Int) -> [STLogRecord] { let buffer = self.shared.queue.sync { self.shared.memoryBuffer.suffix(limit) } if buffer.count >= limit { return Array(Array(buffer).reversed()) @@ -242,7 +242,7 @@ public final class STLogManager { return STLogFileWriter.shared.fetchRecords(skip: 0, limit: limit) } - public class func records(page: Int, pageSize: Int, levels: Set? = nil, searchText: String? = nil) -> [STLogRecord] { + public static func records(page: Int, pageSize: Int, levels: Set? = nil, searchText: String? = nil) -> [STLogRecord] { let normalizedLevels = levels ?? Set(STLogLevel.allCases) let normalizedSearch = searchText?.trimmingCharacters(in: .whitespacesAndNewlines) let shouldSearch = !(normalizedSearch?.isEmpty ?? true) || normalizedLevels.count < STLogLevel.allCases.count @@ -260,7 +260,7 @@ public final class STLogManager { return STLogFileWriter.shared.fetchRecords(skip: skip, limit: pageSize) } - public class func hasMoreRecords(page: Int, pageSize: Int, levels: Set? = nil, searchText: String? = nil) -> Bool { + public static func hasMoreRecords(page: Int, pageSize: Int, levels: Set? = nil, searchText: String? = nil) -> Bool { !self.records(page: page + 1, pageSize: 1, levels: levels, searchText: searchText).isEmpty } diff --git a/Sources/STUIKit/STTabBar/STTabBarItemView.swift b/Sources/STUIKit/STTabBar/STTabBarItemView.swift index 1503379..443e1f0 100644 --- a/Sources/STUIKit/STTabBar/STTabBarItemView.swift +++ b/Sources/STUIKit/STTabBar/STTabBarItemView.swift @@ -186,7 +186,6 @@ public class STTabBarItemView: UIView { return max(1, min(configured, measured)) } - /// 将 `imageTopInset`、图标尺寸约束在可用高度内,避免 Auto Layout 无法同时满足 private func resolvedImageAndTextLayout(for model: STTabBarItemModel) -> (topInset: CGFloat, iconWidth: CGFloat, iconHeight: CGFloat) { let barH = self.effectiveBarHeightForImageTextLayout() let baseW = model.layout.imageSize?.width ?? 24 @@ -368,11 +367,11 @@ public class STTabBarItemView: UIView { self.alpha = selected ? 1.0 : config.unselectedAlpha self.titleLabel.textColor = selected ? model.colors.selectedText : model.colors.normalText self.backgroundColor = selected ? model.colors.selectedBackground : model.colors.normalBackground - }) { _ in + }, completion: { _ in UIView.transition(with: self.iconImageView, duration: 0.2, options: .transitionCrossDissolve) { self.iconImageView.image = selected ? model.selectedImage : model.normalImage } - } + }) } @objc private func handleTap() { diff --git a/Sources/STUIKit/STTabBar/STTabBarMixedSupport.swift b/Sources/STUIKit/STTabBar/STTabBarMixedSupport.swift index c7d8218..0420745 100644 --- a/Sources/STUIKit/STTabBar/STTabBarMixedSupport.swift +++ b/Sources/STUIKit/STTabBar/STTabBarMixedSupport.swift @@ -46,10 +46,8 @@ public enum STTabBarMixedSupport { tabBarController.setViewControllers(viewControllers, animated: false) // 如果有系统 TabBar Item,设置到对应的 ViewController - for (index, systemItem) in systemItems.enumerated() { - if index < viewControllers.count { - viewControllers[index].tabBarItem = systemItem - } + for (index, systemItem) in systemItems.enumerated() where index < viewControllers.count { + viewControllers[index].tabBarItem = systemItem } if !customItems.isEmpty { @@ -122,10 +120,8 @@ public extension STCustomTabBarController { self.setViewControllers(viewControllers, animated: false) - for (index, systemItem) in systemItems.enumerated() { - if index < viewControllers.count { - viewControllers[index].tabBarItem = systemItem - } + for (index, systemItem) in systemItems.enumerated() where index < viewControllers.count { + viewControllers[index].tabBarItem = systemItem } if !customItems.isEmpty { diff --git a/Sources/STUIKit/STTextView/STPlaceholderTextView.swift b/Sources/STUIKit/STTextView/STPlaceholderTextView.swift index 10bd94f..22d8912 100644 --- a/Sources/STUIKit/STTextView/STPlaceholderTextView.swift +++ b/Sources/STUIKit/STTextView/STPlaceholderTextView.swift @@ -131,7 +131,6 @@ open class STPlaceholderTextView: UITextView { } } - // swiftlint:disable:next implicitly_unwrapped_optional // UITextView 父类签名 override open var text: String! { didSet { self.updatePlaceholderVisibility() @@ -139,7 +138,6 @@ open class STPlaceholderTextView: UITextView { } } - // swiftlint:disable:next implicitly_unwrapped_optional // UITextView 父类签名 override open var attributedText: NSAttributedString! { didSet { self.updatePlaceholderVisibility() diff --git a/Sources/STUIKit/STTextView/STShimmerTextView.swift b/Sources/STUIKit/STTextView/STShimmerTextView.swift index f0a7a79..dcaa6bf 100644 --- a/Sources/STUIKit/STTextView/STShimmerTextView.swift +++ b/Sources/STUIKit/STTextView/STShimmerTextView.swift @@ -578,12 +578,12 @@ open class STShimmerTextView: UITextView { } } - /// 立即完成"当前行"之前所有行的 fade-in 动画。 - /// - /// 原则:_baseAttributedText 中最后一个 \n 之前的字符已属于已完成的行, - /// 它们的 animatingToken 应立即置为全不透明,不应继续半透明地悬挂在屏幕上。 - /// 调用时机:在每次 append 新字符 **之前**(_baseAttributedText 尚未追加新内容), - /// 以 _baseAttributedText 的当前末尾搜索最后一个换行符。 + // 立即完成"当前行"之前所有行的 fade-in 动画。 + // + // 原则:_baseAttributedText 中最后一个 \n 之前的字符已属于已完成的行, + // 它们的 animatingToken 应立即置为全不透明,不应继续半透明地悬挂在屏幕上。 + // 调用时机:在每次 append 新字符 **之前**(_baseAttributedText 尚未追加新内容), + // 以 _baseAttributedText 的当前末尾搜索最后一个换行符。 private func finishAnimationsBeforeLastNewline() { guard !self.animatingTokens.isEmpty else { return } let str = _baseAttributedText.string as NSString @@ -725,8 +725,7 @@ open class STShimmerTextView: UITextView { let glyphRange = self.layoutManager.glyphRange( forCharacterRange: changedRange, actualCharacterRange: nil ) - self.layoutManager.enumerateLineFragments(forGlyphRange: glyphRange) { [weak self] - rect, usedRect, _, lineGlyphRange, _ in + self.layoutManager.enumerateLineFragments(forGlyphRange: glyphRange) { [weak self] rect, usedRect, _, lineGlyphRange, _ in guard let self else { return } guard NSMaxRange(glyphRange) == NSMaxRange(lineGlyphRange) else { return } self.installLineFadeLayer(lineRect: rect, rightEdge: usedRect.maxX, mask: mask, base: base) diff --git a/Sources/STUIKit/STView/STIBInspectable.swift b/Sources/STUIKit/STView/STIBInspectable.swift index 3263d15..6fffad8 100644 --- a/Sources/STUIKit/STView/STIBInspectable.swift +++ b/Sources/STUIKit/STView/STIBInspectable.swift @@ -277,10 +277,8 @@ public extension UIView { /// 收集已适配的约束 private func collectAdaptedConstraintsRecursively(in view: UIView, result: inout [NSLayoutConstraint]) { - for constraint in view.constraints { - if constraint.hasAdaptiveConstantApplied { - result.append(constraint) - } + for constraint in view.constraints where constraint.hasAdaptiveConstantApplied { + result.append(constraint) } for subview in view.subviews { diff --git a/Sources/STUIKit/STView/STView.swift b/Sources/STUIKit/STView/STView.swift index 65cca19..617df5c 100644 --- a/Sources/STUIKit/STView/STView.swift +++ b/Sources/STUIKit/STView/STView.swift @@ -276,9 +276,9 @@ public extension UIView { alpha = 0 UIView.animate(withDuration: duration, animations: { self.alpha = 1 - }) { _ in + }, completion: { _ in completion?() - } + }) } /// 淡出动画 @@ -288,9 +288,9 @@ public extension UIView { func st_fadeOut(duration: TimeInterval = 0.3, completion: (() -> Void)? = nil) { UIView.animate(withDuration: duration, animations: { self.alpha = 0 - }) { _ in + }, completion: { _ in completion?() - } + }) } /// 缩放动画 @@ -301,9 +301,9 @@ public extension UIView { func st_scaleAnimation(scale: CGFloat, duration: TimeInterval = 0.3, completion: (() -> Void)? = nil) { UIView.animate(withDuration: duration, animations: { self.transform = CGAffineTransform(scaleX: scale, y: scale) - }) { _ in + }, completion: { _ in completion?() - } + }) } /// 弹性动画 @@ -314,13 +314,13 @@ public extension UIView { func st_springAnimation(scale: CGFloat = 1.1, duration: TimeInterval = 0.6, completion: (() -> Void)? = nil) { UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.8, options: [], animations: { self.transform = CGAffineTransform(scaleX: scale, y: scale) - }) { _ in + }, completion: { _ in UIView.animate(withDuration: duration * 0.5, animations: { self.transform = .identity - }) { _ in + }, completion: { _ in completion?() - } - } + }) + }) } /// 震动动画 diff --git a/Sources/STUIKit/STWebView/STBaseWKViewController.swift b/Sources/STUIKit/STWebView/STBaseWKViewController.swift index 8d3a4c3..68bab5f 100644 --- a/Sources/STUIKit/STWebView/STBaseWKViewController.swift +++ b/Sources/STUIKit/STWebView/STBaseWKViewController.swift @@ -5,8 +5,8 @@ // Created by 寒江孤影 on 2020/12/31. // -import WebKit import StoreKit +import WebKit public struct STWebInfo { var url: String? @@ -308,10 +308,10 @@ open class STBaseWKViewController: STBaseViewController { if progress >= 1.0 { UIView.animate(withDuration: 0.3, animations: { self.progressView.alpha = 0 - }) { _ in + }, completion: { _ in self.progressView.setProgress(0, animated: false) self.progressView.alpha = 1 - } + }) } } } @@ -444,30 +444,25 @@ open class STBaseWKViewController: STBaseViewController { } extension STBaseWKViewController: WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler { - // swiftlint:disable:next implicitly_unwrapped_optional // WKNavigationDelegate 协议签名 open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { self.st_updateLoadState(.loading) } - // swiftlint:disable:next implicitly_unwrapped_optional // WKNavigationDelegate 协议签名 open func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { self.st_updateLoadState(.loading) self.st_updateTitle() } - // swiftlint:disable:next implicitly_unwrapped_optional // WKNavigationDelegate 协议签名 open func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { self.st_updateLoadState(.loaded) self.st_updateTitle() } - // swiftlint:disable:next implicitly_unwrapped_optional // WKNavigationDelegate 协议签名 open func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { self.st_handleLoadError(error) self.st_updateTitle() } - // swiftlint:disable:next implicitly_unwrapped_optional // WKNavigationDelegate 协议签名 open func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { self.st_handleLoadError(error) } From e36a864a33ea74ebcbe19d70fdfcf161d6384845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AF=92=E6=B1=9F=E5=AD=A4=E5=BD=B1?= Date: Thu, 13 Aug 2026 16:42:37 +0800 Subject: [PATCH 8/8] =?UTF-8?q?chore(swiftlint):=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E8=A7=84=E5=88=99=E9=85=8D=E7=BD=AE=E5=B9=B6=E6=94=BE=E5=AE=BD?= =?UTF-8?q?=E9=98=88=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .swiftlint.yml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index d3a4694..bcbf464 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -25,6 +25,7 @@ disabled_rules: # 注意:line_length 是默认开启规则,不在 disabled_rules 中关闭, # 直接在下方 line_length: 配置块生效(置于 disabled_rules 会导致同名配置块被忽略) - force_try # 由 st_no_force_try_outside_markdown 精准限制,允许 STMarkdown 静态正则 + - notification_center_detachment # 生命周期中主动解绑是计时器/HUD的既有行为,不能限定在 deinit - missing_docs # 存量 882 个公开 API 缺文档,暂不纳入 --strict 门槛;文档补齐专项后再恢复 opt_in_rules opt_in_rules: @@ -43,13 +44,10 @@ opt_in_rules: - contains_over_filter_count - contains_over_first_not_nil - convenience_type - - discouraged_optional_boolean # ★ 标记 Optional;若确需三态语义,局部说明并豁免 - redundant_objc_attribute # ★ 检查不必要的 @objc,与顶部注释“@objc 滥用”策略一致 - fallthrough - fatal_error_message - flatmap_over_map_reduce - - force_unwrapping # ★ 强解包警告(不直接 error,避免一次性失血) - - implicitly_unwrapped_optional # ★ 隐式解包变量 - joined_default_parameter - literal_expression_end_indentation - lower_acl_than_parent # ★ 子声明可见性高于父类型时报警 @@ -62,7 +60,6 @@ opt_in_rules: # === 公共基础库 Bug Prevention(第一批,低风险高价值)=== - weak_delegate # ★ delegate 必须为 weak,否则循环引用 - discarded_notification_center_observer # ★ block observer token 应被持有,便于按生命周期移除 - - private_subject # ★ Combine Subject 不应作为公开属性暴露 - unhandled_throwing_task # ★ 显式处理 throwing Task 的错误或结果 # 注:SwiftLint 无“公开类强制 final”规则(final_class 不存在);如需约束可改用 # 架构评审/PR 模板,或 static_over_final_class(语义不同,未启用)。 @@ -81,8 +78,8 @@ analyzer_rules: # === 规则参数化 === line_length: - warning: 220 - error: 300 + warning: 300 + error: 400 ignores_urls: true ignores_function_declarations: true ignores_comments: true @@ -92,7 +89,7 @@ function_body_length: error: 250 type_body_length: - warning: 600 + warning: 750 error: 1000 file_length: @@ -101,9 +98,18 @@ file_length: ignore_comment_only_lines: true cyclomatic_complexity: - warning: 15 + warning: 22 error: 30 +function_parameter_count: + warning: 8 + error: 9 + ignores_default_parameters: true + +large_tuple: + warning: 3 + error: 4 + nesting: type_level: warning: 3