Trabajar con NSURLSession Parte 3

En los tutoriales anteriores, exploramos los fundamentos de la SESIÓN API. Hay otra característica de la SESIÓN API que aún no hemos examinado, es decir, subidas y descargas fuera de proceso. En los siguientes dos tutoriales, te mostraré cómo crear un cliente de podcast muy simple que permita descargas en segundo plano..


Introducción

El cliente de podcast que estamos a punto de crear no será realmente tan funcional. Le permitirá al usuario consultar la API de búsqueda de iTunes para obtener una lista de podcasts, seleccionar un podcast y descargar episodios. Ya que nos estamos enfocando en el SESIÓN API, no entraremos a reproducir los episodios que descarga la aplicación..

Sin embargo, el proyecto le enseñará cómo usar tareas de datos y descargar tareas en una aplicación del mundo real. El cliente de podcast también habilitará descargas en segundo plano para las que aprovecharemos SESIÓNAPI fuera de proceso. Tenemos algunas cosas que hacer, así que no perdamos tiempo y comencemos..


1. Configuración del proyecto

Encienda el Xcode 5, seleccione Nuevo> Proyecto ... desde el Expediente menú, y elija la Solicitud de vista única Plantilla de la lista de plantillas de aplicaciones iOS. Nombra la aplicación Singlecast, selecciona el Familia de dispositivos a iPhone, y dile a Xcode dónde te gustaría guardar el proyecto. Golpear Crear para crear el proyecto.




2. Actualizar Storyboard

Lo primero que debemos hacer es editar el guión gráfico principal del proyecto. Abierto Main.storyboard, Seleccione el único controlador de vista del guión gráfico y elija Insertar en> Controlador de navegación desde el Editor menú. La razón para incrustar el controlador de vista en un controlador de navegación se aclarará más adelante en este tutorial..



3. Controlador de vista de búsqueda

Paso 1: Crear archivos de clase

Como mencioné en la introducción, para mantener las cosas simples, el usuario solo podrá suscribirse a un podcast. Vamos a empezar por crear el controlador de vista de búsqueda. Seleccionar Nuevo> Archivo ... desde el Expediente menú y elegir Clase objetiva-c De las opciones de la derecha. Nombra la clase MTSearchViewController y convertirlo en una subclase de UIViewController. Deje la casilla marcada Con XIB para la interfaz de usuario. desenfrenado. Dile a Xcode dónde quieres guardar los archivos de clase y pulsa Crear.


Paso 2: Actualizar la interfaz de clase

Antes de crear la interfaz de usuario, abra el archivo de encabezado del controlador de vista y actualice la interfaz de la clase como se muestra a continuación. Especificamos que la MTSearchViewController clase se ajusta a la UITableViewDataSource, UITableViewDelegate, y UISearchBarDelegate Protocolos, declaramos dos salidas., barra de búsqueda y tableView así como una acción, cancelar, para descartar el controlador de vista de búsqueda.

 #importar  @interface MTSearchViewController: UIViewController  @ propiedad (débil, no atómica) IBOutlet UISearchBar * searchBar; @ propiedad (débil, no atómica) IBOutlet UITableView * tableView; - (IBAction) cancelar: (id) remitente; @fin

Paso 3: Crear interfaz de usuario

Revise el guión gráfico principal del proyecto y arrastre un nuevo controlador de vista desde el Biblioteca de objetos a la derecha. Seleccione el nuevo controlador de vista, abra el Inspector de identidad a la derecha, y configura la clase del controlador de vista a MTSearchViewController. Con el nuevo controlador de vista aún seleccionado, abra el Editor menú y elegir Insertar en> Controlador de navegación. Arrastre una vista de tabla a la vista del controlador de vista y conecte la vista de tabla fuente de datos y delegar puntos de venta con el controlador de vista de búsqueda.


Con la vista de tabla aún seleccionada, abra el Inspector de atributos, y establecer el número de células prototipo para 1. Seleccione la celda prototipo y establezca su propiedad de estilo en Subtitular y su identificador a SearchCell.


