Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 65 additions & 3 deletions Sources/SectionKit/CollectionBase/SKCManager.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// File.swift
//
// SKCManager.swift
// SectionKit
//
// Created by linhey on 2022/8/11.
//
Expand All @@ -9,21 +9,37 @@
import UIKit
import Combine

/// 请求 ID 类,用于管理异步请求的生命周期
/// Request ID class for managing asynchronous request lifecycle
public class SKRequestID {

/// 请求的唯一标识符
/// Unique identifier for the request
public let id: String

/// 是否已取消
/// Whether cancelled
var isCancelled: Bool = false

/// 执行任务的闭包,返回 true 表示任务完成
/// Task closure, returns true when task is completed
let task: () -> Bool

/// 初始化请求 ID
/// Initialize request ID
init(id: String, task: @escaping () -> Bool) {
self.id = id
self.task = task
}

/// 取消请求
/// Cancel request
public func cancel() {
isCancelled = true
}

/// 执行请求任务
/// Perform request task
public func perform() {
if !isCancelled, task() {
cancel()
Expand All @@ -32,51 +48,97 @@ public class SKRequestID {

}

/// 请求发布者结构体,包含布局相关的发布者
/// Request publishers structure containing layout-related publishers
public struct SKRequestPublishers {
/// 布局子视图的发布者
/// Publisher for layout subviews
public let layoutSubviews = PassthroughSubject<Void, Never>()
public init() {}
}

/// 请求视图协议,定义具有请求发布者的视图
/// Request view protocol defining views with request publishers
public protocol SKCRequestViewProtocol {
/// 请求发布者实例
/// Request publishers instance
var requestPublishers: SKRequestPublishers { get }
}

/// SKC 管理器发布者类,管理 section 相关的发布者
/// SKC manager publishers class managing section-related publishers
public class SKCManagerPublishers {

/// section 数组的主题
/// Subject for sections array
fileprivate lazy var sectionsSubject = CurrentValueSubject<[SKCBaseSectionProtocol], Never>([])

/// 只读的 section 发布者
/// Read-only sections publisher
public private(set) lazy var sectionsPublisher = sectionsSubject.eraseToAnyPublisher()

/// 当前的 section 数组
/// Current sections array
public var sections: [SKCBaseSectionProtocol] { sectionsSubject.value }

/// 安全获取指定索引的 section
/// Safely get section at specified index
func safe<T>(section: Int) -> T? {
guard sections.indices.contains(section) else {
return nil
}
return sections[section] as? T
}

/// 获取指定类型的 section 集合
/// Get collection of sections of specified type
func collection<T>(_ type: T.Type = T.self) -> any Collection<T> {
sections.lazy.compactMap({ $0 as? T })
}
}

/// SKC 管理器主类,负责管理集合视图的数据和行为
/// Main SKC manager class responsible for managing collection view data and behavior
public class SKCManager {

/// 转换器结构体,用于在处理过程中转换数据
/// Converters structure for transforming data during processing
public struct Converts {
/// 转换器类型定义
/// Converter type definition
public typealias Convert<T> = (_ manager: SKCManager, _ item: T) -> T

/// section 注入转换器数组
/// Array of section injection converters
public var sectionInjection = [Convert<SKCSectionInjection>]()
}

/// 配置结构体,定义管理器的行为配置
/// Configuration structure defining manager behavior settings
public struct Configuration {
/// 将 reloadSections 操作替换为 reloadData 操作
/// Replace reloadSections operations with reloadData operations
public var replaceReloadWithReloadData = false
/// 将 insertSections 操作替换为 reloadData 操作

/// 将 insertSections 操作替换为 reloadData 操作
/// Replace insertSections operations with reloadData operations
public var replaceInsertWithReloadData = true

/// 将 deleteSections 操作替换为 reloadData 操作
/// Replace deleteSections operations with reloadData operations
public var replaceDeleteWithReloadData = false
}

/// 静态配置实例
/// Static configuration instance
public static var configuration = Configuration()

/// 实例配置
/// Instance configuration
public var configuration = SKCManager.configuration

/// 转换器实例
/// Converters instance
public var converts = Converts()
public private(set) lazy var publishers = SKCManagerPublishers()
public private(set) weak var sectionView: UICollectionView?
Expand Down
25 changes: 21 additions & 4 deletions Sources/SectionKit/CollectionBase/SKSupplementaryKind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,32 @@ import Foundation
#if canImport(UIKit)
import UIKit

/// SupplementaryView regist type
/// 补充视图注册类型枚举
/// Supplementary view registration type enumeration
///
/// - header: header
/// - footer: footer
/// - custom: custom
/// - header: 头部视图 / Header view
/// - footer: 底部视图 / Footer view
/// - cell: 单元格视图 / Cell view
/// - custom: 自定义视图 / Custom view
public enum SKSupplementaryKind: Equatable, Hashable, RawRepresentable {
/// 头部补充视图
/// Header supplementary view
case header

/// 底部补充视图
/// Footer supplementary view
case footer

/// 单元格视图
/// Cell view
case cell

/// 自定义补充视图
/// Custom supplementary view
case custom(_ value: String)

/// 从原始值初始化
/// Initialize from raw value
public init(rawValue: String) {
switch rawValue {
case UICollectionView.elementKindSectionHeader: self = .header
Expand All @@ -45,6 +60,8 @@ public enum SKSupplementaryKind: Equatable, Hashable, RawRepresentable {
}
}

/// 获取原始值
/// Get raw value
public var rawValue: String {
switch self {
case .header: return UICollectionView.elementKindSectionHeader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,43 @@
import UIKit
import Foundation

/// 任意 Section 协议,提供类型擦除的 Section 抽象
/// Any section protocol providing type-erased section abstraction
public protocol SKCAnySectionProtocol: SKCSectionActionProtocol {
/// 底层的 section 实例
/// Underlying section instance
var section: SKCSectionProtocol { get }

/// 对象标识符,用于唯一标识
/// Object identifier for unique identification
var objectIdentifier: ObjectIdentifier { get }
}

public extension SKCAnySectionProtocol {
/// 项目数量,代理到底层 section
/// Item count, delegated to underlying section
var itemCount: Int { section.itemCount }

/// Section 注入配置,代理到底层 section
/// Section injection configuration, delegated to underlying section
var sectionInjection: SKCSectionInjection? {
get { section.sectionInjection }
set { section.sectionInjection = newValue }
}

/// 配置 section 视图,代理到底层 section
/// Configure section view, delegated to underlying section
func config(sectionView: UICollectionView) {
section.config(sectionView: sectionView)
}

/// 获取对象标识符
/// Get object identifier
var objectIdentifier: ObjectIdentifier { .init(section) }
}

public extension SKCAnySectionProtocol where Self: SKCSectionProtocol {
/// 当自身已经是 SKCSectionProtocol 时,返回自身
/// When self is already SKCSectionProtocol, return self
var section: SKCSectionProtocol { self }
}
12 changes: 10 additions & 2 deletions Sources/SectionKit/CollectionBaseProtocol/SKCSectionProtocol.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
//
// File.swift
//
// SKCSectionProtocol.swift
// SectionKit
//
// Created by linhey on 2022/8/12.
//

#if canImport(UIKit)
import UIKit

/// 基础 section 协议,组合了数据源、代理和操作协议
/// Base section protocol combining data source, delegate and action protocols
public typealias SKCBaseSectionProtocol = SKCSectionActionProtocol & SKCDataSourceProtocol & SKCDelegateProtocol

/// 完整的 section 协议,在基础协议基础上添加了布局和类型协议
/// Complete section protocol adding layout and type protocols to base protocol
public typealias SKCSectionProtocol = SKCBaseSectionProtocol & SKCViewDelegateFlowLayoutProtocol & SKCAnySectionProtocol

public extension SKCDataSourceProtocol where Self: SKCViewDelegateFlowLayoutProtocol {

/// 获取指定类型和行的补充视图
/// Get supplementary view for specified kind and row
func supplementary(kind: SKSupplementaryKind, at row: Int) -> UICollectionReusableView? {
switch kind {
case .header:
Expand Down
52 changes: 44 additions & 8 deletions Sources/SectionKit/Common/SKBinding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,55 @@
import Foundation
import Combine

/// SKBinding 属性包装器,提供双向数据绑定功能
/// SKBinding property wrapper providing bidirectional data binding functionality
@propertyWrapper
public struct SKBinding<Value> {

// 包装的值
/// 包装的值,支持读取和设置
/// Wrapped value supporting get and set operations
public var wrappedValue: Value {
get { _get() }
nonmutating set {
// 执行所有设置器回调
// Execute all setter callbacks
for item in _set {
item(newValue)
}
// 如果有设置器,发送变化通知
// Send change notification if setters exist
if !_set.isEmpty {
self.changedSubject.send(newValue)
}
}
}

// 返回 SKBinding 的实例
/// 返回 SKBinding 的实例,用于访问绑定本身
/// Returns SKBinding instance for accessing the binding itself
public var projectedValue: SKBinding<Value> { self }

/// 值变化的发布者,用于监听数据变化
/// Publisher for value changes, used to observe data changes
public var changedPublisher: AnyPublisher<Value, Never> { changedSubject.eraseToAnyPublisher() }

/// 是否可设置,基于是否有设置器回调
/// Whether settable, based on whether setter callbacks exist
public var isSetable: Bool { !_set.isEmpty }

/// 获取值的闭包
/// Closure for getting value
private let _get: () -> Value

/// 设置值的闭包数组
/// Array of closures for setting value
private let _set: [(Value) -> Void]

/// 变化通知的主题
/// Subject for change notifications
private let changedSubject = PassthroughSubject<Value, Never>()

// 初始化方法,接受一个 getter 和 setter
/// 初始化方法,接受一个 getter 和可选的 setter
/// Initialization method accepting a getter and optional setter
public init(get: @escaping () -> Value, set: ((Value) -> Void)? = nil) {
if let set = set {
self.init(get: get, set: [set])
Expand All @@ -42,6 +65,8 @@ public struct SKBinding<Value> {
}
}

/// 私有初始化方法,接受 getter 和 setter 数组
/// Private initialization method accepting getter and setter array
private init(get: @escaping () -> Value, set: [(Value) -> Void]) {
self._get = get
self._set = set
Expand All @@ -51,11 +76,14 @@ public struct SKBinding<Value> {

public extension SKBinding {

// 创建一个常量绑定
/// 创建一个常量绑定,值不可变
/// Create a constant binding with immutable value
static func constant(_ value: Value) -> SKBinding<Value> {
.init(get: { value }, set: { _ in })
}

/// 创建一个常量绑定,使用闭包提供值
/// Create a constant binding using closure to provide value
static func constant(_ value: @escaping () -> Value) -> SKBinding<Value> {
.init(get: value, set: { _ in })
}
Expand All @@ -64,12 +92,14 @@ public extension SKBinding {

public extension SKBinding {

// 从一个现有的绑定创建一个新的绑定
/// 从 CurrentValueSubject 创建绑定
/// Create binding from CurrentValueSubject
init(_ source: CurrentValueSubject<Value, Never>) {
self.init(get: { source.value }, set: { source.send($0) })
}

// 从一个现有的绑定创建一个新的绑定
/// 从可选值的 CurrentValueSubject 创建绑定,提供默认值
/// Create binding from optional CurrentValueSubject with default value
init(_ source: CurrentValueSubject<Value?, Never>, default: Value) {
self.init(get: { source.value ?? `default` }, set: { source.send($0) })
}
Expand All @@ -78,12 +108,14 @@ public extension SKBinding {

public extension SKBinding {

// 从一个现有的绑定创建一个新的绑定
/// 从现有的 SKBinding 创建新的绑定
/// Create new binding from existing SKBinding
init(_ source: SKBinding<Value>) {
self.init(get: source._get, set: source._set)
}

// 从一个对象的 keyPath 创建一个绑定
/// 从对象的 keyPath 创建绑定
/// Create binding from object's keyPath
init<Root>(on object: Root, keyPath: ReferenceWritableKeyPath<Root, Value>) {
self.init {
object[keyPath: keyPath]
Expand All @@ -92,6 +124,8 @@ public extension SKBinding {
}
}

/// 从弱引用对象的 keyPath 创建绑定,提供默认值
/// Create binding from weakly referenced object's keyPath with default value
init<Root>(on object: Root, keyPath: ReferenceWritableKeyPath<Root, Value>, default: Value) where Root: AnyObject {
self.init { [weak object] in
object?[keyPath: keyPath] ?? `default`
Expand All @@ -100,6 +134,8 @@ public extension SKBinding {
}
}

/// 从弱引用对象的可选 keyPath 创建绑定,提供默认值
/// Create binding from weakly referenced object's optional keyPath with default value
init<Root>(on object: Root, keyPath: ReferenceWritableKeyPath<Root, Value?>, default: Value) where Root: AnyObject {
self.init { [weak object] in
object?[keyPath: keyPath] ?? `default`
Expand Down
Loading