ios swift uibutton initializer

ios - ¿Dónde inicializar el objetivo en un UIButton? Particularmente cuidadoso para IBDesignable



swift initializer (4)

tl; dr

override func endTrackingWithTouch(touch: UITouch?, withEvent event: UIEvent?) { super.endTrackingWithTouch(touch, withEvent: event) if let touchNotNil = touch { if self.pointInside(touchNotNil.locationInView(self), withEvent: event) { print("it works") } } }

Por qué no usar addTarget

addTarget método addTarget es parte de la interfaz acción-objetivo que se considera '' pública ''. Cualquier cosa con referencia a su botón puede, por ejemplo, eliminar todas sus acciones , rompiéndola efectivamente. Se prefiere utilizar algunos de los medios " protegidos ", por ejemplo, endTrackingWithTouch que solo se puede anular , no endTrackingWithTouch directamente. De esta forma, no interferirá con ningún objeto externo mediante el mecanismo de acción-objetivo.

(Sé que no hay un estricto ''público'' o ''protegido'' en ObjC / UIKit, pero el concepto permanece)

A tu manera

Si quieres hacerlo exactamente a tu manera, entonces tu ejemplo está bien, solo copia addTarget call to init(frame:CGRect) .

O puede poner addTarget en awakeFromNib (no olvide super) en lugar de init?(coder decoder: NSCoder) , pero se verá obligado a implementar init con el codificador de todos modos, por lo que ...

layoutSubviews y didMoveToSuperView son ideas terribles. Ambos pueden suceder más de una vez, lo que resulta en blah target-action agregado nuevamente. Luego se llamará blah varias veces por un solo clic.

Por cierto

La forma de Apple

Por el Cocoa MVC (que se aplica mediante la implementación de clases de UIKit) debe asignar esa acción al objeto que controla ese botón, las animaciones o no. Muy a menudo ese objeto será Cocoa MVC ''Controller'' - UIViewController .

Si crea un botón programáticamente, UIViewController debe asignar el destino a sí mismo en loadView o viewDidLoad . Cuando se carga el botón desde la punta, la forma preferida es asignar acción objetivo en xib.

Old Good MVC

Como se menciona aquí en las vistas MVC reales , no se envíen acciones a sí mismos. Lo más parecido al controlador MVC real en UIKit es UIGestureRecognizer .

Tenga en cuenta que es bastante difícil extraer MVC real con el conjunto de clases UIKit.

tengo un

@IBDesignable class Fancy:UIButton

quiero

addTarget(self, action:#selector(blah), forControlEvents: UIControlEvents.TouchUpInside)

Entonces, ¿dónde en UIButton debería hacerse eso?

¿Dónde está el mejor lugar para addTarget ?

1 - He visto el layoutSubviews sugerido - ¿es así?

Nota: la experimentación muestra que un problema con layoutSubviews es que, por supuesto, se puede layoutSubviews menudo, siempre que las cosas se muevan. Sería una mala idea "agregarTarget" más de una vez.

2 - didMoveToSuperview es otra sugerencia.

3 - ¿En algún lugar en (uno de) los Inits?

Nota: la experimentación muestra un problema fascinante si lo haces dentro de Init. Durante Init, las variables IBInspectables aún no están configuradas. (Entonces, por ejemplo, estaba ramificando dependiendo del "estilo" de control establecido por un IBInspectable; simplemente no funciona como @IBInspectable: ¡no funcionará cuando se ejecute!)

4 - ¿En algún otro lugar?

Intenté hacerlo en Init, y funcionó bien. Pero rompe designables de trabajar en el Editor.

Al dar vueltas, se me ocurrió esto (¿por alguna razón ambos deben incluirse?)

@IBDesignable class DotButton:UIButton { @IBInspectable var mainColor ... etc. required init?(coder decoder: NSCoder) { super.init(coder: decoder) addTarget(self, action:#selector(blah), forControlEvents: UIControlEvents.TouchUpInside) } override init(frame:CGRect) { super.init(frame:frame) }

No sé por qué funciona, y no entiendo por qué habría dos rutinas de init diferentes.

¿Cuál es la forma correcta de incluir addTarget en un UIButton?


¿Qué hay de la implementación de awakeFromNib y hacerlo allí?

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Protocols/NSNibAwaking_Protocol/#//apple_ref/occ/instm/NSObject/awakeFromNib

También puede ejecutar (o no ejecutar) código de forma condicional cuando se ejecuta en el contexto de Interface Builder:

#if !TARGET_INTERFACE_BUILDER // this code will run in the app itself #else // this code will execute only in IB #endif

(ver http://nshipster.com/ibinspectable-ibdesignable/ )


No debe agregar como objetivo el mismo objeto que produce la acción.
El objetivo y su devolución de llamada deberían ser otro objeto, generalmente un controlador de vista.
Hay 2 métodos inits porque el botón se puede crear una instancia invocando init o mediante el proceso de deserialización ( NSCoder ) desde un nib / xib. Dado que probablemente haya agregado el botón a un guión gráfico, el método init llamado es init?(_: NSCoder) .
[ACTUALIZAR]
Estoy de acuerdo con lo que dices en el comentario, pero creo que el patrón acción-objetivo debe usarse para comunicarme con otros objetos, estoy usando condicional, porque hasta donde sé nunca he visto algo como lo que escribiste en Apple código o alguna otra biblioteca. Si desea interceptar y realizar algunas acciones dentro del botón, probablemente debería anular algunos de los métodos expuestos en UIControl .
Acerca de designable, usted es, de nuevo, correcto. init(frame) si está creando un botón mediante programación, init(coder) si el botón proviene de un xib.
El método init(frame) también se llama durante el proceso designado. En este momento, creo que la mejor opción es depurar directamente su vista.

  • Coloque algunos puntos de interrupción dentro de usted UIButton subclase
  • Seleccione la vista en su guión gráfico
  • Vaya al Editor -> Depurar vistas seleccionadas

Ahora deberías ser capaz de entender dónde está el problema.


Su método de inicialización no es correcto, esto funcionará:

`` `rápido

override init(frame: CGRect) { super.init(frame: frame) self.loadNib() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.loadNib() } private func loadNib() { let nibView = NSBundle(forClass: self.classForCoder).loadNibNamed("yourView", owner: self, options: nil).first as! UIView nibView.frame = self.bounds nibView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] self.button.addTarget(self, action: #selector(action), forControlEvents: .TouchUpInside) self.addSubview(nibView) }

`` `