Arrastre una barra de búsqueda de la Biblioteca de objetos y agregarlo a la vista de encabezado de la vista de tabla. Selecciona la barra de búsqueda y conecta su delegar toma de corriente con el controlador de vista.


Seleccione el controlador de vista y conecte su barra de búsqueda y tableView Outlets con la barra de búsqueda y vista de tabla respectivamente. Hay algunas otras cosas que debemos hacer antes de que terminemos con el guión gráfico.

Abre el Biblioteca de objetos y arrastre un elemento del botón de la barra a la barra de navegación. Seleccione el elemento del botón de la barra, conéctelo con el cancelar: Acción que declaramos en la interfaz del controlador de vista de búsqueda, y cambiamos su Identificador en el Inspector de atributos a Cancelar.


Arrastre un elemento del botón de la barra a la barra de navegación del controlador de vista (no del controlador de vista de búsqueda) y cambie su Identificador en el Inspector de atributos a Añadir. Controle el arrastre desde el elemento del botón de la barra al controlador de navegación del controlador de vista de búsqueda y seleccione modal Del menú que aparece. Esto crea un segmento del controlador de vista al controlador de navegación del controlador de vista de búsqueda.

Si tuviera que controlar el arrastre desde el elemento del botón de la barra del controlador de la vista directamente al controlador de la vista de búsqueda en lugar de su controlador de navegación, el controlador de navegación nunca se instanciará y no verá una barra de navegación en la parte superior del controlador de la vista de búsqueda.

Paso 4: Implementación de la vista de tabla

Antes de implementar el UITableViewDataSource y UITableViewDelegate protocolos en el MTSearchViewController Clase, debemos declarar una propiedad que almacena los resultados de búsqueda que obtendremos de la API de búsqueda de iTunes. Nombra la propiedad podcasts Como se muestra abajo. También declaramos una cadena estática que servirá como un identificador de reutilización de celda. Corresponde al identificador que configuramos en la celda prototipo hace unos momentos..

 #importar "MTSearchViewController.h" @interface MTSearchViewController () @property (strong, nonatomic) NSMutableArray * podcasts; @fin
 NSString estático * SearchCell = @ "SearchCell";

