Cómo utilizar el primer carácter de un nombre de sección

Estoy utilizando Datos Básicos para la vista de la tabla, y me gustaría utilizar la primera letra de cada una de mis resultados como el encabezado de la sección (para que yo pueda llegar a la sección de índice en el lado). Es allí una manera de hacer esto con la ruta de la clave? Algo como la siguiente, donde puedo usar name.firstLetter como el sectionNameKeyPath (que por desgracia no funciona).

¿Tengo que agarrar a la primera letra de cada uno de los resultados de forma manual y crear mis secciones como que? Es mejor poner en una nueva propiedad que acaba de celebrar la primera letra y usar eso como la sectionNameKeyPath?

NSFetchedResultsController *aFetchedResultsController = 
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
            managedObjectContext:managedObjectContext
            sectionNameKeyPath:@"name.firstLetter"
            cacheName:@"Root"];

Gracias.

**EDITAR: ** no estoy seguro si hace una diferencia, pero mis resultados son Japoneses, ordenados por el Katakana. Quiero usar estos Katakana como el índice de sección.

InformationsquelleAutor nevan king | 2009-11-16

6 Kommentare

  1. 79

    Sólo debe pasar «nombre» como el sectionNameKeyPath. Ver este respuesta a la pregunta «Núcleo de Datos de copia de UITableView con la indexación».

    ACTUALIZACIÓN

    Esa solución sólo funciona si sólo se preocupan por tener el rápido índice de título barra de desplazamiento. En ese caso, NO sería mostrar los encabezados de sección. Vea a continuación para el código de ejemplo.

    Lo contrario, estoy de acuerdo con refulgentis que un transitorio de la propiedad es la mejor solución. También, cuando la creación de la NSFetchedResultsController, el sectionNameKeyPath tiene esta limitación:

    Si esta ruta de la clave no es la misma que
    que el especificado por el primer criterio de ordenación
    descriptor en fetchRequest, deben
    generar la misma en relación ordenamientos.
    Por ejemplo, el primer tipo de descriptor de
    en fetchRequest puede especificar la clave
    para una persistente de la propiedad;
    sectionNameKeyPath puede especificar una clave de
    para los transitorios de la propiedad derivados de
    la persistencia de la propiedad.

    Repetitivo UITableViewDataSource implementaciones de uso NSFetchedResultsController:

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        return [[fetchedResultsController sections] count];
    }
    
    - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
        return [fetchedResultsController sectionIndexTitles];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
        return [fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
        return [sectionInfo numberOfObjects];
    }
    
    //Don't implement this since each "name" is its own section:
    //- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    //   id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    //   return [sectionInfo name];
    //}

    ACTUALIZACIÓN 2

    De la nueva ‘uppercaseFirstLetterOfName transitorio de la propiedad, agregar un nuevo atributo de cadena para la aplicable a la entidad en el modelo y comprobar el «transitorio» del cuadro.

    Hay un par de maneras de implementar la función de captador. Si la generación/creación de subclases, entonces usted puede agregar en la subclase de la aplicación (.m) archivo.

    De lo contrario, puede crear una categoría en NSManagedObject (pongo este derecho en la parte superior de mi punto de vista controlador del archivo de implementación, pero se puede dividir entre un adecuado y el encabezado del archivo de implementación de su propia):

    @interface NSManagedObject (FirstLetter)
    - (NSString *)uppercaseFirstLetterOfName;
    @end
    
    @implementation NSManagedObject (FirstLetter)
    - (NSString *)uppercaseFirstLetterOfName {
        [self willAccessValueForKey:@"uppercaseFirstLetterOfName"];
        NSString *aString = [[self valueForKey:@"name"] uppercaseString];
    
        //support UTF-16:
        NSString *stringToReturn = [aString substringWithRange:[aString rangeOfComposedCharacterSequenceAtIndex:0]];
    
        //OR no UTF-16 support:
        //NSString *stringToReturn = [aString substringToIndex:1];
    
        [self didAccessValueForKey:@"uppercaseFirstLetterOfName"];
        return stringToReturn;
    }
    @end

    También, en esta versión, no olvide pasar ‘uppercaseFirstLetterOfName’ como el sectionNameKeyPath:

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext
    sectionNameKeyPath:@"uppercaseFirstLetterOfName" //this key defines the sections
    cacheName:@"Root"];

    Y, para descomentar tableView:titleForHeaderInSection: en el UITableViewDataSource aplicación:

    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
        return [sectionInfo name];
    }
    • He intentado poner el nombre en el sectionNameKeyPath, pero terminó con una sección para cada nombre devuelto. Tengo tantas secciones como eran los nombres, cada sección con una sola entrada (el nombre).
    • Puede que no tenga las cosas bien configurado. Dar la respuesta otra lectura. Funciona como se anuncia.
    • Yo no creo que la respuesta de las «obras» de por sí, no sé por qué el respondedor actuado como si de un milagro para utilizar el primer nombre como la ruta de la clave.
    • Buen punto. Solo funciona con el índice y el rápido índice de desplazamiento, no para los encabezados de sección. He actualizado mi respuesta adecuada.
    • +1. Gran solución, y me gusta especialmente evitando cualquier cambio en el modelo de datos mediante el uso de una categoría. Mi única refinamiento en esta era agregar la categoría para mi clase de Entidad en lugar de NSManagedObject.
    • Se puede poner a la derecha en la definición de clase personalizado en lugar de una categoría. Si usted está preocupado acerca de que sobreescritos cuando el auto-generación de los archivos de clase, usted debe comprobar fuera de mogenerator: rentzsch.github.com/mogenerator
    • Lo que proponemos es más complicado. ¿Por qué no utilizar una categoría y evitar no sólo que se sobrescriba el problema, sino de evitar la creación de una dependencia en algunos 3ª parte del paquete?
    • Tuve la gran dificultad para realizar este trabajo. La solución para mí estaba haciendo [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)] en lugar de [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES] ya que uno de mis objetos comenzó con un carácter en minúsculas.
    • Para la posteridad: tuve que espolvorear un poco de tableView reloadData llama a mantener mi índice en sincronía con mis datos.
    • No veo la necesidad de que el willAccessValueForKey y didAccessValueForKey llamadas. Estás diciendo CD que usted está accediendo el valor que se está generando. No hay necesidad de eso.
    • Esta no es la solución perfecta! Doc: The fetch request must have at least one sort descriptor. If the controller generates sections, the first sort descriptor in the array is used to group the objects into sections; its key must either be the same as sectionNameKeyPath or the relative ordering using its key must match that using sectionNameKeyPath.. Ninguna de estas dos condiciones son satisfechas. Usted no se puede construir un tipo de descriptor transitoria de la propiedad (que siempre se bloquea para mí) ni el orden relativo no es coincidencia (si es que hay de todo en UTF8 conjunto, caseInsensitiveCompare: no es suficiente para que coincida).
    • llamar a la willAccessValueForKey es de carácter informativo a la base de Datos de paradigma por la documentación de Apple: developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…

  2. 11

    Puede haber una forma más elegante de hacer esto, pero recientemente he tenido el mismo problema y me encontré con esta solución.

    Primero, he definido un transitorio de la propiedad sobre los objetos que se indexación llamado firstLetterOfName, y escribió el captador en el .m archivo para el objeto.
    e.x.

    - (NSString *)uppercaseFirstLetterOfName {
        [self willAccessValueForKey:@"uppercaseFirstLetterOfName"];
        NSString *stringToReturn = [[self.name uppercaseString] substringToIndex:1];
        [self didAccessValueForKey:@"uppercaseFirstLetterOfName"];
        return stringToReturn;
    }

    Siguiente, puedo configurar mi recuperación solicitud/entidades para utilizar esta propiedad.

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Object" inManagedObjectContext:dataContext];
    [request setEntity:entity];
    [NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)];
    NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
    [request setSortDescriptors:sortDescriptors];

    Nota de lado, a propósito de nada: hay que tener cuidado con NSFetchedResultsController — no es exactamente completamente horneados sin embargo, en mi humilde opinión, y en cualquier situación, más allá de la simple los casos mencionados en la documentación, usted probablemente será mejor hacerlo de la ‘old fashioned’ manera.

    • +1 Transitorio de la propiedad es la mejor solución cuando se muestran los encabezados de sección.
    • Tenga cuidado de substringToIndex:! Si la cadena es un UTF-16 de la cadena, que sólo le agarra la primera mitad del primer carácter. La manera correcta de hacer esto es [aString subStringWithRange:[aString rangeOfComposedCharacterSequenceAtIndex:1]]
    • Gracias por la respuesta. No entiendo donde se llama a la uppercaseFirstLetterOfName método. Usted debe llamar a este lugar de caseInsensitiveCompare o hay otra manera es que se llama?
    • He añadido los detalles acerca de la transitoria de la propiedad como de la ACTUALIZACIÓN 2 de mi respuesta.
  3. 4

    Lo resuelto mediante la UILocalizedIndexCollation como se mencionó en el NSFetchedResultsController v. s. UILocalizedIndexedCollation pregunta

    • Esta es realmente la única manera de resolverlo. UILocalizedIndexCollation tiene un mucho de construido en el comportamiento, y la uppercaseFirstLetterOfName código sugerido en otras respuestas a la que no llega siquiera a acercarse. Como un simple ejemplo, UILocalizedIndexCollation correctamente se derrumba la mitad Japonés y Katakana de ancho completo en la sección correcta, con el nombre de la sección que se denota por la correcta carácter Hiragana – y que hace lo correcto para casi todos los otros idiomas en el mundo.
  4. 1

    La elegante forma es hacer que el «firstLetter» un transitorio de la propiedad, sin EMBARGO, en la práctica, que es lento.

    Es lento, porque para los transitorios de la propiedad para ser calculado, todo objeto que se necesita para ser fallados en la memoria. Si usted tiene una gran cantidad de registros, va a ser muy, muy lento.

    El ayuno, pero de forma poco elegante, es crear un no-transitorio «firstLetter» los bienes que actualizar cada vez que usted establezca su propiedad «nombre». Varias maneras de hacer esto: reemplazar el «setName:» asesor de reemplazo «willSave», KVO.

    • Fueron capaces de confirmar esto? Yo no podía ver la diferencia entre transitoria y persistente propiedades en mi proyecto.
    • Estoy cuestionando la «elegante» camino en el comentario de @gerry3 respuesta. Y «poco elegante» es aún más «poco elegante» que aparece. Los índices deben ser hechas de UILocalizedIndexedCollation. Así que usted debe restablecer cada entrada en el cambio de la configuración regional de la sospecha para que coincida con la corriente de intercalación con su primera letra.
  5. 1

    Ver mi respuesta a una pregunta similar aquí, en la que se describe cómo crear localizada sectionKey índices que se conservan (porque no se puede ordenar transitoria atributos en un NSFetchedResultsController).

  6. 0

    Aquí es la solución simple para obj-c, de varios años y un lenguaje tarde . Funciona y funciona de forma rápida en un proyecto de mina.

    Primero he creado una categoría en la NSString, nombrando el archivo NSString+Indexación. Escribí un método que devuelve la primera letra de una cadena de

    @implementation NSString (Indexing)
    
    - (NSString *)stringGroupByFirstInitial {
        if (!self.length || self.length == 1)
            return self;
        return [self substringToIndex:1];
    }

    Luego he utilizado ese método en la definición de la traída resultado controlador de la siguiente manera

    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"name.stringGroupByFirstInitial"
                                                                                   cacheName:nil];

    El código anterior en conjunción con los dos stringIndex métodos de trabajo sin necesidad de meterse con propiedades transitorias o el almacenamiento de un atributo independiente que sólo cuenta con la primera letra en los datos de los núcleos

    Sin embargo cuando intento hacer lo mismo con Swift lanza una excepción, ya que no le gusta tener una función como parte de la ruta de la clave (o calculados propiedad de la cadena – traté de que también) Si alguien sabe cómo conseguir lo mismo en Swift de todo corazón me encantaría saber cómo.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea