コードで実装したUIViewのサブクラスを、コードからもIBからも使えるようにしておく時の共通の初期化のコードをどうしたら良いのかの話。
Objective-Cではこんな感じでやってたはず
@interface HogeView: UIView
@property(nonatomic)UIView *fugaView;
@end
@implementation HogeView
- (instancetype)initWithFrame:(CGFrame)frame {
self = [super initWithFrame:frame];
if(self) {
[self setup];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if(self) {
[self setup];
}
return self;
}
- (void)setup {
self.fugaView = [UIView new];
[self addSubview:self.fugaView];
}
@end
平和すぎる。
Swiftの場合
プロパティは出来るだけletにしておきたいしもちろんOptionalにもしたくないので全部initの中でやる必要があるが
共通の処理はどう書いたら良いのか...という事情があって調べたらこういう方法があった。
class HogeView: UIView {
let fugaView: UIView
init(_ coder: NSCoder? = nil) {
// common initialize
fugaView = UIView.init()
if let coder = coder {
super.init(coder: coder)!
} else {
super.init(frame: CGRect.zero)
}
// common setup
addSubview(fugaView)
}
required convenience init?(coder aDecoder: NSCoder) {
self.init(aDecoder)
}
}
やったぜ。
ちなみに、この方法だとinit(frame)
が失われてしまっています。
自分はAutolayoutを使わない場合のレイアウトは全てlayoutSubviews()
とかviewDidLayoutSubviews()
でやるので別にいらないけど...。
という感じのことが↓の記事に書かれていました。
https://theswiftdev.com/2015/08/05/swift-init-patterns/ (リンク切れ)