Как написать пользовательский init для подкласса UIView в Swift?
Скажем, я хочу подкласс init
a UIView
с String
и Int
.
Как бы это сделать в Swift, если я просто подклассифицирую UIView
? Если я просто создаю пользовательскую функцию init()
, но параметры - это String и Int, она сообщает мне, что "super.init() не вызывается перед возвратом из инициализатора".
И если я позвоню super.init()
, мне сказали, что я должен использовать назначенный инициализатор. Что я должен там использовать? Кадровая версия? Версия кодера? И то и другое? Почему?
Ответы
Ответ 1
Версия init(frame:)
является инициализатором по умолчанию. Вы должны вызывать его только после инициализации ваших переменных экземпляра. Если это представление восстанавливается из Nib, тогда ваш пользовательский инициализатор не будет вызываться, а вместо него будет вызываться init?(coder:)
. Поскольку Swift теперь требует реализации требуемого init?(coder:)
, я обновил приведенный ниже пример и изменил объявления переменных let
на var
и необязательно. В этом случае вы должны инициализировать их в awakeFromNib()
или через некоторое время.
class TestView : UIView {
var s: String?
var i: Int?
init(s: String, i: Int) {
self.s = s
self.i = i
super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Ответ 2
Вот как я это делаю на iOS 9 в Swift -
import UIKit
class CustomView : UIView {
init() {
super.init(frame: UIScreen.mainScreen().bounds);
//for debug validation
self.backgroundColor = UIColor.blueColor();
print("My Custom Init");
return;
}
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented"); }
}
Вот полный проект с примером:
Ответ 3
Вот как я делаю Subview на iOS в Swift -
class CustomSubview : UIView {
init() {
super.init(frame: UIScreen.mainScreen().bounds);
let windowHeight : CGFloat = 150;
let windowWidth : CGFloat = 360;
self.backgroundColor = UIColor.whiteColor();
self.frame = CGRectMake(0, 0, windowWidth, windowHeight);
self.center = CGPoint(x: UIScreen.mainScreen().bounds.width/2, y: 375);
//for debug validation
self.backgroundColor = UIColor.grayColor();
print("My Custom Init");
return;
}
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented"); }
}
Ответ 4
Я создаю общий init для назначенного и требуемого. Для удобства я передаю init(frame:)
с нулевым кадром.
Наличие нулевого кадра не является проблемой, потому что обычно представление находится внутри представления ViewController. Супервизор вызывает layoutSubviews()
или updateConstraints()
, который рекурсивно вызывается системой в иерархии представлений.
Если у вашего пользовательского представления есть subviews, вы можете установить рамки subviews либо в updateContstraints()
, либо layoutSubviews()
. updateContstraints()
вызывается первым, тогда layoutSubviews()
. В updateConstraints()
обязательно вызовите super last. В layoutSubviews()
вызовите super first.
Вот что я делаю:
class MyView: UIView {
convenience init(args: Whatever) {
self.init(frame: CGRect.zero)
//assign custom vars
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
//custom initialization
}
override func updateConstraints() {
//set subview constraints here
super.updateConstraints()
}
override func layoutSubviews() {
super.layoutSubviews()
//manually set subview frames here
}
}