UILabelにlineSpacingプロパティを追加しようとしてはまった話

2014-04-08

UILabelに「lineSpacing」というプロパティを追加して、見事にはまったので書き残しておきます。

装飾付きテキスト「NSAttributedString」

いまさら感に溢れていますが、iOS 6.0からUILabelがNSAttributedStringに対応し、装飾付きのテキストを設定できるようになりました。例えば、

[[NSAttributedString alloc] initWithString:str attributes:attrs]

みたいに初期化すれば、装飾情報をNSDictionaryで指定することができます。 設定できる属性の一覧は、公式リファレンス「NSAttributedString UIKit Additions」に載っています。

行間を簡単に設定したい

今回の目的は、UILabelの行間を簡単に設定できるようにすることです。

行間は、先ほどのリファレンスによるとNSParagraphStyleのプロパティとして設定します。ただ、毎回NSParagraphStyleを生成して、属性の辞書を生成して、…と諸々設定するのは面倒ですよね。

UILabelを継承してlineSpacingプロパティを追加し、内側でうまいことやれば楽になるのでは?

プロパティを追加してみるが…

設定用の「lineSpacing」プロパティを試しに追加してみました。

@interface MyLabel : UILabel

@property (nonatomic) CGFloat lineSpacing;

@end

…が、追加した瞬間、ラベルのテキストが描画されなくなってしまいました。lineSpacingプロパティの定義を外せば元に戻ります。

ふーむ、これは…

「UILabelのプライベートな定義と重複している」と直感が囁いている!!

UILabelのプライベートを覗き見る

直感が正しいかどうかを確認するため、UILabelのプライベートを覗いてみましょう。

class-dumpというコマンドラインのツールがありまして、指定したframeworkのクラスを走査し、プライベートな定義も含めすべてダンプしてくれます。すてきですね。

UILabelはUIKit一族なので、該当するframeworkは「UIKit.framework」です。ディレクトリの奥深くに眠っているので、探し出してそのパスをclass-dumpに渡します。他の方が通ってきた道をありがたく辿りながら、class-dumpを実行。

% ./class-dump -H -o UIKit /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/UIKit.framework

無事に出力できたようです。 さっそくUIKit/UILabel.hを見てみると…

あった!やっぱりあったよ! 隠さずに提供してくれてもいいのよ…。あるいは警告のひとつでも出していただけないでしょうか、Xcodeさん。

名前が衝突してしまうと、予期しない動作を引き起こす可能性があります。今回のようなケースでは、追加するプロパティを他の名前、例えばmyLineSpacingにして回避する必要がありそうです。

Share: