3
2

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 3 years have passed since last update.

SF SymbolsのsystemNameでタイポを防ぐために....

Posted at

環境

  • Swift 5.3.2

実装

enum SFSymbol {
    case rectangleAndPencilAndEllipsis
    case ...

    var image: UIImage? {
        switch self {
        case .rectangleAndPencilAndEllipsis: return UIImage(systemName: "rectangle.and.pencil.and.ellipsis")
        case ...
        }
    }
}

let image = SFSymbol.rectangleAndPencilAndEllipsis.image

たったこれだけのことなのに、
よく分からない寄り道をしました。

その作業工程で
正規表現を使わずにlowerCamelCaseをsnake_case等に変換するStringのExtension
という副産物ができたので合わせてご覧ください。

経緯

SF Symbolsの画像を複数箇所で利用する場合

let image = UIImage(systemName: "rectangle.and.pencil.and.ellipsis")

毎回文字列指定するのはタイポ起きそうだし長いしなんだかなぁと思っていました。

過ち

その一

早速足を踏み外します。

enum SFSymbol {
    case rectangleAndPencilAndEllipsis
    case ...
    
    var name: String {
        switch self {
        case .rectangleAndPencilAndEllipsis: return "rectangle.and.pencil.and.ellipsis"
        case ...
        }
    }
}

let image = UIImage(systemName: SFSymbol.rectangleAndPencilAndEllipsis.name)

この時点でなんで気づかないんですかね。

その二

微調整が入ります。

enum SFSymbol {
    case rectangleAndPencilAndEllipsis
    case ...
    
    var name: String {
        switch self {
        case .rectangleAndPencilAndEllipsis: return "rectangle.and.pencil.and.ellipsis"
        case ...
        }
    }
}

extension UIImage {
    convenience init?(sfSymbol: SFSymbol) {
        self.init(systemName: sfSymbol.name)
    }
}

let image = UIImage(sfSymbol: .rectangleAndPencilAndEllipsis)

何がしたかったんですかね。

その三

過去の自分:「nameで返してる文字列も無くしてしまえばいいのでは?」

副産物が出来上がります。

extension String {
    var splitLowercaseStrings: [String] {
        guard self.includesUppercaseChar else { return [self] }
        let (lowercaseString, otherString) = self.dividedLowercaseStringBeforeUppercaseCharAndOther
        let replacedOtherString = otherString.replacedFirstCharWithLowercaseChar
        guard replacedOtherString.includesUppercaseChar else { return [lowercaseString, replacedOtherString] }
        return [[lowercaseString],
                replacedOtherString.splitLowercaseStrings]
            .flatMap { $0 }
    }

    private var includesUppercaseChar: Bool {
        filter { $0.isUppercase }.count != 0
    }

    private var dividedLowercaseStringBeforeUppercaseCharAndOther: (prefixString: String, otherString: String) {
        guard let uppercaseCharIndex = firstIndex(where: { $0.isUppercase }) else { return (self, "") }
        let targetRange = startIndex..<uppercaseCharIndex
        let firstLowercaseString = String(self[targetRange])
        var otherString = self
        otherString.removeSubrange(targetRange)
        return (firstLowercaseString, otherString)
    }

    private var replacedFirstCharWithLowercaseChar: String {
        var string = self
        let firstUppercaseChar = string.first!
        let firstLowercaseChar = firstUppercaseChar.lowercased()
        let secondIndex = string.index(after: string.startIndex)
        string.insert(contentsOf: firstLowercaseChar, at: secondIndex)
        return String(string.dropFirst())
    }
}

enum SystemSymbol: String {
    case rectangleAndPencilAndEllipsis
    case ...
}

let systemImageName = SystemSymbol.rectangleAndPencilAndEllipsis.rawValue.splitLowercaseStrings.joined(separator: ".")
let image = UIImage(systemName: systemImageName)

地獄ですね。

最終的に

そもそもSF Symbolsを複数箇所で利用していませんでした。

余談

副産物について

let ordinalNumbers = "firstSecondThirdFourthFifthSixth"

print("dot: \(ordinalNumbers.splitLowercaseStrings.joined(separator: "."))")
// dot: first.second.third.fourth.fifth.sixth
print("underScore: \(ordinalNumbers.splitLowercaseStrings.joined(separator: "_"))")
// underScore: first_second_third_fourth_fifth_sixth

lowerCamelCaseの文字列を任意の文字列で連結できます。

(※)先頭の大文字を小文字に差し替える
var replacedFirstCharWithLowercaseChar: String では、
replacingOccurrences(of:with:)も試しましたが、
後続している大文字始まりの文字列の塊があると、その大文字も差し代わってしまうので
insert(contentsOf: at:)dropFirst(_:)を用いて処理しています。

3
2
2

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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?