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);
}
}