2023-10-28 设计模式理解

将要修改的全部都用类然后调用的时候直接在manager里操作
如图4个文件都是涉及到指标的


811783580.png

class DHTechIndexManager: NSObject {
    
    
    /// 供指标库读取文件
    /// - Parameter type: <#type description#>
    static func loadXML(type: DJQuoteMarketInfo.BCTechIndexType?) {
        
        if let targetPath = DHTechIndexPath.getTargetPath(for: type ?? .stock),
           let sortTechIndexPath = DHTechIndexPath.getSortTechIndexPath(for: type ?? .stock) {
            DHBaseTechIndexXmlEditor.loadXML(sortTechIndexPath: sortTechIndexPath, targetPath: targetPath) { str in
                
            }
        } else {
            DZPrint("Invalid BCTechIndexType")
        }
        
    }

    
    /// 保存常用指标
    /// - Parameters:
    ///   - type: <#type description#>
    ///   - saveData: <#saveData description#>
    ///   - finsehdHandler: <#finsehdHandler description#>
    static func saveNormalTechIndexImpl(type:DJQuoteMarketInfo.BCTechIndexType?,
                                        saveData: [BCTechIndexXMLTitleNode],
                                        finsehdHandler: @escaping (() -> Void)) {
        if let sortTechIndexPath = DHTechIndexPath.getSortTechIndexPath(for: type ?? .stock) {
            DHBaseTechIndexXmlEditor.saveNormalTechIndex(sortTechIndexPath: sortTechIndexPath, saveData: saveData, finsehdHandler: finsehdHandler)
        } else {
            DZPrint("Invalid BCTechIndexType")
        }
    }
    
    
    /// 获取常用指标,优先从文件中读取,如果文件为空,则返回默认指标
    /// - Parameters:
    ///   - type: <#type description#>
    ///   - finshedHandler: <#finshedHandler description#>
    static func getNormalTechIndexImpl(type:DJQuoteMarketInfo.BCTechIndexType?,
                                       finshedHandler: @escaping ([BCTechIndexXMLTitleNode])->Void) {
        if let sortTechIndexPath = DHTechIndexPath.getSortTechIndexPath(for: type ?? .stock) {
            DHBaseTechIndexXmlEditor.getNormalTechIndex(type: type, sortTechIndexPath: sortTechIndexPath, finshedHandler: finshedHandler)
        } else {
            DZPrint("Invalid BCTechIndexType")
        }
    }

    
    
    /// 保存排序后的常用指(主副图分组)
    /// - Parameters:
    ///   - type: <#type description#>
    ///   - saveData: <#saveData description#>
    ///   - finsehdHandler: <#finsehdHandler description#>
    static func saveNormalTechIndexGroup(type:DJQuoteMarketInfo.BCTechIndexType?, saveData:(master:[BCTechIndexXMLTitleNode],figure:[BCTechIndexXMLTitleNode]),
                                         finsehdHandler:(()->Void)? = nil)
    {
        
        if let sortTechIndexPath = DHTechIndexPath.getSortTechIndexPath(for: type ?? .stock) {
            DHBaseTechIndexXmlEditor.saveNormalTechIndexGroup(sortTechIndexPath: sortTechIndexPath, saveData: saveData ,finsehdHandler: finsehdHandler)
        } else {
            DZPrint("Invalid BCTechIndexType")
        }
    }
    
    
    
    /// 获取所有指标(主图附图分组)
    /// - Parameters:
    ///   - sortTechIndexPath: <#sortTechIndexPath description#>
    ///   - finshedHandler: <#finshedHandler description#>
    static func getNormalTechIndexGroup(type:DJQuoteMarketInfo.BCTechIndexType?,
                                        finshedHandler: @escaping ((master:[BCTechIndexXMLTitleNode],figure:[BCTechIndexXMLTitleNode]))->Void)
    {
        if let sortTechIndexPath = DHTechIndexPath.getSortTechIndexPath(for: type ?? .stock) {
            DHBaseTechIndexXmlEditor.getNormalTechIndexGroup(sortTechIndexPath: sortTechIndexPath, finshedHandler: finshedHandler)
        } else {
            DZPrint("Invalid BCTechIndexType")
        }
    }
    
    
    //MARK - 以下方法为老数据兼容方法
    
    /// 获取常用指标
    /// - Parameters:
    ///   - type: <#type description#>
    ///   - finshedHandler: <#finshedHandler description#>
    static func getNormalTechIndex(type:DJQuoteMarketInfo.MarketType?,
                                   finshedHandler: @escaping ([BCTechIndexXMLTitleNode])->Void) {
        if type == .CNStock {
            BCTechIndexXmlEditor.getNormalTechIndex { (obj) in
                finshedHandler(obj)
            }
        } else {
            BCTechIndexXmlEditor.Industry_getFilterTechIndex { (obj) in
                finshedHandler(obj)
            }
        }
    }
    
    
    
    /// 获取指标数据(按指标类型分类)
    /// - Parameters:
    ///   - type: <#type description#>
    ///   - finshedHandler: <#finshedHandler description#>
    static func getAllXMLTechIndexGroup( _ type:DJQuoteMarketInfo.BCTechIndexType?,
                                         finshedHandler : @escaping ([(groupName:String,indexData:[BCTechIndexXMLNodeItem])]?)->Void)
    {
    
        if type == .stock {
            DHBaseTechIndexXmlEditor.getAllXMLTechIndexGroup { (obj) in
                if var allContent = obj {
                    var updatedContent: [(groupName: String, indexData: [BCTechIndexXMLNodeItem])] = []
                    for content in allContent {
                        let groupName = content.groupName
                        var groupIndexData = content.indexData
                        //个股特色型不能有这3个特色指标
                        if groupName == "特色型" {
                            let toRemove = ["情绪周期", "连板高度", "四季牛熊"]
                            groupIndexData = content.indexData.filter { !toRemove.contains($0.id) }
                        }
                        let updatedContentItem = (groupName: groupName, indexData: groupIndexData)
                        updatedContent.append(updatedContentItem)
                    }
                    allContent = updatedContent
                    finshedHandler(allContent)
                }
            }
        } else {
            DHBaseTechIndexXmlEditor.getAllXMLTechIndexGroup { (obj) in
                finshedHandler(obj)
            }
        }
    }
}

import UIKit

class DHTechIndexPath: NSObject {
    static let paths: [DJQuoteMarketInfo.BCTechIndexType: (targetPath: String, sortTechIndexPath: String)] = [
        .stock: (
            targetPath: (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first as NSString?)?.appendingPathComponent("bctechIndexxml.xml") ?? "",
            sortTechIndexPath: (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first as NSString?)?.appendingPathComponent("bcsortTechIndexPath.plist") ?? ""
        ),
        .industry: (
            targetPath: (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first as NSString?)?.appendingPathComponent("industry_bctechIndexxml.xml") ?? "",
            sortTechIndexPath: (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first as NSString?)?.appendingPathComponent("industry_bcsortTechIndexPath.plist") ?? ""
        ),
        .dpql: (
            targetPath: (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first as NSString?)?.appendingPathComponent("QL_bctechIndexxml.xml") ?? "",
            sortTechIndexPath: (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first as NSString?)?.appendingPathComponent("QL_bcsortTechIndexPath.plist") ?? ""
        )
    ]
    
    
    static func getTargetPath(for type: DJQuoteMarketInfo.BCTechIndexType) -> String? {
        return DHTechIndexPath.paths[type]?.targetPath
    }
    
    static func getSortTechIndexPath(for type: DJQuoteMarketInfo.BCTechIndexType) -> String? {
        return DHTechIndexPath.paths[type]?.sortTechIndexPath
    }
}

import UIKit

