あたも技術ブログ

セットジャパンコーポレーションの社員が運営しています。

【Swift】xmlで管理している色情報を簡単に扱う

はじめに

今回は、xmlで色を管理した場合に、簡単に扱えるようにしたいと思います。

xmlについて

以下のフォーマットでxmlを用意します。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="buttonBackGround">#285176</color>
    <color name="buttonText">#305c83</color>
    .
    .
    .
</resources>

コード

今回は、色に関してのみですが、xmlファイル1つで色々とまとめて管理することができるので、使い回しがしやすいように、クラスを分けています。

class XMLUtil: NSObject,  XMLParserDelegate {
    
    var parser: XMLParser!
    
    var compleationBlock: (([String : String]?)->Void) = {_ in}
    var element: String!
    var attribute: String!
    var tmpDic: [String : String]!
    var tmpKey: String!
    
    public func parse(fileName: String, element: String! = nil, attribute: String! = nil, compleation: @escaping (([String : String]?)->Void)) {
        self.element = element
        self.attribute = attribute
        compleationBlock = compleation
        
        guard let tmpData: Data = loadAssetFile(name: fileName) else {
            self.compleationBlock(nil)
            return
        }
        
        parser = XMLParser(data: tmpData)
        parser.delegate = self
        
        let _ = parser.parse()
        
    }
    
    private func loadAssetFile(name: String) -> Data! {
        var data: Data! = nil
        // Assetsから取得
        if #available(iOS 9.0, *) {
            if let tmpData = NSDataAsset(name: name) {
                data = tmpData.data
            }
        } 
        return data
    }
    
    // MARK: - NSXMLParserDelegate
    
   public func parserDidStartDocument(_ parser: XMLParser) {
        tmpDic = [ : ]
    }
    
    public func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        
        guard let _ = element else {
            tmpKey = elementName
            return
        }
        guard let _ = attribute else {
            tmpKey = element
            return
        }
        if elementName == element {
            guard let key = attributeDict[attribute] else {
                return
            }
            tmpKey = key
        }
    }
    
    public func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        tmpKey = nil
    }
    
    public func parser(_ parser: XMLParser, foundCharacters string: String) {
        guard let _ = tmpKey else {
            return
        }
        tmpDic[tmpKey] = string
    }
    
    public func parserDidEndDocument(_ parser: XMLParser) {
        self.compleationBlock(tmpDic)
    }
}
class XMLColorUtil: NSObject {
    private var colors: [String : String]! = nil
    
    static var shared: XMLColorUtil = {
        let instance = XMLColorUtil()
        let res = instance.loadColors()

        return instance
    }()
    private override init() {
    }
   
    internal func loadColors() {
        var finish = false
        XMLUtil().parse(fileName: "colors", element: "color", attribute: "name") {
            dic in
            if dic != nil {
                self.colors = dic
            }
            finish = true
        }
        
    }
    
    public func getColor(key: String = #function) -> UIColor {
        guard let _ = colors else {
            return .white
        }
        guard let hexColor = colors[key] else {
            return .white
        }
        return UIColor(hex: hexColor)
    }
}
extension UIColor {
    convenience init(hex: String) {
        let range = NSMakeRange(0, rgbString.characters.count)
        let hexStr = (rgbString as NSString).replacingOccurrences(of: "[^0-9a-fA-F]", with: "", options: .regularExpression, range: range)
        
        var r: Float = 1
        var g: Float = 1
        var b: Float = 1
        let a: Float = 1
        if hexStr.characters.count == 6 {
            if let num = Int(hexStr, radix: 16) {
                r = Float((num >> 16) & 0xFF) / 255.0
                g = Float((num >> 8) & 0xFF) / 255.0
                b = Float((num) & 0xFF) / 255.0
            }
        }
        self.init(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: CGFloat(a))
    }
}

色クラス

class AppColor: NSObject {
    private let util = XMLColorUtil.shared
    
    // xml上のnameと合わせる
    public var buttonBackGround: UIColor {
        return util.getColor()
    }
    public var buttonText: UIColor {
        return util.getColor()
    }
    .
    .
    .
}

このクラスに上にxmlでname属性に設定した値をプロパティとして定義し、XMLColorUtilクラスのgetColor()を呼びます

getColor()の引数の初期値は#functionなので、呼び出し元のメソッド名を取得するようになっています。

XMLColorUtil().getColor(key: "buttonBackGround")とすることもできます。

使い方

let appColor = AppColor()

let button = UIButton(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 60)))

button.backgroundColor = appColor.buttonBackGround
button.setTitleColor(appColor.buttonText, for: .normal)

使用する色が増えた際には、xml編集後、AppColorクラスにプロパティを追加するだけで使えるようになります。