Gestión de Colecciones y Filtrado de Datos con NSPredicate en Foundation

El framework Foundation proporciona un conjunto robusto de clases para gestionar grupos de objetos. Estas colecciones son fundamentales en el desarrollo con Objective-C, permitiendo organizar, ordenar y filtrar datos de manera eficiente. En este artículo, analizaremos las tres estructuras principales (NSArray, NSDictionary y NSSet) y el uso de predicados para la selección de datos.

Estructuras de Datos en Foundation

1. Arrays: Listas Ordenadas (NSArray y NSMutableArray)

Los arrays en Foundation son colecciones ordenadas basadas en índices (comenzando en 0). Un NSArray es inmutable, mientras que un NSMutableArray permite modificar su contenido dinámicamente.

// Creación de un array inmutable con sintaxis moderna
NSArray *frutas = @[@"Manzana", @"Pera", @"Naranja"];

// Acceso a elementos
NSString *primeraFruta = frutas[0];
NSUInteger total = [frutas count];

// Iteración eficiente mediante bloques
[frutas enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
    NSLog(@"Fruta en índice %lu: %@", (unsigned long)idx, obj);
}];

// Manipulación de strings y arrays
NSString *cadenaCSV = @"iOS,Android,Web";
NSArray *plataformas = [cadenaCSV componentsSeparatedByString:@","];
NSString *unificado = [plataformas componentsJoinedByString:@" | "];

// Array mutable
NSMutableArray *listaTareas = [NSMutableArray arrayWithCapacity:5];
[listaTareas addObject:@"Lavar auto"];
[listaTareas insertObject:@"Estudiar" atIndex:0];

Nota técnica: Estas colecciones solo pueden almacenar objetos (derivados de NSObject). No es posible guardar tipos primitivos como int o float directamente; deben envolverse en NSNumber. Tampoco se permite almacenar nil.

2. Diccionarios: Pares Clave-Valor (NSDictionary)

Los diccionarios funcionan de manera similar a un mapa o un objeto JSON, donde cada valor se asocia a una clave única.

// Creación de diccionario mutable
NSMutableDictionary *configuracion = [NSMutableDictionary dictionary];

// Insertar datos
[configuracion setObject:@"Oscuro" forKey:@"tema"];
configuracion[@"brillo"] = @85;

// Obtener y eliminar
NSString *temaActual = [configuracion objectForKey:@"tema"];
[configuracion removeObjectForKey:@"brillo"];

// Iteración de claves y valores
for (NSString *key in configuracion) {
    NSLog(@"Clave: %@ - Valor: %@", key, configuracion[key]);
}

3. Conjuntos: Elementos Únicos (NSSet)

A diferencia de los arrays, los sets no garantizan un orden, pero aseguran que cada objeto sea único. Son ideales para operaciones matemáticas de conjuntos.

NSSet *setA = [NSSet setWithObjects:@1, @2, @3, nil];
NSSet *setB = [NSSet setWithObjects:@3, @4, @5, nil];

// Comprobar pertenencia
BOOL existe = [setA containsObject:@2];

// Operaciones de conjuntos (requiere NSMutableSet)
NSMutableSet *interseccion = [setA mutableCopy];
[interseccion intersectSet:setB]; // Resultado: {@3}

Filtrado de Datos con NSPredicate

NSPredicate es una herramienta poderosa que define criterios lógicos para filtrar colecciones o evaluar objetos individuales.

Sintaxis y Formato

Existen varias formas de definir un predicado, desde comparaciones simples hasta el uso de variables dinámicas.

// Comparación simple de cadenas
NSPredicate *predicadoNombre = [NSPredicate predicateWithFormat:@"nombre == 'iPhone'"];

// Uso de especificadores de formato
NSPredicate *predicadoPrecio = [NSPredicate predicateWithFormat:@"precio > %d", 500];

// Uso de claves dinámicas (%K)
NSString *propiedad = @"marca";
NSPredicate *dinamico = [NSPredicate predicateWithFormat:@"%K BEGINSWITH %@", propiedad, @"App"];

Variables de Sustitución

Para predicados reutilizables, se pueden emplear plantillas con el símbolo $.

NSPredicate *plantilla = [NSPredicate predicateWithFormat:@"categoria == $CAT"];
NSDictionary *variables = @{@"CAT": @"Electrónica"};
NSPredicate *final = [plantilla predicateWithSubstitutionVariables:variables];

Filtrado de Arrays

Supongamos que tenemos una lista de objetos de tipo Vehiculo con propiedades modelo y potencia.

NSArray *inventario = @[vehiculo1, vehiculo2, vehiculo3];

// Filtrar todos los vehículos con potencia superior a 200cv
NSPredicate *filtroPotencia = [NSPredicate predicateWithFormat:@"potencia > 200"];
NSArray *vehiculosPotentes = [inventario filteredArrayUsingPredicate:filtroPotencia];

// Evaluar un solo objeto
BOOL esPotente = [filtroPotencia evaluateWithObject:vehiculo1];

Operadores Avanzados

  • Rangos: BETWEEN {min, max}
  • Pertenencia: IN {val1, val2, ...}
  • Cadenas: CONTAINS, BEGINSWITH, ENDSWITH
  • Comodines: LIKE (permite * y ?). Se puede añadir [cd] para ignorar mayúsculas y acentos.
// Buscar modelos que contengan "sport" ignorando mayúsculas
NSPredicate *filtroTexto = [NSPredicate predicateWithFormat:@"modelo LIKE[cd] '*sport*'"];

// Filtrado compuesto
NSPredicate *compuesto = [NSPredicate predicateWithFormat:@"potencia > 100 AND modelo IN {'Sedan', 'SUV'}"];

Ejemplo Práctico: Búsqueda de Archivos

A continuación, un ejemplo de cómo combinar colecciones y lógica de filtrado para encontrar archivos específicos en el sistema.

void buscarDocumentosPNG() {
    NSFileManager *fm = [NSFileManager defaultManager];
    NSString *rutaUsuario = NSHomeDirectory();
    
    // Enumerador de directorio
    NSDirectoryEnumerator *enumerador = [fm enumeratorAtPath:rutaUsuario];
    NSMutableArray *archivosEncontrados = [NSMutableArray array];
    
    // Filtrado manual durante la iteración
    for (NSString *archivo in enumerador) {
        if ([[archivo pathExtension] isEqualToString:@"png"]) {
            [archivosEncontrados addObject:archivo];
        }
    }
    
    // Imprimir resultados
    for (NSString *item in archivosEncontrados) {
        NSLog(@"Imagen hallada: %@", item);
    }
}

Etiquetas: Objective-C Foundation NSArray NSDictionary NSSet

Publicado el 8-20 06:04