class DHDefaultTechIndex: NSObject {
    static let ownObj = DHDefaultTechIndex()
    //默认指标
    lazy var getDefaultTechIndex:[BCTechIndexXMLTitleNode] =
    {
        
        var retObj = [BCTechIndexXMLTitleNode]()
        retObj.append(BCTechIndexXMLTitleNode(id:"主力操盘", desc: "主力操盘"))
        retObj.append(BCTechIndexXMLTitleNode(id:"主力控盘", desc: "主力控盘"))
        retObj.append(BCTechIndexXMLTitleNode(id:"主力吸筹", desc: "主力吸筹"))
        //        retObj.append(BCTechIndexXMLTitleNode(id:"超短擒龙主", desc: "超短擒龙主"))
        //        retObj.append(BCTechIndexXMLTitleNode(id:"超短擒龙副", desc: "超短擒龙副"))
        retObj.append(BCTechIndexXMLTitleNode(id:"MA", desc: "MA"))
        retObj.append(BCTechIndexXMLTitleNode(id:"MACD", desc: "MACD"))
        retObj.append(BCTechIndexXMLTitleNode(id:"KDJ", desc: "KDJ"))
        retObj.append(BCTechIndexXMLTitleNode(id:"BOLL", desc: "BOLL"))
        retObj.append(BCTechIndexXMLTitleNode(id:"VOL", desc: "VOL"))
        
        return retObj
        
    }()
    
    
    //板块指标
    lazy var getIndustryTechIndex:[BCTechIndexXMLTitleNode] =
    {
        
        var retObj = [BCTechIndexXMLTitleNode]()
        retObj.append(BCTechIndexXMLTitleNode(id:"主力操盘", desc: "主力操盘"))
        retObj.append(BCTechIndexXMLTitleNode(id:"主力控盘", desc: "主力控盘"))
        retObj.append(BCTechIndexXMLTitleNode(id:"主力吸筹", desc: "主力吸筹"))
        //        retObj.append(BCTechIndexXMLTitleNode(id:"超短擒龙主", desc: "超短擒龙主"))
        //        retObj.append(BCTechIndexXMLTitleNode(id:"超短擒龙副", desc: "超短擒龙副"))
        retObj.append(BCTechIndexXMLTitleNode(id:"MA", desc: "MA"))
        retObj.append(BCTechIndexXMLTitleNode(id:"MACD", desc: "MACD"))
        retObj.append(BCTechIndexXMLTitleNode(id:"KDJ", desc: "KDJ"))
        retObj.append(BCTechIndexXMLTitleNode(id:"BOLL", desc: "BOLL"))
        retObj.append(BCTechIndexXMLTitleNode(id:"VOL", desc: "VOL"))
        retObj.append(BCTechIndexXMLTitleNode(id:"四季牛熊", desc: "四季牛熊"))
        retObj.append(BCTechIndexXMLTitleNode(id:"连板高度", desc: "连板高度"))
        retObj.append(BCTechIndexXMLTitleNode(id:"情绪周期", desc: "情绪周期"))
        
        return retObj
        
    }()
    
    
    //大盘擒龙指标
    lazy var getQLTechIndex:[BCTechIndexXMLTitleNode] =
    {
        var retObj = [BCTechIndexXMLTitleNode]()
        //        retObj.append(BCTechIndexXMLTitleNode(id:"四季牛熊", desc: "四季牛熊"))
        //要判断情绪周期指标有没有权限
        //zb1_fkld
        /*
         let zb1_fkld = DJPrivilageBusiness.isHaveData(funcType: .zb1_fkld)
         let ggQxzq = DJPrivilageBusiness.isHaveData(funcType: .ggQxzq)
         if zb1_fkld && ggQxzq{
         //两个权限都有则一个都不显示
         }else if (zb1_fkld == true && ggQxzq == false){
         //风口轮动还没开发,也不添加
         }else if (zb1_fkld == false && ggQxzq == true){
         //只有情绪周期
         
         }else{
         //两个权限都没有
         }
         */
        let ggsjnx = DJPrivilageBusiness.isHaveData(funcType: .zb1_sjnx)
        if ggsjnx == true{
            retObj.append(BCTechIndexXMLTitleNode(id:"四季牛熊", desc: "四季牛熊"))
        }
        
        let ggQxzq = DJPrivilageBusiness.isHaveData(funcType: .ggQxzq)
        if ggQxzq == true{
            retObj.append(BCTechIndexXMLTitleNode(id:"情绪周期", desc: "情绪周期"))
        }
        
        let gglbgd = DJPrivilageBusiness.isHaveData(funcType: .zb1_lbgd)
        if gglbgd == true{
            retObj.append(BCTechIndexXMLTitleNode(id:"连板高度", desc: "连板高度"))
        }
        
        retObj.append(BCTechIndexXMLTitleNode(id:"MA", desc: "MA"))
        retObj.append(BCTechIndexXMLTitleNode(id:"MACD", desc: "MACD"))
        retObj.append(BCTechIndexXMLTitleNode(id:"KDJ", desc: "KDJ"))
        retObj.append(BCTechIndexXMLTitleNode(id:"BOLL", desc: "BOLL"))
        retObj.append(BCTechIndexXMLTitleNode(id:"VOL", desc: "VOL"))
        
        
        return retObj
    }()
    
}


import UIKit
class DHBaseTechIndexXmlEditor: NSObject {
    static let ownObj = DHBaseTechIndexXmlEditor()
    
    let loadXMLQueue = DispatchQueue(label: "DHBaseTechIndexXmlEditor.loadXMLQueue")
    
    
    //分组后的Content
    var techIndexContent:[(groupName:String,indexData:[BCTechIndexXMLNodeItem])]?
    
    //未分组的无序的Content
    var allTechIndexContent:[String:BCTechIndexXMLNodeItem]?
    

    
    private var orignXMLData:String?
    

    
    static var techIndexY = [String:[CGFloat?]?]()
    
    
    
    /// 查找指标数据
    /// - Parameter techIndexID: <#techIndexID description#>
    /// - Returns: <#description#>
    static func findTechIndexData(techIndexID:String) -> BCTechIndexXMLNodeItem?
    {
        return ownObj.allTechIndexContent?[techIndexID]
    }
    
    
    /// 获取指标数据
    /// - Parameters:
    ///   - techIndexID: <#techIndexID description#>
    ///   - handler: <#handler description#>
    static func getTechIndexData(techIndexID:String, _ handler : @escaping (BCTechIndexXMLNodeItem?)->Void)
    {
        
        if let data = findTechIndexData(techIndexID: techIndexID)
        {
            DispatchQueue.main.async {
                handler(data)
            }
            return
        }
        else
        {
            
            self.ownObj.loadXMLQueue.async {
                if let data =  self.ownObj.techIndexContent
                {
                    for item in data
                    {
                        for subItem in item.indexData
                        {
                            if subItem.id == techIndexID
                            {
                                DispatchQueue.main.async {
                                    handler(subItem)
                                }
                                return
                            }
                        }
                    }
                }
                else
                {
                    DispatchQueue.main.async {
                        handler(nil)
                    }
                }
                
            }
            
        }
        
    }
    
    //默认指标
    lazy var getDefaultTechIndex:[BCTechIndexXMLTitleNode] =
    {
        return DHDefaultTechIndex.ownObj.getDefaultTechIndex
    }()
    
    //板块指标
    lazy var getIndustryTechIndex:[BCTechIndexXMLTitleNode] =
    {
        return DHDefaultTechIndex.ownObj.getIndustryTechIndex
    }()
    
    //大盘擒龙指标
    func QL_getDefaultTechIndex() -> [BCTechIndexXMLTitleNode] {
        return DHDefaultTechIndex.ownObj.getQLTechIndex
    }
    
    
    //修改XML参数
    static func modifyXML(item:BCTechIndexXMLNodeItem,  finshedHandler: @escaping ()->Void)
    {
        
        ownObj.loadXMLQueue.async
        {
            
            //修改缓存中techIndexContent的参数数据
            if let index = ownObj.techIndexContent?.firstIndex(where: { (obj) -> Bool in
                
                return obj.groupName == item.groupName
            })
            {
                
                if let subIndex = ownObj.techIndexContent?[index].indexData.firstIndex(where: { (obj) -> Bool in
                    return item.id == obj.id
                })
                {
                    ownObj.techIndexContent?[index].indexData[subIndex] = item
                }
                
            }
            
            
            //修改整个XML数据
            if let xmlData = ownObj.orignXMLData
            {
                
                if  let obj = try? GDataXMLDocument(xmlString: xmlData)
                {
                    let domObj = obj.rootElement()
                    
                    
                    if let  findNode = try? domObj?.nodes(forXPath: "//group1/group2/index") as? [GDataXMLNode],let params = item.params
                    {
                        if let contentNode = findNode
                        {
                            
                            for subItem in contentNode
                            {
                                
                                if let id = try? subItem.firstNode(forXPath: "@id").stringValue()
                                {
                                    if id == item.id
                                    {
                                        if let allElement = subItem.children()
                                        {
                                            //可以更改分量名称的指标,比如5日MA,那么指标描述名字为MA5,只是为了UI显示直观
                                            let canModifyContentName =  ["MA","EMA","SMA","PBX"].contains(id?.uppercased())
                                            
                                            //删除原始参数元素
                                            for element in allElement
                                            {
                                                if element.name() == "param"
                                                {
                                                    (subItem as? GDataXMLElement)?.removeChild(element)
                                                }
                                            }
                                            
                                            //增加修改后的参数元素
                                            var contentString = ""
                                            for repaceItem in params
                                            {
                                                
                                                
                                                if  let name = repaceItem.name, let max = repaceItem.max ,let min = repaceItem.min , let value = repaceItem.value
                                                {
                                                    
                                                    let newElement = GDataXMLElement.element(withName: "param")
                                                    
                                                    let attributeName = GDataXMLNode.attribute(withName: "name", stringValue: name) as? GDataXMLNode
                                                    let attributeDesc = GDataXMLNode.attribute(withName: "desc", stringValue: "") as? GDataXMLNode
                                                    let attributeMin =  GDataXMLNode.attribute(withName: "min", stringValue: min) as? GDataXMLNode
                                                    let attributeMax = GDataXMLNode.attribute(withName: "max", stringValue: max) as? GDataXMLNode
                                                    let attributeValue = GDataXMLNode.attribute(withName: "default", stringValue:value) as? GDataXMLNode
                                                    let attributeStep = GDataXMLNode.attribute(withName: "step", stringValue: "0") as? GDataXMLNode
                                                    
                                                    
                                                    newElement?.addAttribute(attributeName)
                                                    newElement?.addAttribute(attributeDesc)
                                                    newElement?.addAttribute(attributeMin)
                                                    newElement?.addAttribute(attributeMax)
                                                    newElement?.addAttribute(attributeValue)
                                                    newElement?.addAttribute(attributeStep)
                                                    
                                                    (subItem as? GDataXMLElement)?.addChild(newElement)
                                                    
                                                    //一些均线名字通过参数而定 比如5日MA,那么指标描述名字为MA5
                                                    if let nameValue = Float(value)
                                                    {
                                                        if id == "MA"
                                                        {
                                                            contentString = contentString + "MA\(Int(nameValue)):MA(CLOSE,\(name));"
                                                        }
                                                        else if id == "EMA"
                                                        {
                                                            contentString = contentString + "EMA\(Int(nameValue)):EMA(CLOSE,\(name));"
                                                        }
                                                        else if id == "SMA"
                                                        {
                                                            contentString = contentString + "SMA\(Int(nameValue)):SMA(CLOSE,\(name),1);"
                                                        }
                                                        else  if id == "PBX"
                                                        {
                                                            //PBX1:(EMA(CLOSE,M1)+MA(CLOSE,M1*2)+MA(CLOSE,M1*4))/3
                                                            contentString = contentString + "PBX\(Int(nameValue)):(EMA(CLOSE,\(name))+MA(CLOSE,\(name)*2)+MA(CLOSE,\(name)*4))/3;"
                                                        }
                                                    }
                                                    
                                                }
                                                
                                                
                                            }
                                            
                                            if canModifyContentName
                                            {
                                                //let newElement = GDataXMLElement.element(withName: "content")
                                                if  let contentAtr = try?subItem.firstNode(forXPath: "@content")
                                                {
                                                    (subItem as? GDataXMLElement)?.removeChild(contentAtr)
                                                }
                                                
                                                (subItem as? GDataXMLElement)?.addChild(GDataXMLNode.attribute(withName: "content", stringValue: contentString) as? GDataXMLNode)
                                                
                                            }
                                            
                                            
                                            saveXMLModifyedXMLData(xmlData: obj.xmlData())
                                            
                                            
                                            DispatchQueue.main.async {
                                                finshedHandler()
                                            }
                                            
                                            break
                                            
                                        }
                                        
                                    }
                                    
                                    
                                    
                                }
                            }
                            
                            
                            
                            
                        }
                    }
                    
                    
                }
                
                
            }
            
        }
        
    }
}

