无法在 Swift 中转换自定义 ExpyTableView 类型

问题描述 投票:0回答:1

我正在使用 Swift 开发 iOS 应用程序,并在尝试使用可扩展表格视图库 ExpyTableView 时遇到类型不匹配错误。该错误发生在我尝试操作表视图的可扩展部分的代码部分中。


import UIKit
import ExpyTableView

open class ExpyTableView: UITableView {
    
    fileprivate weak var expyDataSource: ExpyTableViewDataSource?
    fileprivate weak var expyDelegate: ExpyTableViewDelegate?
    
    public fileprivate(set) var expandedSections: [Int: Bool] = [:]
    
      open var expandingAnimation: UITableView.RowAnimation = ExpyTableViewDefaultValues.expandingAnimation
      open var collapsingAnimation: UITableView.RowAnimation = ExpyTableViewDefaultValues.collapsingAnimation
    
      public override init(frame: CGRect, style: UITableView.Style) {
        super.init(frame: frame, style: style)
    }
    
    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    open override var dataSource: UITableViewDataSource? {
        
        get { return super.dataSource }
        
        set(dataSource) {
            guard let dataSource = dataSource else { return }
            expyDataSource = dataSource as? ExpyTableViewDataSource
            super.dataSource = self
        }
    }
    
    open override var delegate: UITableViewDelegate? {
        
        get { return super.delegate }
        
        set(delegate) {
            guard let delegate = delegate else { return }
            expyDelegate = delegate as? ExpyTableViewDelegate
            super.delegate = self
        }
    }
    
    open override func awakeFromNib() {
        super.awakeFromNib()
        if expyDelegate == nil {
            //Set UITableViewDelegate even if ExpyTableViewDelegate is nil. Because we are getting callbacks here in didSelectRowAtIndexPath UITableViewDelegate method.
            super.delegate = self
        }
    }
}

extension ExpyTableView {
    public func expand(_ section: Int) {
        animate(with: .expand, forSection: section)
    }
    
    public func collapse(_ section: Int) {
        animate(with: .collapse, forSection: section)
    }
    
    private func animate(with type: ExpyActionType, forSection section: Int) {
        guard canExpand(section) else { return }
        
        let sectionIsExpanded = didExpand(section)
        
        //If section is visible and action type is expand, OR, If section is not visible and action type is collapse, return.
        if ((type == .expand) && (sectionIsExpanded)) || ((type == .collapse) && (!sectionIsExpanded)) { return }
        
        assign(section, asExpanded: (type == .expand))
        startAnimating(self, with: type, forSection: section)
    }
    
    private func startAnimating(_ tableView: ExpyTableView, with type: ExpyActionType, forSection section: Int) {
    
        let headerCell = (self.cellForRow(at: IndexPath(row: 0, section: section)))
        let headerCellConformant = headerCell as? ExpyTableViewHeaderCell
        
        CATransaction.begin()
        headerCell?.isUserInteractionEnabled = false
        
        //Inform the delegates here.
        headerCellConformant?.changeState((type == .expand ? .willExpand : .willCollapse), cellReuseStatus: false)
        expyDelegate?.tableView(tableView, expyState: (type == .expand ? .willExpand : .willCollapse), changeForSection: section)

        CATransaction.setCompletionBlock {
            //Inform the delegates here.
            headerCellConformant?.changeState((type == .expand ? .didExpand : .didCollapse), cellReuseStatus: false)
            
            self.expyDelegate?.tableView(tableView, expyState: (type == .expand ? .didExpand : .didCollapse), changeForSection: section)
            headerCell?.isUserInteractionEnabled = true
        }
        
        self.beginUpdates()
        
        //Don't insert or delete anything if section has only 1 cell.
        if let sectionRowCount = expyDataSource?.tableView(tableView, numberOfRowsInSection: section), sectionRowCount > 1 {
            
            var indexesToProcess: [IndexPath] = []
            
            //Start from 1, because 0 is the header cell.
            for row in 1..<sectionRowCount {
                indexesToProcess.append(IndexPath(row: row, section: section))
            }
            
            //Expand means inserting rows, collapse means deleting rows.
            if type == .expand {
                self.insertRows(at: indexesToProcess, with: expandingAnimation)
            }else if type == .collapse {
                self.deleteRows(at: indexesToProcess, with: collapsingAnimation)
            }
        }
        self.endUpdates()
        
        CATransaction.commit()
    }
}

