Configuración del estilo de UITableViewCell cuando se usa iOS 6 UITableView dequeueReusableCellWithIdentifier: forIndexPath:

82

Estoy tratando de averiguar cómo configurar el UITableViewCellStyleal usar los nuevos métodos en iOS 6 para UITableView.

Anteriormente, al crear un UITableViewCell, cambiaba la UITableViewCellStyleenumeración para crear diferentes tipos de celdas predeterminadas al llamar, initWithStyle:pero por lo que puedo recopilar, este ya no es el caso.

La documentación de Apple para los UITableViewestados:

Valor de retorno : un objeto UITableViewCell con el identificador de reutilización asociado. Este método siempre devuelve una celda válida.

Discusión : Por razones de rendimiento, la fuente de datos de una vista de tabla generalmente debe reutilizar objetos UITableViewCell cuando asigna celdas a filas en su método tableView: cellForRowAtIndexPath :. Una vista de tabla mantiene una cola o lista de objetos UITableViewCell que la fuente de datos ha marcado para su reutilización. Llame a este método desde su objeto de fuente de datos cuando se le solicite que proporcione una nueva celda para la vista de tabla. Este método quita la cola de una celda existente si hay una disponible o crea una nueva basada en la clase o archivo nib que registró anteriormente.

Importante : Debe registrar una clase o un archivo nib utilizando el método registerNib: forCellReuseIdentifier: o registerClass: forCellReuseIdentifier: antes de llamar a este método.

Si registró una clase para el identificador especificado y se debe crear una nueva celda, este método inicializa la celda llamando a su método initWithStyle: reuseIdentifier:. Para las celdas basadas en plumillas, este método carga el objeto de celda desde el archivo de plumillas proporcionado. Si una celda existente estaba disponible para su reutilización, este método llama al método prepareForReuse de la celda en su lugar.

Así es como se cellForRowAtIndexPathve mi nuevo después de implementar los nuevos métodos:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"cell_identifier";

    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    return cell;
}

El código que tengo hasta ahora funciona bien pero siempre devuelve el estilo predeterminado. ¿Cómo puedo cambiar esto para que pueda crear células con los otros estilos como UITableViewCellStyleDefault, UITableViewCellStyleValue1, UITableViewCellStyleValue2y UITableViewCellStyleSubtitle?

No quiero hacer una subclase UITableViewCell, solo quiero cambiar el tipo predeterminado como podía hacer antes de iOS 6. Parece extraño que Apple proporcione métodos mejorados pero con documentación mínima para respaldar su implementación.

¿Alguien ha dominado esto o se ha encontrado con un problema similar? Estoy luchando por encontrar alguna información razonable.

CapitánRedmuff
fuente

Respuestas:

106

Sé que dijiste que no querías crear una subclase, pero parece inevitable. Basado en el código ensamblador durante la prueba en el simulador de iOS 6.0, UITableViewcrea nuevas instancias de UITableViewCell(o sus subclases) realizando

[[<RegisteredClass> alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:<ReuseIdentifier>]

En otras palabras, el estilo enviado ( UITableViewCellStyleDefault) parece estar codificado. Para evitar esto, deberá crear una subclase que anule el inicializador predeterminado initWithStyle:reuseIdentifier:y pase el estilo que desea usar:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    // ignore the style argument, use our own to override
    self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier];
    if (self) {
        // If you need any further customization
    }
    return self;
}

Además, podría ser mejor enviar , registerClass:forCellReuseIdentifier:en viewDidLoadlugar de hacerlo cada vez que se solicita una celda:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView registerClass:<RegisteredClass> forCellReuseIdentifier:<ReuseIdentifier>];
}
bolot
fuente
4
Estaba empezando a asumir que este sería el caso. No es un problema importante, pero tener UITableViewCellque crear una subclase para obtener los otros estilos predeterminados es un problema, ya que solo crea archivos innecesarios. Gracias por tu comentario y confirmando mis sospechas.
CaptainRedmuff
11
No olvide que en lugar de subclasificar, puede utilizar el antiguo método iOS5, que sigue siendo válido. De esa manera, puede inicializar cualquier tipo de estilo de celda que desee. Vea la otra respuesta.
SpacyRicochet
60

