2014-09-30 3 views
4

Некоторые специальные классы, такие как UIView, имеют более одного назначенного инициализатора.Ручная инициализация UIView в swift

В Objective-X, мы могли бы учитывать общую инициализацию в отдельную функцию

- (id)initWithCoder:(NSCoder *)aDecoder { 
    if (self = [super initWithCoder:aDecoder]) { 
     [self initialize]; 
    } 

    return self; 
} 

- (id)initWithFrame:(CGRect)frame { 
    if (self = [super initWithFrame:frame]) { 
     [self initialize]; 
    } 
    return self; 
} 

В Swift это уже не возможно, потому что следующий код приводит к самостоятельной аудиторной используется до super.init вызова '

override init(frame: CGRect) { 
    self.initialize() 
    super.init(frame: frame) 
} 

required init(coder aDecoder: NSCoder) { 
    self.initialize() 
    super.init(coder: aDecoder) 
} 

Размещение self.initialize после того, как super.init тоже не помогает, поскольку вся моя цель - инициализация членов. Ниже приведет к «собственности не self.x инициализируется при super.init вызове»

var X : Int 

override init(frame: CGRect) { 
    super.init(frame: frame) 
    self.initialize() 
} 

required init(coder aDecoder: NSCoder) { 
    super.init(coder: aDecoder) 
    self.initialize() 
} 

Что я должен делать, если я хочу, чтобы учитывать общую инициализацию в этом случае? Обратите внимание, что я специально не хочу использовать awakeFromNib, потому что хочу, чтобы мои объекты были доступны в любых связанных реализациях awakeFromNib в моей иерархии объектов. Обратите также внимание на то, что опции не имеют смысла для моего варианта использования.

ответ

2

Очевидный ответ для вызова initialize после вызова super.init:

override init(frame: CGRect) { 
    super.init(frame: frame) 
    self.initialize() 
} 

Однако, вы, вероятно, есть некоторые переменные экземпляра, которые вы хотите инициализировать в методе initialize. Факты таковы:

  1. Перед вызовом super вы должны инициализировать все переменные-члены.
  2. Вы не можете вызывать методы на self (или получить доступ к вычисленным свойствам на self) перед вызовом super.init.

Неумолимая вывод о том, что если у вас есть переменные экземпляра, которые вы хотите инициализировать в initialize, вы должны объявить каждую такую ​​переменную с var, не let, и сделать один из этих вещей:

  1. Give экземпляр переменное значение по умолчанию:

    var name: String = "Fred" 
    
  2. Сделать экземпляр переменным Optional, и пусть это будет иня tialized всухую:

    var name: String? 
    
  3. Сделать экземпляр переменной ImplicitlyUnwrappedOptional, и пусть он будет инициализирован к нулю:

    var name: String! 
    

Мое предпочтение в этой точке # 2 (сделать его Optional и инициализируется до нуля).

+0

Это для случая, когда я хочу nonoptional переменную. Кажется, единственное решение в этом случае - использовать значение по умолчанию. Однако это не касается случая взаимозависимости между дефолтами. Например, что, если у меня есть неопциональный Y, который зависит от того, что происходит по неопровержимому X по умолчанию? – graveley

+0

Инициализатор переменной экземпляра (в объявлении переменной) не может ссылаться на 'self', любую другую переменную экземпляра или любой аргумент' init'. Так оно и есть. Да, это отстой. –

+1

Итак, некоторые функции просто невозможны, если вы хотите использовать nonoptionals. Вы должны настроить свой выбор типа, чтобы быть тем, чего вы никогда не хотели просто согласовать с языковыми ограничениями. Тот факт, что эти случаи существуют, также означает, что иногда, при рефакторинге или добавлении функций, вам нужно будет изменить свои неопъединения на дополнительные параметры, чтобы они работали правильно. Таким образом, люди просто в конечном итоге используют опции в таких случаях, даже для вещей, которые всегда гарантируются. – graveley

0

Там аккуратное решение этой проблемы здесь: https://stackoverflow.com/a/26772103/2420477

В основном, пометить две инициализацию функции convenience и затем их взывать к третьей private функции инициализации, которая имеет свой общий код инициализации.

В вашем случае, вы могли бы использовать что-то вроде этого:

class MyView: UIView { 

    let X: Int // No need to use an optional, as we assign this in an initializer 

    enum InitMethod { 
     case Coder(NSCoder) 
     case Frame(CGRect) 
    } 

    override convenience init(frame: CGRect) { // Marking as convenience let's us call out to another constructor 
     self.init(.Frame(frame))! 
    } 

    required convenience init?(coder aDecoder: NSCoder) { // Marking as convenience let's us call out to another constructor 
     self.init(.Coder(aDecoder)) 
    } 

    private init?(_ initMethod: InitMethod) { 
     // You can put your common initialization code here: 
     X = 1 

     switch initMethod { 
      case let .Coder(coder): super.init(coder: coder) 
      case let .Frame(frame): super.init(frame: frame) 
     } 
    } 
} 
+0

Просьба предоставить решение для данного конкретного вопроса – loki

Смежные вопросы