Инициализация удобства подкласса UINavigationController делает подклассом константу init дважды
У меня есть подклассы UINavigationController
и UITableViewController
.
Для инициализации подклассов я решил использовать некоторые convenience init
методы convenience init
которые вызывают некоторый назначенный инициализатор суперкласса. Кроме того, каждый подкласс некоторые let
постоянно:
let someValue: SomeClass = SomeClass()
Каждый класс успешно инициализируется путем вызова его вновь созданного метода convenience init
.
Проблема в том, что константа let
инициализируется TWICE в подклассе UINavigationController
.
import UIKit
import PlaygroundSupport
final class Navigation: UINavigationController {
convenience init(anyObject: Any) {
self.init(rootViewController: UIViewController())
}
let service = Constant("Constant Initialization -> Navigation")
}
final class Table: UITableViewController {
convenience init(anyObject: Any) {
self.init(style: .plain)
}
let service = Constant("Constant Initialization -> Table")
}
class Constant: NSObject {
init(_ string: String) {
super.init()
debugPrint(string)
}
}
Navigation(anyObject: NSNull())
Table(anyObject: NSNull())
Можем ли мы использовать convenience init
как указано выше? Зачем?
Почему в этих двух случаях поведение convenience init
отличается?
Проверено: версия 8.2 beta (8C30a), версия 8.2 (8C38), версия 8.2.1 (8C1002)
PS Игровой журнал приведенный выше код:
"Constant Initialization -> Navigation"
"Constant Initialization -> Navigation"
"Constant Initialization -> Table"
Ответы
Ответ 1
Так что это кажется странным "ожидаемым поведением" со Свифт. Причина, по которой это происходит, связана с постоянной инициализированной service
недвижимости. А именно, этот пост суммирует проблему, которую вы видите довольно хорошо: сообщение в блоге
По сути, супер-классы, основанные на Obj-C, вызывают утечку памяти, и ваше свойство service
инициализируется дважды из-за этого шаблона инициализации Obj-C:
- (id)init {
self = [super init];
if (self) {
self = [[self.class alloc] initWithNibName:nil bundle:nil];
}
return self;
}
Простым решением, чтобы избежать этого, является следующий шаблон:
import UIKit
final class NavigationController: UINavigationController {
var service: ObjectTest?
convenience init() {
self.init(rootViewController: UIViewController())
self.service = ObjectTest("init nav")
}
}
class ObjectTest: NSObject{
init(_ string: String) {
super.init()
print(string)
}
}
Все, что меняется от вашей реализации, инициализирует service
только после инициализации самого класса.
Другое решение, однако, состоит в том, чтобы использовать назначенный инициализатор для суперкласса вашей инициализации. Это означает, что вы не используете инициализатор удобства, который использовал бы описанную выше схему инициализации Obj-C.