¿Cómo eliminar una subvista específica?

He agregado una subvista (ViewController) a mi ViewController:

Location *location = [[Location alloc] initWithNibName:@"Location" bundle:[NSBundle mainBundle]];
[self.subView addSubview:location.view];

¿Cómo puedo eliminar esta subvista?

Sé que para eliminar todas las subvistas es:

for (UIView *subview in [self.view subviews]) {

  [subview removeFromSuperview];

}

preguntado el 03 de mayo de 12 a las 17:05

Realmente no debería agregar la vista de otro viewController a la vista de un viewController existente de esa manera:

¿No hay forma de que pueda eliminar esa subvista agregada? -

Bueno, puedes, pero solo estaba haciendo una observación, sobre un punto de dolor potencial y la raíz de muchos errores complicados. Si desea eliminar esa vista en particular, ¿por qué no crear un ivar que le proporcione una referencia a la location viewController de la view en sí mismo y luego no necesita escalar a través de las subvistas... -

¿Puede explicar eso con más detalles porque no entiendo o dar mi enlace a un ejemplo? -

3 Respuestas

Rápido y sucio: Asigne una etiqueta a su vista, para que luego pueda identificarla:

Location *location = [[Location alloc] initWithNibName:@"Location" bundle:[NSBundle mainBundle]];
UIView *viewToAdd = location.view;
viewToAdd.tag = 17; //you can use any number you like
[self.view addSubview:viewToAdd];

Luego, para eliminar:

UIView *viewToRemove = [self.view viewWithTag:17];
[viewToRemove removeFromSuperview];

A más limpio, más rápido, más fácil de leer y de mantener alternativa sería crear una variable o propiedad para acceder a la vista:

En la interfaz:

@property (nonatomic, weak) UIView *locationView;

En la implementación:

Location *location = [[Location alloc] initWithNibName:@"Location" bundle:[NSBundle mainBundle]];
UIView *viewToAdd = location.view;
self.locationView = viewToAdd;
[self.view addSubview:viewToAdd];

Luego, para eliminar:

[self.locationView removeFromSuperview];

Dicho esto, preste atención a las advertencias de los comentaristas sobre jugar con las Vistas de otros ViewControllers. Leer sobre Contención de ViewController si quieres hacerlo

Respondido 27 Oct 14, 16:10

viewWithTag: = ¡Puaj! Si necesita un identificador para una vista, ¿por qué no se da uno adecuado sin pasar por una jerarquía de vistas pidiendo a cada vista un número arbitrario que cualquiera puede cambiar accidentalmente? - Pablo.s

Porque esto responde a la pregunta genérica que tenía el autor de la pregunta sin tener que introducir iVars ni cambiar nada más que esas dos llamadas. Muy rara vez etiqueto mis vistas (y si es así, principalmente para depurar), pero aquí finalmente tiene un uso. - fzwo

Eso es solo fomentar un mal diseño... (También cuando respondes a las personas, haz eso @ o no reciben una notificación y es posible que nunca sepan que respondiste...) - Pablo.s

@ Paul.s Estoy de acuerdo en que no es genial, pero no creo que tu publicación explique qué (y por qué) lo suficientemente bien como para fomentar un mejor diseño (no te notifiquen porque tu comentario está directamente encima del mío, y comentaste en mi post? Admito que lo olvidé). - fzwo

No, parece un poco tonto, pero solo recibiría una notificación si comentara mi pregunta/respuesta o usara @myName. Ah, bueno, supongo que si el OP no entiende algo, lo buscarán, que es la mejor manera de aprender. Siempre puede mejorar ligeramente el estándar de su respuesta agregando constantes en lugar de números mágicos;) al menos entonces podría estremecerme un poco menos: Pablo.s

Cree un ivar que le proporcione una referencia al nuevo controlador de vista o solo a la vista. Iré por el viewController aquí

Añadir una propiedad y sintetizarla

// .h
@property (nonatomic, strong) Location *location;

// .m
@synthesize location = _location;

Ahora, cuando crees una ubicación, configura el ivar

Location *location = [[Location alloc] initWithNibName:@"Location" bundle:[NSBundle mainBundle]];
self.location = location;

[self.subView addSubview:location.view];

Ahora más tarde para quitarlo

[self.location.view removeFromSuperview];

Nota al margen

En general, es un camino doloroso agregar la vista de un controlador de vista a la vista de otro como este. Para una lectura ligera sobre esto ver Abusar de UIViewControllers

tu nombre de Location probablemente no es excelente, puede ser más apropiado llamarlo algo como LocationViewController o similar. La nomenclatura consistente de esta manera permite que cualquier otra persona (o usted en el futuro) pueda leer y comprender fácilmente que se trata de un controlador de vista sin abrir el encabezado.

Respondido el 20 de junio de 20 a las 10:06

Excelente punto sobre la denominación (y los ViewControllers). Esta solución es más limpia que la mía a continuación. - fzwo

Simplemente podría establecer una etiqueta única para su vista que la identifique. Y luego cuando quieras quitarlo. Utilizar el viewWithTag:(NSInteger)tag método para recuperarlo y eliminar solo este.

Location *location = [[Location alloc] initWithNibName:@"Location" bundle:[NSBundle mainBundle]];
location.tag = 8001; // 8001 is an exemple
[self.subView addSubview:location.view];

Y entonces

UIView * v = [self.subView viewWithTag:8001];
if (nil != v) {
    [v removeFromSuperview];
}

contestado el 03 de mayo de 12 a las 17:05

La comprobación de cero no es necesaria en Objective-C; de lo contrario, esto es solo un duplicado de mi respuesta, y @ Paul.s ya dio la respuesta más limpia de todos modos. - fzwo

Lo hicimos casi en el mismo momento. Pero la buena escritura explica las cosas ;-) No me gusta abusar del sistema al no revisar el mensaje que se envía. No envíe un mensaje al objeto si no tiene que hacerlo o si no es necesario. Esto es inútil y puede resultar muy costoso en un entorno de bucle grande. - Vaseltior

Enviar mensajes a nil casi no tiene una sobrecarga mayor que verificar if (foo != nil), porque objc_msgSend verifica eso primero y regresa temprano. Esto es no abusar del sistema, es usar la belleza del sistema. La verificación de Null es para otros idiomas. - fzwo

A veces tienes que hacer cálculos de alto rendimiento, a veces no. Es por eso que mantengo esta forma híbrida y aún fundamental de codificación. Y esto ayudará a su sucesor a comprender lo que está haciendo. ¿Tienes alguna pista o enlace que muestre que objc_msgSend comprueba eso primero? Estoy muy interesado en los sótanos de ObjC. - Vaseltior

No sea víctima de una optimización prematura: optimizar objc_msgSend solo tiene sentido después de haber realizado todas las demás optimizaciones. Aquí es un excelente artículo detallado sobre esto de @bbum, y un Evaluación del desempeño por Mike Ash en un iPhone 1. Vea también las excelentes respuestas a stackoverflow.com/questions/2962466/… - especialmente también las dos respuestas no aceptadas. - fzwo

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.