美文网首页
Swift - 面向协议的应用

Swift - 面向协议的应用

作者: 啧啧同学 | 来源:发表于2020-08-05 09:02 被阅读0次

应用一 - 代码“逻辑汇总”:

很多实际场景下,由于业务复杂程度,可能会将独立的业务拆分至不同的类中实现,单独的Class来维护独立业务各自的代码逻辑,需要将分散至各分类的代码逻辑判断汇总至一处来判断;对于Swift这门面向协议的语言来说,也是可以处理得十分的优雅

还是以交易页面来做栗子:

用户输入界面
 class userInputViewController: UIViewController,  CCBATradeVerifyProtocol {
        .....
        func doVerify() -> Bool {
               //验证用户的输入是否通过合法校验
               return true
        }
}
//用户的账户信息class
class UserAccountController: UIViewController, CCBATradeVerifyProtocol {
        ......
        func doVerify() -> Bool {
               //验证资金是否满足条件
               return true
        }
}
//股票信息class
class StockMarketViewController: UIViewController, CCBATradeVerifyProtocol {
        ......

        func doVerify() -> Bool {
               //验证股票数据是否正常
               return true
        }
}
//汇总的根页面
class TradeRootViewController: CCBATradeVerifyProtocol {
        ......
        // 下单接口调用逻辑
        func doRequestTradeOrder() {
                // 如果条件不满足,则不发送请求至后台
                guard  getVerifyResult() else { return }
                  
                 /* 提交订单信息至交易所 */
        }

//交易下单的前提条件是否全部满足(账户、股票、用户输入的验证条件分散在三个不同的class中)

    func getVerifyResult() -> Bool {
        
        var isVerify: Bool = true
        // 遍历所有实现 CCBATradeVerifyProtocol协议的子class 来“汇总”所有的条件
        for item in authProcessors {
            if !item.doVerify() {
                isVerify = false
                break
            } else { /* do nothing */ }
        }
        return isVerify
    }

    var authProcessors: [CCBATradeVerifyProtocol] = []
}

应用二 - 代码复用:

所有的界面具有同一种功能,且功能实现的逻辑代码完全一致,以 protocol 进行代理,并用作接口的抽象(通过extension Protocol来对目标方法的实现)进行代码复用,对于拥有这些功能的类(如view 或者 viewController )直接实现该protocol,便自动拥有此功能

栗子:数据缓存

以protocol抽象一个文件缓存功能逻辑

// 文档抽象类
protocol DocumentAbstract: class {
    
    /// 获取当前路径下的所有的子路径,并按照文件夹 -->  图片  --> 视频排序
    /// - Parameter path: 当前路径
    func getTotalCacheModel(at path: String) -> [FCFileBaseModel]?
    
    
    /// 获取用于展示用的文件夹类型的item
    /// - Parameter totalModels: 传入原数据模型组队列
    func getDocItems(_ totalModels: [FCFileBaseModel]) -> [YFCollectionItem]
    
    
    /// 获取媒体类Item
    /// - Parameter totalModels: 传入原数据模型组队列
    func getMediaItems(_ totalModels: [FCFileBaseModel]) -> [YFCollectionItem]
    
    
    /// 获取占位的item
    func getPlaceHolderItem() -> YFCollectionItem
    
    //长按的工具
    func showTools(_ model: FCFileBaseModel)
    
}

拓展DocumentAbstract中的协议方法(即默认实现)

extension FCDocumentFileAbstract {
    
    func getTotalCacheModel(at path: String) -> [FCFileBaseModel]? {
        
        let subDirectorys = YFFileManager.shared.subDicrsOfDirectory(at: path)
        
        guard !subDirectorys.isEmpty else {
            return nil
        }
        
        //重新排序,文件夹 -->  图片  --> 视频
        let totalModels: [FCFileBaseModel] = subDirectorys.compactMap { (title) -> FCFileBaseModel in
            
            let components = title.components(separatedBy: ".")
            var category: FCFileCategory = .doc
            
            components.forEach({ (component) in
                
                let mediaMaps: [String: FCFileCategory] = ["jpeg": .image,
                                                      "png": .image,
                                                      "heic": .image,
                                                      "mp4": .video,
                                                      "mov": .video,
                                                      "pdf": .pdf,
                                                      "txt": .txt]
                category = mediaMaps[component.lowercased()] ?? .unknown
            })
            
            let cachePath = path + "/\(title)"
            
            return FCFileBaseModel(path: cachePath, category: category, isShowDelete: false, title: title)
            
        }.sorted { (model0, model1) -> Bool in
            
            return model0.category.rawValue <  model1.category.rawValue
        }
        
        return totalModels
    }
    
    //MARK: - 获取文件类item
    func getDocItems(_ totalModels: [FCFileBaseModel]) -> [YFCollectionItem] {
        
        let width: CGFloat = UIScreen.main.bounds.width / 2.0 - 20.0
        
        let docItems: [YFCollectionItem] = totalModels.filter {
            
            $0.category == .doc
            
        }.compactMap { (subModel) -> YFCollectionItem in
            
            let cellItem: YFCollectionItem = (kFCFileDocumentFolderCollectionViewCell, CGSize(width: width, height: 86.0), subModel, { _ in
                
                let fileVC = FCDocumentBaseCollectionViewController(subModel)
                fileVC.isRootVC = false
                YFApp.UI.pushViewController(fileVC, animated: true)
            })
            
            return cellItem
        }
        
        return docItems
    }
    
    
    //MARK: - 获取媒体类Item
    func getMediaItems(_ totalModels: [FCFileBaseModel]) -> [YFCollectionItem] {
        
        let itemSize = CGSize(width: 68.0, height: 68.0)
        
        let mediaModels: [FCFileBaseModel] = totalModels.filter { $0.category != .doc }
        
        let mediaItems: [YFCollectionItem] = mediaModels.compactMap { (subModel) -> YFCollectionItem in
            
            subModel.clipClosure = { [weak self] in
                guard let strongSelf = self else { return }
                
                let category = subModel.category
                
                if category == .image {
                    
                    strongSelf.openImage(model: subModel, total: mediaModels)
                    
                } else if category == .video {
                    
                    let fileurl = URL(fileURLWithPath: subModel.path)
                    let player = YFPlayerViewController(url: fileurl)
                    player.play()
                    
                } else if category == .pdf {
                        
                    let vc = YFQLPreviewController(path: subModel.path, title: subModel.title)
                    YFApp.UI.present(vc, animated: true, completion: nil)
                        
                } else if category == .txt {
                   
                    let vc = FCTxtReaderViewController(title: subModel.displayTitle, path: subModel.path, isEditable: true)
                    let nav = UINavigationController(rootViewController: vc)
                    nav.modalPresentationStyle = .fullScreen
                    YFApp.UI.present(nav, animated: true, completion: nil)
                    
                } else { /* do nothing */ }
            }
            
            subModel.longPressClosure = { [weak self] in
                guard let strongSelf = self else { return }
                
                strongSelf.showTools(subModel)
            }
            
            let cellItem: YFCollectionItem = (kZWFileDocumentCollectionCell, itemSize, subModel, nil)
            
            return cellItem
        }
        
        
        return mediaItems
    }

    func getPlaceHolderItem() -> YFCollectionItem {
        
        let width: CGFloat = UIScreen.main.bounds.width
        
        let cellItem: YFCollectionItem = (kFCPlaceholderCollectionViewCell, CGSize(width: width, height: 190.0), nil, nil)
        
        return cellItem
    }
    
    private func openImage(model: FCFileBaseModel, total: [FCFileBaseModel]) {
        
        var selected: Int = 0
        
        let filterModels = total.filter { $0.category == .image }
        //仅仅轮播图片
        for (index, subModel) in filterModels.enumerated() {
            if subModel == model {
                selected = index
                break
            }
        }
        let photos: [SKPhoto] = filterModels.compactMap { (model) -> SKPhoto in
            return SKPhoto.photoWithImage(model.displayImage)
        }
        
        let browser = SKPhotoBrowser(photos: photos)
        browser.initializePageIndex(selected)
        YFApp.UI.present(browser, animated: true, completion: nil)
    }
}

class AnyYourClass: FCDocumentFileAbstract {}

AnyYourClass本身已默认实现FCDocumentFileAbstract相关的方法,只需要直接调用即可

应用三 - 约束功能

如目录中的其他两篇文章 《数据驱动之 UICollectionViewController》和《数据驱动之 UITableViewController》中对 用来展示用的cell必须要实现特定的Protocol才能用来注册tableView/collectionView, 从而所有的cell都具有相同的协议方法,基类在渲染cell时仅需在统一代码块中调用特定的方法,无需子类重复实现!

相关文章

网友评论

      本文标题:Swift - 面向协议的应用

      本文链接:https://www.haomeiwen.com/subject/nweirktx.html