2014-06-29 5 views
8

Il problema con sottoclasse UITextView (e UICollectionView) è che il costruttore designato è "initWithFrame". Ma nella vita reale, quando viene caricato dallo storyboard, viene chiamato initWithCoder.Swift: sottoclasse UITextView o UICollectionView e inizializzazione corretta

class BorderedTextView: UITextView { 
    //will be called 
    init(coder: NSCoder?){ 
     //constant values here is not an option 
     super.init(frame: CGRectMake(0,0,100,100), textContainer: nil) 
    } 
    //will not be called 
    init(frame: CGRect, textContainer: NSTextContainer!) { 
     super.init(frame: frame, textContainer: textContainer) 
    } 
} 

Come risultato non posso chiamare qualsiasi codice di personalizzazione dell'interfaccia utente su init e fornire qualsiasi valore di inizializzazione delle variabili Swift, tranne le impostazioni predefinite.

Suppongo che il problema possa essere risolto temporaneamente estraendo la dimensione del frame da "coder", ma non ho trovato la chiave per esso.

Qualche idea migliore dei valori dei frame hardcode?

+0

Mi aspetto che 'super.init (coder: coder)' funzioni - e per le sottoclassi di UIView o UILabel lo fa (almeno il compilatore non si lamenta). Ma per sottoclassi di 'UITextView' fallisce con un messaggio di errore" Deve chiamare l'inizializzatore designato ... ". Un bug di Swift? –

+0

Una possibile soluzione potrebbe essere quella di eseguire l'inizializzazione in 'awakeFromNib'. –

+0

Hai ragione, sembra che funzioni per UIView (ho una domanda aggiornata). Ma ho anche lo stesso problema con UICollectionView, quindi il problema non è solo con UITextView. –

risposta

12

(Dai miei commenti sopra :) Questo sembra un bug Swift. initWithCoder: viene chiamato quando una vista (o controller della vista) viene istanziato da un file storyboard o pennino, e prioritario che metodo funziona in Objective-C:

- (instancetype)initWithCoder:(NSCoder *)aDecoder 
{ 
    self = [super initWithCoder:aDecoder]; 
    if (self) { 
     // Initialization code 
    } 
    return self; 
} 

Ma il codice Swift equivalente

class BorderedTextView: UITextView { 
    init(coder: NSCoder!) { 
     super.init(coder: coder) 
    } 
} 

non riesce con il messaggio di errore "deve chiamare un inizializzatore designato della superclasse 'UITextView'".

Questo problema si verifica con tutte le sottoclassi di UIView che hanno un loro inizializzatore designato (ad esempio UITextView, UICollectionView). D'altra parte, il problema non si verifica con sottoclassi di UILabel, che non ha un inizializzatore designato. Il linguaggio Swift è molto severo nel chiamare l'inizializzatore designato delle super classi, ma ci dovrebbe essere un modo per sovrascrivere initWithCoder: per tutte le sottoclassi personalizzate UIView, quindi considero questo un bug Swift.

Per risolvere il problema, si può fare l'inizializzazione personalizzato in

override func awakeFromNib() { 
    super.awakeFromNib() 
    // ... 
} 

Aggiornamento per Swift 1.2: Questo a quanto pare è stato risolto. Il parametro è stato modificato, non è più un facoltativo facoltativo da scartare. Quindi questo compila e funziona come previsto (testato con Xcode 6.4):

class BorderedTextView: UITextView { 
    required init(coder: NSCoder) { 
     super.init(coder: coder) 

     // ... 
    } 
} 

Aggiornamento per Swift 2 (Xcode 7):init(coder:) è un failable inizializzatore ora:

class BorderedTextView: UITextView { 
    required init?(coder: NSCoder) { 
     super.init(coder: coder) 

     // ... 
    } 
} 
+0

Funziona in Swift 1.2? – Jacob

0

Una risposta più completa per Swift 3:

class ValidatedTextField:UITextField, UITextFieldDelegate 
{ 
    required override init(frame: CGRect) 
    { 
     super.init(frame: frame) 
     //custom code 
     self.delegate = self 
    } 

    required init?(coder: NSCoder) 
    { 
     super.init(coder: coder) 
     //custom code 
     self.delegate = self 
    }