//MARK: - 文件存储相关
extension DHBaseTechIndexXmlEditor
{
    
    //XML保存路径
    static let targetPath = (NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first as NSString?)?.appendingPathComponent("bctechIndexxml.xml")
    
    //XML初始路径
    static let initPath =  Bundle.main.path(forResource: "sys_index", ofType: "xml")


    static let initXMLXRC32Key =   "initXMLXRC32Key"
    
    
    
    
    
    
    //供指标库读取文件
    @objc static func loadXML(sortTechIndexPath: String,
                              targetPath: String?,
                              finshedHandler: @escaping (String?)->Void)
    {
        DHBaseTechIndexXmlEditor.ownObj.loadXMLQueue.async {
            
            var retObj:String?  = try? String(contentsOf: URL(fileURLWithPath: DHBaseTechIndexXmlEditor.initPath! ), encoding: .utf8)
            
            let sysIndexXMLCRC32 = DataEncryAndDecry.icrc32(with: retObj ?? "")
            let savedSysIndexXMLCRC32 =  Int(UserDefaults.standard.object(forKey: DHBaseTechIndexXmlEditor.initXMLXRC32Key) as? String ?? "-1")!
            
            if  savedSysIndexXMLCRC32 != sysIndexXMLCRC32
            {
                //删除本地保存的指标
                let fileManager = FileManager.default
                if fileManager.fileExists(atPath: sortTechIndexPath ?? "")
                {
                    if  let _ = try? fileManager.removeItem(atPath: sortTechIndexPath) {}
                }
                
                UserDefaults.standard.set(String(sysIndexXMLCRC32), forKey: DHBaseTechIndexXmlEditor.initXMLXRC32Key)
                
                UserDefaults.standard.synchronize()
            }
            else if let _targetPath = targetPath
            {
                if let retStr =   try? String(contentsOf: URL(fileURLWithPath: _targetPath ), encoding: .utf8)
                {
                    retObj = retStr
                }
            }
            
            DHBaseTechIndexXmlEditor.ownObj.orignXMLData = retObj
            DispatchQueue.main.async {
                finshedHandler(retObj)
            }
            parseXMLData { _ in
                
            }
            
            
//            DispatchQueue.main.async {
//
//                DHBaseTechIndexXmlEditor.ownObj.orignXMLData = retObj
//
//                finshedHandler(retObj)
//
//                DHBaseTechIndexXmlEditor.parseXMLData { _ in }
//
//
//
//            }
            
        }
    }
    
    
    
