13
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ZOZOテクノロジーズその2Advent Calendar 2018

Day 7

ZOZOTOWN iOS アプリで利用している Tips の一部

Last updated at Posted at 2018-12-06

ZOZOTOWN iOS の内部で利用している UI/NS 系クラス拡張につきまして、ニッチすぎる内容を除き紹介させていただきます!

※下記のコードはすべて、 Swift 4.2 / iOS12 SDK で動作するものです。

Array+Safe

配列の範囲外にアクセスしたさい、クラッシュせず nil を返して欲しい場合に利用します。

Array+Safe.swift
extension Array {

    subscript (safe index: Index) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }

}

Use Case

func xxx(index: Int) {
    let list: [String] = ["a", "b", "c"]

    if let item = list?[safe: index] {
        ...
    }
}

String+HtmlMutableAttributedString

HTMLが格納されている String をHTML形式の NSMutableAttributedString に変換するさいに利用します。
※メインスレッド以外で利用するとクラッシュするため、ご注意ください。

String+HtmlMutableAttributedString.swift
extension String {

    var htmlMutableAttributedString: NSMutableAttributedString? {
        if let encodedData = data(using: .unicode, allowLossyConversion: true) {
            let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [.documentType: NSAttributedString.DocumentType.html]
            let htmlText = try? NSMutableAttributedString(data: encodedData, options: options, documentAttributes: nil)
            return htmlText
        }
        return nil
    }

}

NSMutableParagraphStyle+Initializer

NSAttributedText を作成するさいに利用します。

NSAttributedTextを作成するさい、

let paragraph = NSMutableParagraphStyle()
paragraph.lineSpacing = 6
paragraph.textAlignment = .center
paragraph.lineBreakMode = .byWordWrapping 

上記がリーダブルではなく、コードを書く手間を削減したかったので、下記のように簡単に書けるようにしました。

NSMutableParagraphStyle+Initializer.swift
extension NSMutableParagraphStyle {

    convenience init(lineSpacing: CGFloat? = nil, textAlignment: NSTextAlignment? = nil, lineBreakMode: NSLineBreakMode? = nil, lineHeight: CGFloat? = nil) {
        self.init()

        if let lineSpacing = lineSpacing {
            self.lineSpacing = lineSpacing
        }
        if let textAlignment = textAlignment {
            self.alignment = textAlignment
        }
        if let lineBreakMode = lineBreakMode {
            self.lineBreakMode = lineBreakMode
        }
        if let lineHeight = lineHeight {
            self.maximumLineHeight = lineHeight
            self.minimumLineHeight = lineHeight
        }
    }

}

Use Case

func xxx() {
        let attributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 14),
                                                         .foregroundColor: UIColor.black,
                                                         .paragraphStyle: NSMutableParagraphStyle(lineSpacing: 6, textAlignment: .center, lineBreakMode: .byWordWrapping)]
    ...
}

UIColor+Hex

CSSで利用されるような16進数表記文字列( #808080 など)を UIColor にするさいに利用します。

UIColor+Hex.swift
extension UIColor {

    public convenience init(hex: Int, alpha: CGFloat) {
        let b = CGFloat((hex & 0x000000ff) >> 0) / 255.0
        let g = CGFloat((hex & 0x0000ff00) >> 8) / 255.0
        let r = CGFloat((hex & 0x00ff0000) >> 16) / 255.0

        self.init(red: r, green: g, blue: b, alpha: alpha)
    }

    public convenience init(hexWithAlpha: UInt32) {
        let b = CGFloat((hexWithAlpha & 0x000000ff) >> 0) / 255.0
        let g = CGFloat((hexWithAlpha & 0x0000ff00) >> 8) / 255.0
        let r = CGFloat((hexWithAlpha & 0x00ff0000) >> 16) / 255.0
        let a = CGFloat((hexWithAlpha & 0xff000000) >> 24) / 255.0

        self.init(red: r, green: g, blue: b, alpha: a)
    }

    public convenience init(hex: Int) {
        self.init(hex: hex, alpha: 1.0)
    }

    public convenience init(hexString: String) {
        var rgbString = hexString.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
        if rgbString.hasPrefix("#") {
            rgbString.remove(at: rgbString.startIndex)
        }

        switch rgbString.count {
        case 8:
            var argbValue: UInt32 = 0
            Scanner(string: rgbString).scanHexInt32(&argbValue)

            self.init(hexWithAlpha: argbValue)
        case 6:
            var rgbValue: UInt32 = 0
            Scanner(string: rgbString).scanHexInt32(&rgbValue)

            self.init(hex: Int(rgbValue))
        default:
            self.init(hex: 0)
        }
    }

}

Use Case

func xxx() {
    let hexWithAlphaColor1 = UIColor(hex: 0xffffff, alpha: 0.8) // rgba: 1.0 / 1.0 / 1.0 / 0.8
    let hexWithAlphaColor2 = UIColor(hexWithAlpha: 0xffffffcc) // rgba: 1.0 / 1.0 / 1.0 / 0.8
    let hexColor = UIColor(hex: 0xffffff) // rgba: 1.0 / 1.0 / 1.0 / 1.0
    let stringColor1 = UIColor(hexString: "ffffff") // rgba: 1.0 / 1.0 / 1.0 / 1.0
    let stringColor2 = UIColor(hexString: "#ffffff") // rgba: 1.0 / 1.0 / 1.0 / 1.0
    let stringColor3 = UIColor(hexString: "#ffffffcc") // rgba: 1.0 / 1.0 / 1.0 / 0.8
}

URL+Queries

APIに GET リクエストを送信する場合など、クエリーパラメーターを Dictionary で設定するさいに利用します。

URL+Queries.swift
extension URL {

    func addQueries(_ queries: [String: String]) -> URL? {
        if queries.isEmpty {
            return self
        } else {
            if var urlComponents = URLComponents(string: absoluteString) {
                urlComponents.queryItems = (urlComponents.queryItems ?? []) + queries.map({ URLQueryItem(name: $0.key, value: $0.value) })
                return urlComponents.url
            } else {
                return self
            }
        }
    }

}

Use Case

func writeAppStoreReview() {
    guard let appStoreUrl = URL(string: String(format: "itms-apps://itunes.apple.com/app/id%@", "(Apple ID)")) else {
        return
    }

    if let appStoreWithWriteReviewUrl = appStoreUrl.addQueries(["action": "write-review"]) {
        _ = openURL(appStoreWithWriteReviewUrl)
    }
}

おまけ:NSURL+Queries

Objective-C のコードから上記 URL+Queries をそのまま利用できなかったため、 NSURL 版も作成しました。

NSURL+Queries.swift
// MARK: - Definition

extension NSURL {

    @objc func addQueries(_ queries: [String: String]) -> NSURL? {
        return (self as URL).addQueries(queries) as NSURL?
    }

}

最後に

もしご自身のプロダクトに使えそうなら、ご利用いただけると幸いです!

13
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?