2012-06-26 12 views
5

Tengo una subclase de UITextView y me gustaría que sea su propio delegado. Para poder anular el método textView:shouldChangeTextInRange:replacementText:, y evitar el ingreso de espacios consecutivos.UITextView como delegado propio significa bucle infinito

En [SATextView awakeFromNib] (SATextView es mi subclase de UITextView), hago [self setDelegate:self];. Cuando presiono sobre la vista de texto para comenzar a editar, todo se congela y finalmente se detiene, y esa traza inversa muestra que ha habido un ciclo infinito.

No importa si implemento todos los métodos de delegado, solo uno o ninguno. Tampoco importa si esos métodos están vacíos.

¿Por qué esto causa un ciclo infinito? Solo parece suceder si con UITextView (otros objetos puede crear una subclase y establecer el delegado en sí mismo, y no tendrá este problema). ¿Y cómo puedo detenerlo? ¿O hay una mejor manera de que esta subclase no tenga espacios consecutivos,

+0

Piénsalo. Difícil. Es posible hacer que una clase sea su propia delegada, pero requiere reflexión. –

+0

@HotLicks Lo he pensado, lo he hecho con otras clases sin problemas? ¿Puede usted ayudar? –

+0

La traza inversa debe mostrarle el bucle en el que se encuentra. –

Respuesta

1

Una idea ... Podría hacer una clase de delegado que actúe como intermediario entre el delegado real y el UITextView (porque lo hará probablemente necesite configurar el delegado después de un tiempo). Así que esta nueva clase implementará el protocolo de delegado, pero también tendrá una propiedad para su propio delegado, de modo que puede reenviar textView: shouldChangeTextInRange: replacementText :, y aún hacer el trabajo de editar los espacios en su clase middleMan.

+0

esto es lo que recomiendo. Cree una clase auxiliar que implemente 'UITextViewDelegate' y aplique los comportamientos que desee. Esta clase puede tener su propio protocolo si se desea enviar mensajes al controlador que gestiona la lógica general. Este patrón es útil en muchos escenarios, también lo uso para 'UITableViewDataSource'. Terminas con implementaciones de protocolo bonitas, ordenadas y reutilizables. – XJones

0

Es posible suscribir cualquier cantidad de observadores a un objeto. Por lo tanto, es posible suscribirse:

@implementation MyTextView 

-(id) initWithFrame:(CGRect)frame // or initWithCoder: for loading from nib 
{ 
    self = [super initWithFrame:frame]; 
    if(self) { 
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewTextDidChangeNotification:) name:UITextViewTextDidChangeNotification object:self]; 
    } 
    return self; 
} 

-(void)textViewTextDidChangeNotification:(NSNotification*)n 
{ 
    self.text = [self.text stringByReplacingOccurrencesOfString:@" " withString:@" "]; 
} 
+1

Gracias, pero necesito los métodos 'should' que no se pueden observar usando el centro de notificaciones –

0

Aquí hay un ejemplo de cómo he hecho esto con éxito. Solo me interesaba evitar que se ingresaran ciertos caracteres, así que solo implementé textView:shouldChangeTextInRange:replacementText: y luego pasé el resto.

#import "INFTextView.h" 

@interface INFTextView() <UITextViewDelegate> 

@property (nonatomic, weak) id<UITextViewDelegate> externalDelegate; 

@end 

@implementation INFTextView 

- (id)init { 
    self = [super init]; 
    if (!self) { 
     return nil; 
    } 

    self.delegate = self; 

    return self; 
} 

- (void)awakeFromNib { 
    self.delegate = self; 
} 

- (void)setDelegate:(id<UITextViewDelegate>)delegate { 
    // we always want self to be the delegate, if someone is interested in delegate calls we will forward those on if applicable 
    if (delegate == self) { 
     [super setDelegate:self]; 
     return; 
    } else { 
     // capture that someone else is interested in delegate calls 
     _externalDelegate = delegate; 
    } 
} 

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { 
    NSCharacterSet *unsupportedCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:kINFSupportedCharacters] invertedSet]; 

    NSRange unsupportedCharacterRange = [text rangeOfCharacterFromSet:unsupportedCharacterSet]; 
    if (unsupportedCharacterRange.location == NSNotFound) { 
     return YES; 
    } else { 
     return NO; 
    } 
} 

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView { 
    if ([_externalDelegate respondsToSelector:@selector(textViewShouldBeginEditing:)]) { 
     return [_externalDelegate textViewShouldBeginEditing:textView]; 
    } 

    return YES; 
} 

- (BOOL)textViewShouldEndEditing:(UITextView *)textView { 
    if ([_externalDelegate respondsToSelector:@selector(textViewShouldEndEditing:)]) { 
     return [_externalDelegate textViewShouldEndEditing:textView]; 
    } 

    return YES; 
} 

- (void)textViewDidBeginEditing:(UITextView *)textView { 
    if ([_externalDelegate respondsToSelector:@selector(textViewDidBeginEditing:)]) { 
     [_externalDelegate textViewDidBeginEditing:textView]; 
    } 
} 

- (void)textViewDidEndEditing:(UITextView *)textView { 
    if ([_externalDelegate respondsToSelector:@selector(textViewDidEndEditing:)]) { 
     [_externalDelegate textViewDidEndEditing:textView]; 
    } 
} 

- (void)textViewDidChange:(UITextView *)textView { 
    if ([_externalDelegate respondsToSelector:@selector(textViewDidChange:)]) { 
     [_externalDelegate textViewDidChange:textView]; 
    } 
} 

- (void)textViewDidChangeSelection:(UITextView *)textView { 
    if ([_externalDelegate respondsToSelector:@selector(textViewDidChangeSelection:)]) { 
     [_externalDelegate textViewDidChangeSelection:textView]; 
    } 
} 

@end 

Una gran 'Gotcha' lo que me llevó a esta pregunta se me estaba tratando de anular delegate para volver _externalDelegate pero que causó algunos efectos secundarios extraños (no deben ser un código interno que depende del delegado real que ser devueltos)