    /// 保存修改后的指标
    /// - Parameter xmlData: <#xmlData description#>
     static func saveXMLModifyedXMLData(xmlData:Data)
    {
        guard let xmlString = String(data: xmlData, encoding: .utf8) else { return }
        
        DispatchQueue.global().async {
            BCTechIndexBusiness.updateIndexFormul(data: xmlString)
        }
        
        
        //更新数据
        if let _ = try? xmlString.write(to: URL(fileURLWithPath:targetPath!), atomically: true, encoding: .utf8)
        {
            
            
            ownObj.orignXMLData = xmlString
            
            parseXMLData { _ in
            }
            
        }
        
    }
    
    
    
    
    /// 解析指标
    /// - Parameter finshedHandler: <#finshedHandler description#>
     static func parseXMLData( _ finshedHandler : @escaping ([(groupName:String,indexData:[BCTechIndexXMLNodeItem])]?)->Void)
    {
        
        ownObj.loadXMLQueue.async {
            
            if let xmlData = ownObj.orignXMLData
            {
                
                if  let obj = try? GDataXMLDocument(xmlString: xmlData)
                {
                    let domObj = obj.rootElement()
                    
                    
                    if let  findNode = try? domObj?.nodes(forXPath: "//group1/group2") as? [GDataXMLNode]
                    {
                        if  let groupNode =   findNode
                        {
                            var techIndexContent = [(String,[BCTechIndexXMLNodeItem])]()
                            var allIndexConetent = [String:BCTechIndexXMLNodeItem]()
                            
                            for  item in  groupNode
                            {
                                
                                let groupName =  try! item.firstNode(forXPath: "@name").stringValue()
                                
                                
                                BCTechIndexXmlEditor.convertToTraditionalString(simpleString: groupName)
                                
                                var contentItem = (groupName!,[BCTechIndexXMLNodeItem]())
                                
                                let allContentNode = try! item.nodes(forXPath: "index") as! [GDataXMLNode]
                                for contentNode in allContentNode
                                {
                                    
                                    var item =  BCTechIndexXMLNodeItem()
                                    
                                    let indexID = try! contentNode.firstNode(forXPath: "@id").stringValue()
                                    BCTechIndexXmlEditor.convertToTraditionalString(simpleString: indexID)
                                    
                                    item.id = indexID
                                    
                                    item.groupName = groupName
                                    
                                    
                                    let inexName = try? contentNode.firstNode(forXPath: "@name").stringValue()
                                    item.name = inexName ?? ""
                                    BCTechIndexXmlEditor.convertToTraditionalString(simpleString: item.name)
                                    
                                    if let indexDesc = try? contentNode.firstNode(forXPath: "@desc").stringValue()
                                    {
                                        item.desc = indexDesc
                                        BCTechIndexXmlEditor.convertToTraditionalString(simpleString: item.desc)
                                    }
                                    
                                    if let help = try? contentNode.firstNode(forXPath: "@help").stringValue()
                                    {
                                        item.help = help
                                        BCTechIndexXmlEditor.convertToTraditionalString(simpleString: item.help)
                                    }
                                    
                                    if let flag = try? contentNode.firstNode(forXPath: "@flag").stringValue() ?? "0"
                                    {
                                        item.isMaster =  0x00100000 & (Int(flag) ?? 0) != 0
                                    }
                                    
                                    if let content = try? contentNode.firstNode(forXPath: "@content").stringValue()
                                    {
                                        item.content = content
                                        BCTechIndexXmlEditor.convertToTraditionalString(simpleString: item.content)
                                        print("content = \(content?.description)\n")
                                        //                                        print("")
                                        //                                        item.help = help
                                        //                                        DHBaseTechIndexXmlEditor.convertToTraditionalString(simpleString: item.help)
                                    }
                                    
                                    //解析默认参数
                                    if let params = try? contentNode.nodes(forXPath: "defaultparam")
                                    {
                                        
                                        if params.count > 0
                                        {
                                            item.defaultparams = [(name:String?,value:String?,max:String?,min:String?)]()
                                            
                                            for paramNode in params
                                            {
                                                if let paramName = try?  (paramNode as? GDataXMLNode)?.firstNode(forXPath: "@name").stringValue() ,  let paramValue = try?  (paramNode as? GDataXMLNode)?.firstNode(forXPath: "@default").stringValue(),let max = try?  (paramNode as? GDataXMLNode)?.firstNode(forXPath: "@max").stringValue(),let min = try?  (paramNode as? GDataXMLNode)?.firstNode(forXPath: "@min").stringValue()
                                                {
                                                    item.defaultparams?.append((paramName,paramValue,max,min))
                                                }
                                            }
                                        }
                                        else
                                        {
                                            item.defaultparams = nil
                                        }
                                        
                                    }
                                    
                                    
                                    //解析参数
                                    if let params = try? contentNode.nodes(forXPath: "param")
                                    {
                                        item.params = [(name:String?,value:String?,max:String?,min:String?)]()
                                        
                                        let bAddDefaultParam =  item.defaultparams == nil
                                        if bAddDefaultParam
                                        {
                                            item.defaultparams = [(name:String?,value:String?,max:String?,min:String?)]()
                                            
                                        }
                                        for paramNode in params
                                        {
                                            if let paramName = try?  (paramNode as? GDataXMLNode)?.firstNode(forXPath: "@name").stringValue() ,  let paramValue = try?  (paramNode as? GDataXMLNode)?.firstNode(forXPath: "@default").stringValue(),let max = try?  (paramNode as? GDataXMLNode)?.firstNode(forXPath: "@max").stringValue(),let min = try?  (paramNode as? GDataXMLNode)?.firstNode(forXPath: "@min").stringValue()
                                            {
                                                item.params?.append((paramName,paramValue,max,min))
                                                
                                                if bAddDefaultParam
                                                {
                                                    item.defaultparams?.append((paramName,paramValue,max,min))
                                                }
                                                
                                            }
                                        }
                                    }
                                    
                                    
                                    
                                    
                                    //解析y
                                    if let params = try? contentNode.nodes(forXPath: "line")
                                    {
                                        item.Y = [CGFloat?]()
                                        
                                        for paramNode in params
                                        {
                                            
                                            if let y = try?  (paramNode as? GDataXMLNode)?.firstNode(forXPath: "@y").stringValue()
                                            {
                                                if let _y  = y
                                                {
                                                    item.Y?.append(CGFloat(Double(_y)!))
                                                }
                                                
                                            }
                                        }
                                    }
                                    
                                    contentItem.1.append(item)
                                    techIndexY[item.id] = item.Y
                                    allIndexConetent.updateValue(item, forKey: item.id)
                                    
                                    
                                }
                                
                                techIndexContent.append(contentItem)
                                
                                
                            }
                            
                            ownObj.techIndexContent = techIndexContent
                            ownObj.allTechIndexContent = allIndexConetent
                            finshedHandler(ownObj.techIndexContent)
                            
                            
                            
                            
                        }
                    }
                }
            }
            
            
        }
        
        
        
    }
    
    
    
