昨日、なんで今までこれをやってなかったんだろう?と思ったこと。
frame 弄るのダルい
UIView の layout 時に
label.frame.origin.y = 5;
とかしたいところですけど出来ません。 この程度の事で
label.frame = CGRectMake(CGRectGetMinX(label.frame),
5,
CGRectGetWidth(label.frame),
CGRectGetHeight(label.frame));
とかはダルすぎるので、一回変数に受けておいてから
CGRect frame = label.frame;
frame.origin.y = 5;
label.frame = frame;
くらいが妥当なところでしょうか。
これだと以下のような問題によく陥ります。
- 複数のViewのレイアウトを行う場合に一時変数名に困る
- 変更した rect を View に突っ込むのをうっかり忘れる
Blocks 使えば良かったんだ
この問題に対して以下のようなカテゴリメソッドを定義して
- (void)cs_changeFrameWithBlock:(CGRect (^)(CGRect frame))block { if (block) { self.frame = block(self.frame); } }
こんな感じでやれば良かったわけです。
[label cs_changeFrameWithBlock:^CGRect (CGRect frame) {
frame.origin.y = 5;
return frame;
}];
こうすることで
- Block のスコープに縛られるので他の一時変数と被ることはない
- 外の情報には問題なくアクセスできる
- CGRect を return し忘れるとビルドに失敗するのですぐ気づく
- ある View に対する frame の変更のコードブロック(塊)がわかりやすくて見やすくなる
まとめ
すでにそんなことやってるよとかもっといい方法を実践してるよっていう感じでしょうが、こんなくだらない小ネタでも気付きになるかと思って書きました。以前にも Blocks を使ったちょっとした便利な使い方を書きました。これからも何か気付きがあれば書いてみようと思います。