美文网首页
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