dequeueReusableCellWithIdentifierno está obsoleto, por lo que no es necesario que utilice el nuevo dequeueReusableCellWithIdentifier:forIndexPath:.

Use la nueva forma junto con el método de registro apropiado (en viewDidLoad) si está usando una clase de celda personalizada, pero use la forma anterior si desea usar una de las enumeraciones UITableViewCellStyle.

Murray Sagal
fuente
1
Votado a favor por señalar que no tienes que usar los nuevos métodos elegantes. Solo si se adaptan a su propósito o si las alternativas están desaprobadas.
SpacyRicochet
Si está especialmente interesado, está bien anular dequeueReusableCellWithIdentifier:forIndexPath:para proporcionar algunos identificadores que construyen celdas de la manera anterior (y las devuelven). Otros identificadores llamarán super y devolverán eso. Podría tener sentido tener un NSDictionaryde identificadores para bloques constructores para ese tipo de identificador.
Benjohn
11

Puede evitar una subclase extraña utilizando el generador de interfaz de guión gráfico:

  1. En la vista Storyboard, seleccione la celda prototipo de celda de la vista de tabla (en la vista de tabla)
  2. En la vista Utilidades, en el inspector de atributos, modifique el valor de Estilo
  3. (Opcionalmente) Modifique otros valores como Selección y Accesorio

El nuevo iOS 6.0 dequeueReusableCellWithIdentifier:forIndexPath:usa esos valores al asignar nuevas celdas y devolverlas. (Probado en una compilación de iOS 6.0 usando Xcode 4.5.2)

Jeff Collier
fuente
7

Otra alternativa que guarda un archivo es crear un Nib y usarlo registerNib:forCellReuseIdentifier:en su lugar.

Hacer la punta es fácil: cree un nuevo archivo .xib en Interface Builder. Elimina la vista predeterminada. Agregue un objeto de celda de vista de tabla. Con el Inspector de atributos, cambie el estilo de la celda. (Aquí también tiene la oportunidad de personalizar aún más la celda ajustando otros atributos).

Luego, en el viewDidLoadmétodo del controlador de vista de tabla, llame a algo como:

[self.tableView registerNib:[UINib nibWithNibName:@"StyleSubtitleTableCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"Cell"];
Sr. Berna
fuente
initWithStyle: no se llama a reuseIdentifier.
thierryb
0

La respuesta de Bolot es la correcta. Simple y no necesita crear ningún archivo XIB.

Solo quería actualizar su respuesta para quien lo esté haciendo usando Swift en lugar de Objective-C:

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: .value1, reuseIdentifier: reuseIdentifier)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
Gabriel Oliva
fuente
-5

Mi solución a esto es llamar initWithStyle: reuseIdentifier:después de haberlo obtenido usando [self.tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath]. Después de todo, inites solo otro selector y el compilador no impone restricciones para llamarlo en un objeto ya inicializado. Sin embargo, se quejará de no usar el resultado de llamar a init, así que lo hago:

UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath];
cell = [cell initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cellId"];

Imagino que esto no funcionará en Swift ...

Chris
fuente
La solución más elegante en mi opinión. Con suerte, las agallas de initWithStyle no vuelven a crear todo de nuevo.
Scott Birksted
2
Bueno, supongo que si lo estás haciendo así, puedes dejar las cosas de quitar la cola por completo ...
stk
1
La reutilización de células es clave para un UITableView eficaz. Su solución sugiere no reutilizar las células.
Berik
2
Cuando llama por initWithStyle: reuseIdentifiersegunda vez, en realidad está sobrescribiendo la celda con un objeto recién creado. Sí, la asignación de la memoria ya se realizó y la nueva celda sobrescribirá la misma ubicación de memoria, pero en realidad está creando un objeto completamente nuevo cuando lo inicializa nuevamente. Esto niega toda la optimización que es el objetivo de reutilizar celdas en primer lugar.
AnthonyMDev
1
No es una buena solución a seguir: si está utilizando esta solución, creo que al menos es mejor eliminar la
eliminación de la cola de