    /// 获取指标数据(按指标类型分类)
    /// - Parameter finshedHandler: <#finshedHandler description#>
    static func getAllXMLTechIndexGroup( _ finshedHandler : @escaping ([(groupName:String,indexData:[BCTechIndexXMLNodeItem])]?)->Void)
    {
        
        if ownObj.techIndexContent?.count != 0 && ownObj.techIndexContent != nil
        {
            finshedHandler(ownObj.techIndexContent)
        }
        else
        {
            parseXMLData { (obj) in
                
                DispatchQueue.main.async {
                    
                    finshedHandler(obj)
                }
                
            }
        }
    }
    
   
    
    
    
    /// 保存排序后的常用指(主副图分组)
    /// - Parameters:
    ///   - sortTechIndexPath: <#sortTechIndexPath description#>
    ///   - saveData: <#saveData description#>
    ///   - finsehdHandler: <#finsehdHandler description#>
    static func saveNormalTechIndexGroup(sortTechIndexPath:String,
                                         saveData:(master:[BCTechIndexXMLTitleNode],figure:[BCTechIndexXMLTitleNode]),
                                         finsehdHandler:(()->Void)? = nil)
    {
        DHBaseTechIndexXmlEditor.ownObj.loadXMLQueue.async {
            
            
            let masterMap = saveData.master.map({ (obj) -> [String:String?] in
                
                return [obj.id:obj.desc]
            })
            
            let figureMap = saveData.figure.map({ (obj) -> [String:String?]  in
                
                return [obj.id:obj.desc]
            })
            
            ([masterMap,figureMap] as NSArray).write(to: URL(fileURLWithPath: sortTechIndexPath), atomically: true)
            
            finsehdHandler?()
        }
        
    }
    
    
    
    
    /// 保存常用指标
    /// - Parameters:
    ///   - sortTechIndexPath: <#sortTechIndexPath description#>
    ///   - saveData: <#saveData description#>
    ///   - finsehdHandler: <#finsehdHandler description#>
    static func saveNormalTechIndex(sortTechIndexPath:String,
                                    saveData:[BCTechIndexXMLTitleNode],
                                    finsehdHandler:(()->Void)? = nil)
    {
        DHBaseTechIndexXmlEditor.ownObj.loadXMLQueue.async {
            
            
            let masterMap = saveData.compactMap({ (obj) -> [String:String?] in
                
                return [obj.id:obj.desc]
            })
            
            (masterMap as NSArray).write(to: URL(fileURLWithPath: sortTechIndexPath), atomically: true)
            
            finsehdHandler?()
        }
        
    }
    
    
    

    
    /// 获取常用指标,优先从文件中读取,如果文件为空,则返回默认指标
    /// - Parameters:
    ///   - type: <#type description#>
    ///   - sortTechIndexPath: <#sortTechIndexPath description#>
    ///   - finshedHandler: <#finshedHandler description#>
    static func getNormalTechIndex(type:DJQuoteMarketInfo.BCTechIndexType?,
                                   sortTechIndexPath:String,
                                   finshedHandler: @escaping ([BCTechIndexXMLTitleNode])->Void)
    {
        
//        DHBaseTechIndexXmlEditor.ownObj.loadXMLQueue.async
//        {
            
            
            var retObj = [BCTechIndexXMLTitleNode]()
            
            //如果本地保存了就从本地拿
            let arr =  NSArray(contentsOf: URL(fileURLWithPath: sortTechIndexPath))
            if (arr?.count ?? 0) != 0
            {
                if let data =  arr as? [[String:String?]]
                {
                    let _retObj = data.map({ obj -> BCTechIndexXMLTitleNode in
                        
                        return BCTechIndexXMLTitleNode(id:  obj.keys.first, desc: obj.values.first as? String)
                    })
                    retObj.append(contentsOf: _retObj)
                }
                
                
                finshedHandler(retObj)
                
                
                return
            }
            
            if type == .stock {
                retObj.append(contentsOf: DHBaseTechIndexXmlEditor.ownObj.getDefaultTechIndex)
            } else if type == .dpql {
                retObj.append(contentsOf: DHBaseTechIndexXmlEditor.ownObj.QL_getDefaultTechIndex())
            } else if type == .industry {
                retObj.append(contentsOf: DHBaseTechIndexXmlEditor.ownObj.getIndustryTechIndex)
            }
        
            
            
            //保存排序指标
            DHBaseTechIndexXmlEditor.saveNormalTechIndex(sortTechIndexPath: sortTechIndexPath, saveData: retObj)
            
            
            //这里并生成
            finshedHandler(retObj)
            
            
//        }
        
        
    }
    
    
    
    /// 获取所有指标(主图附图分组)
    /// - Parameters:
    ///   - sortTechIndexPath: <#sortTechIndexPath description#>
    ///   - finshedHandler: <#finshedHandler description#>
    static func getNormalTechIndexGroup(sortTechIndexPath: String,
                                        finshedHandler: @escaping((master:[BCTechIndexXMLTitleNode],figure:[BCTechIndexXMLTitleNode]))->Void)
    {
        
        
        ownObj.loadXMLQueue.async
        {
            
            
            var retObj:(master:[BCTechIndexXMLTitleNode],figure:[BCTechIndexXMLTitleNode]) = ([BCTechIndexXMLTitleNode](),[BCTechIndexXMLTitleNode]())
            
            //如果本地保存了就从本地拿
            let arr =  NSArray(contentsOf: URL(fileURLWithPath: sortTechIndexPath))
            if (arr?.count ?? 0) != 0
            {
                if let masrterData = arr?.firstObject as? [[String:String?]]
                {
                    let _retObj = masrterData.map({ obj -> BCTechIndexXMLTitleNode in
                        
                        return BCTechIndexXMLTitleNode(id:  obj.keys.first, desc: obj.values.first as? String)
                    })
                    retObj.master.append(contentsOf: _retObj)
                }
                
                if let figureData = arr?.lastObject as? [[String:String?]]
                {
                    let _retObj = figureData.map({ obj -> BCTechIndexXMLTitleNode in
                        
                        return BCTechIndexXMLTitleNode(id:  obj.keys.first, desc: obj.values.first as? String)
                    })
                    
                    retObj.figure.append(contentsOf: _retObj)
                    
                }
                
                
                finshedHandler(retObj)
                
                
                return
            }
            
            //这里并生成
            finshedHandler(retObj)
            
        }
        
        
        
        
        
    }
    
    
    
    
    
    
}

extension DJQuoteMarketInfo
{
    enum BCTechIndexType: Int {
        /// 未知类型,初始值0
        case unknown = 0
        /// 个股
        case stock = 1
        /// 板块
        case industry = 2
        /// 大盘擒龙
        case dpql = 3
        /// 所有类型
        case all = 4
    }

    
}

DHTechIndexManager负责给外部调用,外部想要什么业务,只需要传类型或数据即可
DHTechIndexPath 负责根据类型去取本地的指标缓存路径
DHDefaultTechIndex 负责默认的指标名字
DHBaseTechIndexXmlEditor 负责指标业务的具体实现
DJQuoteMarketInfo 负责指标类型

总的来说就是将一系列功能拆分成一个个的模块,有点类似于构造者模式。改的话只需要改一个地方,不会影响到其他地方,做到了对外扩展对修改关闭!
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 9,201评论 0 14
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 14,571评论 2 59
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,487评论 30 472
  • 点赞再看,养成习惯,白嫖不好,欢迎大家关注我面试小专栏 : iOS中高级进阶之路 有我准备的一线大厂面试资料和简历...
    iOS弗森科阅读 9,825评论 1 36
  • 先谈谈JVM 这篇文章主要是讲class文件和类加载机制,但是整个过程都和jvm密切相关,所以先从jvm说起。 J...
    Garwer阅读 9,593评论 3 5

友情链接更多精彩内容