La implementación de numberOfSectionsInTableView: Es tan fácil como es posible. Regresamos 1 Si self.podcasts no es nulo y 0 si esto es. La implementación de tableView: numberOfRowsInSection: Es bastante similar como se puede ver a continuación. En tableView: cellForRowAtIndexPath:, solicitamos a la vista de tabla una celda pasando el identificador de reutilización de celda, que declaramos anteriormente, y indexPath. Obtenemos el artículo correspondiente de la podcasts fuente de datos y actualizar la celda de vista de tabla. Ambos tableView: canEditRowAtIndexPath: y tableView: canMoveRowAtIndexPath: regreso NO.

 - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return self.podcasts? 1: 0; 
 - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section return self.podcasts? self.podcasts.count: 0; 
 - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: SearchCell forIndexPath: indexPath]; // Fetch Podcast NSDictionary * podcast = [self.podcasts objectAtIndex: indexPath.row]; // Configurar la celda de vista de tabla [cell.textLabel setText: [podcast objectForKey: @ "collectionName"]]; [cell.detailTextLabel setText: [podcast objectForKey: @ "artistName"]]; celda de retorno 
 - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath return NO; 
 - (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath return NO; 

Antes de ejecutar la aplicación, implementar el cancelar: Acción en la que descartamos el controlador de vista de búsqueda..

 - (IBAction) cancel: (id) sender [self dismissViewControllerAnimated: YES completed: nil]; 

Genere el proyecto y ejecute la aplicación para asegurarse de que la base funciona como se espera. Es hora de empezar a usar el SESIÓN API para consultar la API de búsqueda de iTunes.

Paso 5: Crear una sesión

Comencemos por declarar dos propiedades privadas adicionales en el MTSearchViewController clase, sesión y Tarea de datos. los sesión variable se utiliza para almacenar una referencia a la SESIÓN Instancia que usaremos para consultar la API de Apple. También mantenemos una referencia a la tarea de datos que utilizaremos para la solicitud. Esto nos permitirá cancelar la tarea de datos si el usuario actualiza la consulta de búsqueda antes de que recibamos una respuesta de la API. Si tiene un ojo para los detalles, puede haber notado que el MTSearchViewController clase también se ajusta a la UIScrollViewDelegate protocolo. El motivo de esto quedará claro en unos minutos..

 #import "MTSearchViewController.h" @interface MTSearchViewController ()  @property (strong, nonatomic) NSURLSession * session; @property (strong, nonatomic) NSURLSessionDataTask * dataTask; @property (strong, nonatomic) NSMutableArray * podcasts; @fin

La sesión se crea en su método getter como se puede ver a continuación. Su implementación no debería contener sorpresas si has leído los tutoriales anteriores. Anulamos el método getter del sesión propiedad para cargar perezosamente la sesión y limitar la creación de instancias y la configuración de la sesión en su método getter. Esto hace que para código limpio y elegante.

 - (NSURLSession *) session if (! _Session) // Inicializar configuración de sesión NSURLSessionConfiguration * sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; // Configurar la configuración de la sesión [sessionConfiguration setHTTPAdditionalHeaders: @ @ "Aceptar": @ "application / json"]; // Inicializar sesión _session = [NSURLSession sessionWithConfiguration: sessionConfiguration];  return _session; 

Paso 6: Buscando

Para responder a la entrada del usuario en la barra de búsqueda, implementamos searchBar: textDidChange: del UISearchBarDelegate protocolo. La implementación es simple. Si buscar texto es nulo, El método regresa temprano. Si la longitud de buscar texto tiene menos de cuatro caracteres, restablecemos la búsqueda invocando reiniciarBuscar. Si la consulta es de cuatro caracteres o más, realizamos una búsqueda llamando realizarBúsqueda en el controlador de vista de búsqueda.

 - (void) searchBar: (UISearchBar *) searchBar textDidChange: (NSString *) searchText if (! searchText) return; si (searchText.length <= 3)  [self resetSearch];  else  [self performSearch];  

Antes de inspeccionar realizarBúsqueda, echemos un vistazo rápido a reiniciarBuscar. Todo lo que hacemos en reiniciarBuscar está limpiando el contenido de podcasts y recargando la vista de tabla.

 - (void) resetSearch // Actualizar fuente de datos [self.podcasts removeAllObjects]; // Actualizar vista de tabla [self.tableView reloadData]; 

El levantamiento de pesas se realiza en realizarBúsqueda. Después de almacenar la entrada del usuario en una variable llamada consulta, comprobamos si Tarea de datos Está establecido. Si está configurado, llamamos cancelar en eso. Esto es importante ya que no queremos recibir una respuesta de un antiguo Solicitud que ya no puede ser relevante para el usuario. Esta es también la razón por la que solo tenemos una tarea de datos activa a la vez. No hay ninguna ventaja en enviar múltiples solicitudes a la API.

A continuación, solicitamos a la sesión una nueva instancia de tarea de datos al pasarla NSURL instancia y un controlador de finalización. Recuerda que la sesión es la fábrica que crea tareas. Nunca debes crear tareas tú mismo. Si obtenemos una tarea de datos válida de la sesión, llamamos currículum en él como vimos en los tutoriales anteriores.

La lógica dentro del controlador de finalización es interesante por decir lo menos. los error El objeto es importante para nosotros por varias razones. No solo nos dirá si algo salió mal con la solicitud, sino que también es útil para determinar si la tarea de datos se canceló. Si obtenemos un objeto de error, verificamos si su código de error es igual a -999. Este código de error indica que la tarea de datos fue cancelada. Si obtenemos otro código de error, registramos el error en la consola. En una aplicación real, necesitaría mejorar el manejo de errores y notificar al usuario cuando se produce un error.

Si no se pasó ningún error al controlador de finalización, creamos un diccionario desde el NSData instancia que se pasó al controlador de finalización y extraemos los resultados de ella. Si tenemos una serie de resultados con los que trabajar, se lo pasamos a procesoResultados:. ¿Notaste que invocamos? procesoResultados: en un bloque GCD (Grand Central Dispatch)? ¿Por qué hicimos eso? Espero que lo recuerden, porque es un detalle muy importante. No tenemos ninguna garantía de que el controlador de finalización se invoque en el subproceso principal. Dado que necesitamos actualizar la vista de tabla en el subproceso principal, debemos asegurarnos de que procesoResultados: se llama en el hilo principal.

 - (void) performSearch NSString * query = self.searchBar.text; if (self.dataTask) [self.dataTask cancel];  self.dataTask = [self.session dataTaskWithURL: [self urlForQuery: query] completedHandler: ^ (NSData * data, NSURLResponse * response, NSError * error) if (error) if (error.code! = -999)  NSLog (@ "% @", error);  else else NSDictionary * result = [NSJSONSerialization JSONObjectWithData: opciones de datos: 0 error: nil]; NSArray * resultados = [resultado objectForKey: @ "resultados"]; dispatch_async (dispatch_get_main_queue (), ^ if (results) [self ProcessResults: results];); ]; if (self.dataTask) [self.dataTask resume]; 

Antes de ver la implementación de procesoResultados:, Quiero mostrarte rápidamente lo que pasa en urlForQuery:, El método auxiliar que usamos en realizarBúsqueda. En urlForQuery:, reemplazamos cualquier espacio con un + firme para asegurarse de que la API de búsqueda de iTunes esté de acuerdo con lo que le enviamos. Entonces creamos un NSURL instancia con él y devuélvalo.

 - (NSURL *) urlForQuery: (NSString *) query query = [query stringByReplacingOccurrencesOfString: @ "" withString: @ "+"]; return [NSURL URLWithString: [NSString stringWithFormat: @ "https://itunes.apple.com/search?media=podcast&entity=podcast&term=%@", consulta]]; 

En procesoResultados:, la podcasts Se borra la variable, se rellena con los contenidos de resultados, y los resultados se muestran en la vista de tabla..

 - (void) processResults: (NSArray *) resulta if (! self.podcasts) self.podcasts = [NSMutableArray array];  // Actualizar fuente de datos [self.podcasts removeAllObjects]; [self.podcasts addObjectsFromArray: resultados]; // Actualizar vista de tabla [self.tableView reloadData]; 

Paso 6: Seleccionando un Podcast

Cuando el usuario toca una fila en la vista de tabla para seleccionar un podcast, tableView: didSelectRowAtIndexPath: del UITableViewDelegate Se invoca el protocolo. Su implementación puede parecer extraña al principio, así que déjame explicarte lo que está pasando. Seleccionamos el podcast que corresponde con la selección del usuario, lo almacenamos en la base de datos predeterminada de usuario de la aplicación y descartamos el controlador de vista de búsqueda. ¿No notificamos a nadie sobre esto? Por qué hacemos esto quedará claro una vez que continuemos implementando el MTViewController clase.

 - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath [tableView deselectRowAtIndexPath: indexPath animated: YES]; // Fetch Podcast NSDictionary * podcast = [self.podcasts objectAtIndex: indexPath.row]; // Actualizar User Defatuls NSUserDefaults * ud = [NSUserDefaults standardUserDefaults]; [ud setObject: podcast forKey: @ "MTPodcast"]; [ud sincronizar]; // Descartar controlador de vista [self dismissViewControllerAnimated: YES completed: nil]; 

Paso 7: Toques finales

Hay dos detalles de los que quiero hablar antes de volver a la MTViewController clase. Cuando el controlador de la vista de búsqueda se presenta al usuario, está claro que quiere buscar podcasts. Por lo tanto, es una buena idea presentar inmediatamente el teclado. Hacemos esto en viewDidAppear: Como se muestra abajo.

 - (void) viewDidAppear: (BOOL) animated [super viewDidAppear: animated]; // Mostrar teclado [self.searchBar becomeFirstResponder]; 

El teclado debe ocultar el momento en que el usuario comienza a desplazarse por los resultados de búsqueda. Para lograr esto, implementamos scrollViewDidScroll: del UIScrollViewDelegate protocolo. Esto explica porque MTSearchViewController se ajusta a la UIScrollViewDelegate protocolo. Echa un vistazo a la implementación de scrollViewDidScroll: mostrado a continuación.

 - (void) scrollViewDidScroll: (UIScrollView *) scrollView if ([self.searchBar isFirstResponder]) [self.searchBar resignFirstResponder]; 
los UITableView clase es una subclase de UIScrollView, ¿Cuál es la razón por la que funciona el enfoque anterior.

4. Vuelta de vuelta

Como vimos anteriormente, almacenamos la selección del usuario en la base de datos predeterminada de usuario de la aplicación. Necesitamos actualizar el MTViewController Clase para hacer uso de la selección del usuario en el controlador de vista de búsqueda. En el controlador de vista viewDidLoad Método, cargamos el podcast desde la base de datos de valores predeterminados del usuario y agregamos el controlador de vista como observador de la base de datos de valores predeterminados del usuario para la ruta clave MTPodcast para que el controlador de vista sea notificado cuando el valor para MTPodcast cambios.

 - (void) viewDidLoad [super viewDidLoad]; // Load Podcast [self loadPodcast]; // Agregar Observer [[NSUserDefaults standardUserDefaults] addObserver: self forKeyPath: @ Opciones de "MTPodcast": NSKeyValueObservingOptionNew context: NULL]; 

Todo lo que hacemos en loadPodcast está almacenando el valor para MTPodcast desde la base de datos predeterminada de usuario en el controlador de vista podcast propiedad. Este valor será nulo Si la base de datos predeterminada del usuario no contiene una entrada para MTPodcast. El controlador de vista manejará con gracia esto por nosotros. Recuerde que, en Objective-C, puede enviar mensajes a nulo sin que todo el infierno se desate. Esto tiene sus desventajas, pero ciertamente tiene sus ventajas para.

 - (void) loadPodcast NSUserDefaults * ud = [NSUserDefaults standardUserDefaults]; self.podcast = [ud objectForKey: @ "MTPodcast"]; 

Esto también significa que necesitamos declarar una propiedad llamada podcast en el archivo de implementación del controlador de vista.

 #import "MTViewController.h" @interface MTViewController () @property (strong, nonatomic) NSDictionary * podcast; @fin

Echemos también un vistazo rápido a setPodcast: y updateView.

 - (void) setPodcast: (NSDictionary *) podcast if (_podcast! = podcast) _podcast = podcast; // Vista de actualización [self updateView]; 
 - (void) updateView // Update View self.title = [self.podcast objectForKey: @ "collectionName"]; 

Cuando el valor en la base de datos predeterminada del usuario cambia para la clave MTPodcast, El controlador de vista puede responder a este cambio en observeValueForKeyPath: ofObject: change: context:. Así es como funciona el valor clave de la observación. Todo lo que hacemos en este método es actualizar el valor del controlador de vista. podcast propiedad.

 - (void) observeValueForKeyPath: (NSString *) keyPath ofObject: (id) cambio de objeto: (NSDictionary *) cambia el contexto: (void *) context if ([keyPath isEqualToString: @ "MTPodcast"]) self.podcast = [object objectForKey: @ "MTPodcast"]; 

Cuando se trabaja con la observación de valores clave, es fundamental conocer la gestión de la memoria y retener los ciclos. En este caso, significa que debemos eliminar el controlador de vista como observador cuando el controlador de vista está desasignado.

 - (void) dealloc [[NSUserDefaults standardUserDefaults] removeObserver: self forKeyPath: @ "MTPodcast"]; 

5. Obteniendo y analizando la alimentación

Paso 1: Agregando Dependencias

La respuesta que recibimos de la API de búsqueda de iTunes incluye un URL para el canal Atributo para cada podcast. Podríamos obtener el feed manualmente y analizarlo. Sin embargo, para ahorrar algo de tiempo, haremos uso de MWFeedParser, una biblioteca popular que puede hacer esto por nosotros. Puede descargar manualmente e incluir la biblioteca en su proyecto, pero voy a optar por Cocoapods. Prefiero Cocoapods para administrar dependencias en proyectos iOS y OS X. Puedes leer más sobre Cocoapods en su sitio web o en Mobiletuts+.

Voy a asumir que la gema Cocoapods está instalada en su sistema. Puedes encontrar instrucciones detalladas en este tutorial..

Salga de Xcode, navegue hasta la raíz de su proyecto de Xcode y cree un archivo llamado Podfile. Abra este archivo en el editor de texto que prefiera y agregue las siguientes tres líneas de código. En la primera línea, especificamos la plataforma y el destino de la implementación, que es iOS 7 en este ejemplo. Las siguientes dos líneas especifican una dependencia de nuestro proyecto Xcode. El primero es el MWFeedParser biblioteca y también he incluido el popular SVProgressHUD biblioteca, que será útil un poco más tarde.

 plataforma: ios, '7' pod 'MWFeedParser' pod 'SVProgressHUD'

Abra una ventana de Terminal, navegue hasta la raíz de su proyecto Xcode y ejecute el comando instalación de la vaina. Esto debería instalar las dependencias y crear un espacio de trabajo de Xcode.. Cuando Cocoapods termina de instalar las dependencias del proyecto, le indica que use el espacio de trabajo que creó para usted. Esto es importante, así que no ignore este consejo.. En la raíz de su proyecto Xcode, verá que Cocoapods ha creado un espacio de trabajo Xcode para usted. Haga doble clic en este archivo y debería estar listo para ir.


Paso 2: Obteniendo y analizando la alimentación

Abra el archivo de implementación del MTViewController clase, agregue una declaración de importación para MWFeedParser y SVProgressHUD, y declarar dos propiedades, episodios y feedParser. También necesitamos hacer MTViewController conforme a la MWFeedParserDelegate protocolo.

 #import "MTViewController.h" #import "MWFeedParser.h" #import "SVProgressHUD.h" @interface MTViewController ()  @property (fuerte, no atómico) NSDictionary * podcast; Episodios de NSMutableArray * de @property (strong, nonatomic); @property (strong, nonatomic) MWFeedParser * feedParser; @fin

A continuación, actualizamos setPodcast: invocando fetchAndParseFeed, Un método de ayuda en el que usamos el MWFeedParser clase para buscar y analizar el feed del podcast.

 - (void) setPodcast: (NSDictionary *) podcast if (_podcast! = podcast) _podcast = podcast; // Vista de actualización [self updateView]; // Fetch and Parse Feed [self fetchAndParseFeed]; 

En fetchAndParseFeed, Nos deshacemos de nuestra corriente MWFeedParser instancia si tenemos una e inicializamos una nueva instancia con la URL del feed del podcast. Establecemos el feedParseType propiedad a ParseTypeFull y configura el controlador de vista como el delegado del analizador de fuentes. Antes de buscar el feed, utilizamos SVProgressHUD mostrar un HUD de progreso al usuario.

 - (void) fetchAndParseFeed if (! self.podcast) return; NSURL * url = [NSURL URLWithString: [self.podcast objectForKey: @ "feedUrl"]]; si (! url) regresa; if (self.feedParser) [self.feedParser stopParsing]; [self.feedParser setDelegate: nil]; [self setFeedParser: nil];  // Borrar episodios si (self.episodes) [self setEpisodes: nil];  // Inicializar Feed Parser self.feedParser = [[MWFeedParser alloc] initWithFeedURL: url]; // Configurar Feed Parser [self.feedParser setFeedParseType: ParseTypeFull]; [self.feedParser setDelegate: self]; // Mostrar progreso HUD [SVProgress HUD showWithMaskType: SVProgressHUDMaskTypeGradient]; // Iniciar el análisis [self.feedParser parse]; 

También necesitamos implementar dos métodos de MWFeedParserDelegate protocolo, feedParser: didParseFeedItem: y feedParserDidFinish:. En feedParser: didParseFeedItem:, inicializamos el episodios propiedad si es necesario y pásele el elemento de feed que el analizador de feed nos entrega.

 - (void) feedParser: (MWFeedParser *) parser didParseFeedItem: (MWFeedItem *) item if (! self.episodes) self.episodes = [array NSMutableArray];  [self.episodes addObject: item]; 

En feedParserDidFinish:, descartamos el progreso HUD y actualizamos la vista de tabla. ¿Dijiste la vista de tabla? Está bien. Necesitamos agregar una vista de tabla e implementar lo necesario. UITableViewDataSource métodos de protocolo.

 - (void) feedParserDidFinish: (MWFeedParser *) parser // Descartar progreso HUD [SVProgress HUD despedir]; // Vista de actualización [self.tableView reloadData]; 

Paso 3: Visualización de la alimentación

Antes de actualizar la interfaz de usuario, abra MTViewController.h, declarar una salida para la vista de tabla y decirle al compilador MTViewController clase se ajusta a la UITableViewDataSource y UITableViewDelegate protocolos.

 #importar  @interface MTViewController: UIViewController  @ propiedad (débil, no atómica) IBOutlet UITableView * tableView; @fin

Abra el guión gráfico una vez más y agregue una vista de tabla a la vista del controlador de vista. Conecte la vista de tabla fuente de datos y delegar salidas con el controlador de vista y conecte el controlador de vista tableView Salida con la vista de la mesa. Seleccione la vista de tabla, abra el Inspector de atributos, y establecer el número de células prototipo para 1. Seleccione la celda prototipo, establezca su estilo en Subtitular, y darle un identificador de EpisodioCell.


Antes de implementar el UITableViewDataSource protocolo, declarar una cadena estática llamada EpisodioCell en MTViewController.m. Esto se corresponde con el identificador que configuramos para la celda prototipo en el guión gráfico..

 static NSString * EpisodeCell = @ "EpisodeCell";

Implementando el UITableViewDataSource El protocolo es simple como circular y muy similar a cómo implementamos el protocolo en el controlador de vista de búsqueda. La única diferencia es que la episodios variable contiene instancias de la MWFeedItem clase en lugar de NSDiccionario instancias.

 - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return self.episodes? 1: 0; 
 - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section return self.episodes? self.episodes.count: 0; 
 - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: EpisodeCell forIndexPath: indexPath]; // Fetch Feed Item MWFeedItem * feedItem = [self.episodes objectAtIndex: indexPath.row]; // Configurar la celda de vista de tabla [cell.textLabel setText: feedItem.title]; [cell.detailTextLabel setText: [NSString stringWithFormat: @ "% @", feedItem.date]]; celda de retorno 
 - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath return NO; 
 - (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath return NO; 

Ejecute la aplicación en el simulador de iOS o en un dispositivo físico y ejecútelo a su ritmo. Ahora debería poder buscar podcasts, seleccionar un podcast de la lista y ver sus episodios.


Conclusión

Hemos hecho mucho en este tutorial, pero aún tenemos mucho trabajo por delante. En el siguiente tutorial, hacemos zoom en la descarga de episodios de la fuente y analizaremos las descargas en segundo plano o fuera de proceso. Manténganse al tanto.