前提
以下のように、文字列の配列を改行で結合する処理を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難しい。。。
もっと良い書き方があれば是非コメントください。