extension ExpyTableView: UITableViewDataSource {
    open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let numberOfRows = expyDataSource?.tableView(self, numberOfRowsInSection: section) ?? 0
        
        guard canExpand(section) else { return numberOfRows }
        guard numberOfRows != 0 else { return 0 }
        
        return didExpand(section) ? numberOfRows : 1
    }
    
    open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard canExpand(indexPath.section), indexPath.row == 0 else {
            return expyDataSource!.tableView(tableView, cellForRowAt: indexPath)
        }
        
        let headerCell = expyDataSource!.tableView(self, expandableCellForSection: indexPath.section)
        
        guard let headerCellConformant = headerCell as? ExpyTableViewHeaderCell else {
            return headerCell
        }
        
        DispatchQueue.main.async {
            if self.didExpand(indexPath.section) {
                headerCellConformant.changeState(.willExpand, cellReuseStatus: true)
                headerCellConformant.changeState(.didExpand, cellReuseStatus: true)
            }else {
                headerCellConformant.changeState(.willCollapse, cellReuseStatus: true)
                headerCellConformant.changeState(.didCollapse, cellReuseStatus: true)
            }
        }
        return headerCell
    }
}

extension ExpyTableView: UITableViewDelegate {
    
    open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        expyDelegate?.tableView?(tableView, didSelectRowAt: indexPath)
        
        guard canExpand(indexPath.section), indexPath.row == 0 else { return }
        didExpand(indexPath.section) ? collapse(indexPath.section) : expand(indexPath.section)
    }
}

//MARK: Helper Methods

extension ExpyTableView {
    fileprivate func canExpand(_ section: Int) -> Bool {
        //If canExpandSections delegate method is not implemented, it defaults to true.
        return expyDataSource?.tableView(self, canExpandSection: section) ?? ExpyTableViewDefaultValues.expandableStatus
    }
    
    fileprivate func didExpand(_ section: Int) -> Bool {
        return expandedSections[section] ?? false
    }
    
    fileprivate func assign(_ section: Int, asExpanded: Bool) {
        expandedSections[section] = asExpanded
    }
}

//MARK: Protocol Helper
extension ExpyTableView {
    fileprivate func verifyProtocol(_ aProtocol: Protocol, contains aSelector: Selector) -> Bool {
        return protocol_getMethodDescription(aProtocol, aSelector, true, true).name != nil || protocol_getMethodDescription(aProtocol, aSelector, false, true).name != nil
    }
    
    override open func responds(to aSelector: Selector!) -> Bool {
        if verifyProtocol(UITableViewDataSource.self, contains: aSelector) {
            return (super.responds(to: aSelector)) || (expyDataSource?.responds(to: aSelector) ?? false)
            
        }else if verifyProtocol(UITableViewDelegate.self, contains: aSelector) {
            return (super.responds(to: aSelector)) || (expyDelegate?.responds(to: aSelector) ?? false)
        }
        return super.responds(to: aSelector)
    }
    
    override open func forwardingTarget(for aSelector: Selector!) -> Any? {
        if verifyProtocol(UITableViewDataSource.self, contains: aSelector) {
            return expyDataSource
            
        }else if verifyProtocol(UITableViewDelegate.self, contains: aSelector) {
            return expyDelegate
        }
        return super.forwardingTarget(for: aSelector)
    }
}


我尝试过的:

  1. 确保与 ExpyTableView 库不存在命名冲突。
  2. 检查项目的不同部分是否正确引用了自定义子类和库的类。
  3. 验证所有导入均已正确设置并且不存在循环依赖关系。

我的期望:

我希望将我的自定义子类与 ExpyTableView 库的功能无缝集成,从而允许在我的表视图中扩展部分,而不会出现任何类型不匹配错误。

问题:

如何解决此类型不匹配错误并确保我的子类与 ExpyTableView 库正常工作?有没有办法避免自定义子类和库的类名之间的这种冲突?

swift uitableview protocols custom-component
1个回答
0
投票

您已在代码中导入了 ExpyTableView,并且尝试声明一个新的 ExpyTableView,因此您会收到无效的重新声明错误。

如果你想自定义ExpyTableView,你需要创建一个新的ExpyTableView子类:

class CustomTableView: ExpyTableView {
    // override methods and properties you want to change
}
© www.soinside.com 2019 - 2024. All rights reserved.