LoginSignup
6
4

More than 5 years have passed since last update.

NSAttributedStringの配列をjoinedで結合したい

Last updated at Posted at 2016-08-01

前提

以下のように、文字列の配列を改行で結合する処理をNSAttributedStringでもやりたかった。

["a","b","c"].joinWithSeparator("\n")

やりたいこと

let attr = [NSForegroundColorAttributeName: UIColor.redColor()]
let attr_a = NSAttributedString(string: "a", attributes: attr)
let attr_b = NSAttributedString(string: "b", attributes: attr)
let attr_c = NSAttributedString(string: "c", attributes: attr)

[attr_a, attr_b, attr_c].joinWithSeparator("\n")

joinWithSeparatorの定義

extension SequenceType where Generator.Element == String {
    /// Interpose the `separator` between elements of `self`, then concatenate
    /// the result.  For example:
    ///
    ///     ["foo", "bar", "baz"].joinWithSeparator("-|-") // "foo-|-bar-|-baz"
    @warn_unused_result
    public func joinWithSeparator(separator: String) -> String
}

joinWithSeparator()はString専用のExtensionとして定義されているので、このままではNSAttributedStringで使えません。
Generator.Element == String を Generator.Element == NSAttributedStringとすればいけるかと思ったが色々ごにょごにょしてもビルドが通らなかった。。。

Swift 3対応版

mono0926さんより情報提供&修正して頂きました。

extension Sequence where Iterator.Element == NSAttributedString {
    func joined(attributedSeparator: Iterator.Element) -> Iterator.Element {
        let attributedString = self.enumerated()
            .map { (index, element) -> NSAttributedString in
                // 先頭はそのまま
                if index == 0 {
                    return element
                }
                // 各要素間にseparatorを挿入
                let mutable = NSMutableAttributedString(attributedString: attributedSeparator)
                mutable.append(element)
                return mutable
            }
            .reduce(NSMutableAttributedString(), { (list, element) -> NSMutableAttributedString in
                // AttributedString配列を一つのAttributedStringに結合
                list.append(element)
                return list
            })
        return Iterator.Element(attributedString: attributedString)
    }

    func joined(separator: String) -> Iterator.Element {
        return joined(attributedSeparator: Iterator.Element(string: separator))
    }

    var joined: Iterator.Element {
        return joined(separator: "")
    }
}

Swift 2.3まで

extension Array where Element: NSAttributedString {

    func joinWithSeparator(attributedSeparator: Element) -> Element {
        let attributedString = self.enumerate()
            .map { (index, element) -> NSAttributedString in
                // 先頭はそのまま
                if index == 0 {
                    return element
                }
                // 各要素間にseparatorを挿入
                let mutable = NSMutableAttributedString(attributedString: attributedSeparator)
                mutable.appendAttributedString(element)
                return mutable
            }
            .reduce(NSMutableAttributedString(), combine: { (list, element) -> NSMutableAttributedString in
                // AttributedString配列を一つのAttributedStringに結合
                list.appendAttributedString(element)
                return list
            })
        return Element(attributedString: attributedString)
    }

    func joinWithSeparator(separator: String) -> Element {
        return joinWithSeparator(Element(string: separator))
    }
}

結果としてArrayのExtensionにしてあげれば上手くいきました。
末尾判定のself.indices.lastにExtensionの制限がある為、Arrayより狭めることが出来ませんでした。Extenstion難しい。。。

もっと良い書き方があれば是非コメントください。

6
4
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
6
4