SlideShare una empresa de Scribd logo
1 de 74
Descargar para leer sin conexión
Televisió de Catalunya
Formación en movilidad
Conceptos de desarrollo en iOS
4ª sesión mayo 2013
1
Qué veremos hoy
Alert
Search Bar
Action Sheet
Activity
Customizing
Testing
2
Alert
UIAlertView
“Use the UIAlertView class to display an alert
message to the user”
3
Alert
UIAlertView
// MasterViewController.m
- (void)insertNewObject:(NSDictionary *)values
{
// ...
if (![context save:&error])
{
// ...
}
else
{
UIAlertView *notice = [[UIAlertView alloc]
initWithTitle:@"Nuevo vídeo"
message:@"Se a creado un nuevo vídeo correctamente"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil];
[notice show];
}
4
Alert
UIAlertView
// MasterViewController.m
- (void)insertNewObject:(NSDictionary *)values
{
// ...
if (![context save:&error])
{
// ...
}
else
{
UIAlertView *notice = [[UIAlertView alloc]
initWithTitle:@"Nuevo vídeo"
message:@"Se a creado un nuevo vídeo correctamente"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil];
[notice show];
}
5
Alert
UIAlertView
// MasterViewController.m
- (void)insertNewObject:(NSDictionary *)values
{
// ...
if (![context save:&error])
{
// ...
}
else
{
UIAlertView *notice = [[UIAlertView alloc]
initWithTitle:@"Nuevo vídeo"
message:@"Se a creado un nuevo vídeo correctamente"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:@"Deshacer", nil];
[notice show];
}
6
Alert
UIAlertView
// MasterViewController.m
- (void)insertNewObject:(NSDictionary *)values
{
// ...
if (![context save:&error])
{
// ...
}
else
{
UIAlertView *notice = [[UIAlertView alloc]
initWithTitle:@"Nuevo vídeo"
message:@"Se a creado un nuevo vídeo correctamente"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:@"Deshacer", nil];
[notice show];
}
7
“The UISearchBar object does not actually
perform any searches.You use the
UISearchBarDelegate protocol to implement
the actions when text is entered and buttons
are clicked”
Search Bar
8
Search Bar
UISearchBar
9
Search Bar
UISearchBar
Placeholder ‘Buscar por título o autor’
Marcar ‘Shows Cancel Button’
Seleccionar ‘Correction: No’
Conectar ‘Search Bar’ delegate con ‘MasterView Controller’
10
Search Bar
UISearchBarDelegate
// MasterViewController.m
@interface MasterViewController ()
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
- (void)performSearch:(NSString *)searchText;
@end
11
Search Bar
UISearchBarDelegate
// MasterViewController.m
@interface MasterViewController ()
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
- (void)performSearch:(NSString *)searchText;
@end
Declarar método privado performSearch:
12
Search Bar
UISearchBarDelegate
// MasterViewController.m
@interface MasterViewController ()
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
- (void)performSearch:(NSString *)searchText;
@end
- (NSFetchedResultsController *)fetchedResultsController {
// ...
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
// ...
}
13
Search Bar
UISearchBarDelegate
// MasterViewController.m
@interface MasterViewController ()
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
- (void)performSearch:(NSString *)searchText;
@end
- (NSFetchedResultsController *)fetchedResultsController {
// ...
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
// ...
}
Anular uso de caché en initWithFetchRequest:
14
Search Bar
UISearchBarDelegate
// MasterViewController.m
#pragma mark - UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
}
Acciones para
botones ‘Search’ y ‘Cancel’ e introducción de texto
15
Search Bar
UISearchBarDelegate
// MasterViewController.m
#pragma mark - UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self performSearch:searchBar.text];
[searchBar resignFirstResponder];
[self.tableView reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
}
searchBarSearchButtonClicked:
16
Search Bar
UISearchBarDelegate
// MasterViewController.m
#pragma mark - UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self performSearch:searchBar.text];
[searchBar resignFirstResponder];
[self.tableView reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
}
searchBarCancelButtonClicked:
17
Search Bar
UISearchBarDelegate
// MasterViewController.m
#pragma mark - UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self performSearch:searchBar.text];
[searchBar resignFirstResponder];
[self.tableView reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[self performSearch:searchText];
}
searchBar:textDidChange:
18
Search Bar
UISearchBarDelegate + Core Data
// MasterViewController.m
#pragma mark - Private
- (void)performSearch:(NSString *)searchText {
NSPredicate *predicate;
NSError *error = nil;
if(searchText && searchText.length > 0) {
predicate = [NSPredicate predicateWithFormat:
@"title contains[cd] %@ or author contains[cd] %@", searchText, searchText];
[self.fetchedResultsController.fetchRequest setPredicate:predicate];
} else {
[self.fetchedResultsController.fetchRequest setPredicate:nil];
}
if(![self.fetchedResultsController performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
[self.tableView reloadData];
}
Implementar método privado performSearch:
19
Search Bar
UISearchBarDelegate + Core Data
// MasterViewController.m
#pragma mark - Private
- (void)performSearch:(NSString *)searchText {
NSPredicate *predicate;
NSError *error = nil;
if(searchText && searchText.length > 0) {
predicate = [NSPredicate predicateWithFormat:
@"title contains[cd] %@ or author contains[cd] %@", searchText, searchText];
[self.fetchedResultsController.fetchRequest setPredicate:predicate];
} else {
[self.fetchedResultsController.fetchRequest setPredicate:nil];
}
if(![self.fetchedResultsController performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
[self.tableView reloadData];
}
contains[cd] is case and diacritic insensitive
20
Search Bar
UISearchBarDelegate + Core Data
// MasterViewController.m
#pragma mark - Private
- (void)performSearch:(NSString *)searchText {
NSPredicate *predicate;
NSError *error = nil;
if(searchText && searchText.length > 0) {
predicate = [NSPredicate predicateWithFormat:
@"title contains[cd] %@ or author contains[cd] %@", searchText, searchText];
[self.fetchedResultsController.fetchRequest setPredicate:predicate];
} else {
[self.fetchedResultsController.fetchRequest setPredicate:nil];
}
if(![self.fetchedResultsController performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
[self.tableView reloadData];
}
Anular criterios = Buscar todos
21
Search Bar
UISearchBarDelegate
22
“Use the UIActionSheet class to present the
user with a set of alternatives for how to
proceed with a given task”
Action Sheet
23
Action Sheet
24
Action Sheet
Seleccionar ‘Identifier:Action’
25
Action Sheet
Seleccionar ‘Identifier:Action’
Conectar ‘Bar Button Item - Action’ con DetailView Controller
Connection:Action
Name: shareByEmail
Type: id
26
Action Sheet
TARGETS : MyVideos : Build Phases : Link With Binary Libraries
MessageUI.framework
27
Action Sheet
UIActionSheet
// DetailViewController.h
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>
@interface DetailViewController : UIViewController <
UISplitViewControllerDelegate, UIWebViewDelegate,
UIActionSheetDelegate, MFMailComposeViewControllerDelegate>
// ...
@end
Importar MessageUI.h y MFMailComposeViewController.h
28
Action Sheet
UIActionSheet
// DetailViewController.h
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>
@interface DetailViewController : UIViewController <
UISplitViewControllerDelegate, UIWebViewDelegate,
UIActionSheetDelegate, MFMailComposeViewControllerDelegate>
// ...
@end
UIActionSheetDelegate
29
// DetailViewController.h
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>
@interface DetailViewController : UIViewController <
UISplitViewControllerDelegate, UIWebViewDelegate,
UIActionSheetDelegate, MFMailComposeViewControllerDelegate>
// ...
@end
Action Sheet
UIActionSheet
MFMailComposeViewControllerDelegate
30
Action Sheet
UIActionSheet
// DetailViewController.m
- (IBAction)shareByEmail:(id)sender {
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:@"Compartir"
delegate:self
cancelButtonTitle:@"Cancelar"
destructiveButtonTitle:nil
otherButtonTitles:@"Email", nil];
[actionSheet showInView:self.view];
}
initWithTitle:
31
Action Sheet
UIActionSheet
showInView:
// DetailViewController.m
- (IBAction)shareByEmail:(id)sender {
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:@"Compartir"
delegate:self
cancelButtonTitle:@"Cancelar"
destructiveButtonTitle:nil
otherButtonTitles:@"Email", nil];
[actionSheet showInView:self.view];
}
32
Action Sheet
UIActionSheetDelegate
// DetailViewController.m
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
}
@end
Implementar actionSheet:clickedButtonAtIndex:
33
Action Sheet
UIActionSheetDelegate
// DetailViewController.m
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if(buttonIndex == 0 && [MFMailComposeViewController canSendMail]) {
NSString *subject = @"Mira este vídeo!";
NSArray *recipients = @[ @"sergi.hernando@mobivery.com" ];
NSString *url = self.webView.request.URL.absoluteString;
NSString *body = [NSString stringWithFormat:@"Échale un ojo: %@", url];
}
}
@end
Parámetros del email
34
Action Sheet
UIActionSheetDelegate
// DetailViewController.m
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if(buttonIndex == 0 && [MFMailComposeViewController canSendMail]) {
NSString *subject = @"Mira este vídeo!";
NSArray *recipients = @[ @"sergi.hernando@mobivery.com" ];
NSString *url = self.webView.request.URL.absoluteString;
NSString *body = [NSString stringWithFormat:@"Échale un ojo: %@", url];
MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
}
}
@end
Instanciar mail compose view controller
35
Action Sheet
UIActionSheetDelegate
// DetailViewController.m
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if(buttonIndex == 0 && [MFMailComposeViewController canSendMail]) {
NSString *subject = @"Mira este vídeo!";
NSArray *recipients = @[ @"sergi.hernando@mobivery.com" ];
NSString *url = self.webView.request.URL.absoluteString;
NSString *body = [NSString stringWithFormat:@"Échale un ojo: %@", url];
MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
[mailComposer setSubject:subject];
[mailComposer setToRecipients:recipients];
[mailComposer setMessageBody:body isHTML:YES];
[mailComposer setMailComposeDelegate:self];
}
}
@end
Asignar parámetros a mail compose view controller
36
Action Sheet
UIActionSheetDelegate
// DetailViewController.m
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if(buttonIndex == 0 && [MFMailComposeViewController canSendMail]) {
NSString *subject = @"Mira este vídeo!";
NSArray *recipients = @[ @"sergi.hernando@mobivery.com" ];
NSString *url = self.webView.request.URL.absoluteString;
NSString *body = [NSString stringWithFormat:@"Échale un ojo: %@", url];
MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
[mailComposer setSubject:subject];
[mailComposer setToRecipients:recipients];
[mailComposer setMessageBody:body isHTML:YES];
[mailComposer setMailComposeDelegate:self];
[self presentViewController:mailComposer animated:YES completion:nil];
}
}
@end
Mostrar mail compose view controller
37
Action Sheet
MFMailComposeViewControllerDelegate
Implementar mailComposeController:didFinishWithResult:error:
#pragma mark - MFMailComposeViewControllerDelegate
- (void)mailComposeController:(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
}
38
Action Sheet
MFMailComposeViewControllerDelegate
Cerrar mail compose view controller
* [mailComposer setMailComposeDelegate:self];
#pragma mark - MFMailComposeViewControllerDelegate
- (void)mailComposeController:(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
! [self dismissViewControllerAnimated:YES completion:nil];
}
39
Activity
UIActivityViewController
// DetailViewController.m
- (IBAction)shareByEmail:(id)sender {
}
40
Activity
UIActivityViewController
// DetailViewController.m
- (IBAction)shareByEmail:(id)sender {
NSString *url = self.webView.request.URL.absoluteString;
NSString *body = [NSString stringWithFormat:@"Échale un ojo a este vídeo: %@", url];
}
41
Activity
UIActivityViewController
// DetailViewController.m
- (IBAction)shareByEmail:(id)sender {
NSString *url = self.webView.request.URL.absoluteString;
NSString *body = [NSString stringWithFormat:@"Échale un ojo a este vídeo: %@", url];
UIActivityViewController *activity;
activity = [[UIActivityViewController alloc]
initWithActivityItems:@[body] applicationActivities:nil];
}
42
Activity
UIActivityViewController
// DetailViewController.m
- (IBAction)shareByEmail:(id)sender {
NSString *url = self.webView.request.URL.absoluteString;
NSString *body = [NSString stringWithFormat:@"Échale un ojo a este vídeo: %@", url];
UIActivityViewController *activity;
activity = [[UIActivityViewController alloc]
initWithActivityItems:@[body] applicationActivities:nil];
activity.excludedActivityTypes =
@[UIActivityTypeMessage, UIActivityTypeMail, UIActivityTypePostToWeibo];
}
43
Activity
UIActivityViewController
// DetailViewController.m
- (IBAction)shareByEmail:(id)sender {
NSString *url = self.webView.request.URL.absoluteString;
NSString *body = [NSString stringWithFormat:@"Échale un ojo a este vídeo: %@", url];
UIActivityViewController *activity;
activity = [[UIActivityViewController alloc]
initWithActivityItems:@[body] applicationActivities:nil];
activity.excludedActivityTypes =
@[UIActivityTypeMessage, UIActivityTypeMail, UIActivityTypePostToWeibo];
[self presentViewController:activity animated:YES completion:nil];
}
44
Coffee Break!
45
Customizing
UIAppearance
// AppDelegate.m
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ...
return YES;
}
application:didFinishLaunchingWithOptions:
46
Customizing
UIAppearance
// AppDelegate.m
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ...
[[UINavigationBar appearance] setTintColor:[UIColor blackColor]];
return YES;
}
UINavigationBar
47
Customizing
UIAppearance
// AppDelegate.m
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ...
[[UINavigationBar appearance] setTintColor:[UIColor blackColor]];
[[UIBarButtonItem appearance] setTintColor:[UIColor blackColor]];
return YES;
}
UIBarButtonItem
48
Customizing
UIAppearance
// AppDelegate.m
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ...
[[UINavigationBar appearance] setTintColor:[UIColor blackColor]];
[[UIBarButtonItem appearance] setTintColor:[UIColor blackColor]];
[[UISearchBar appearance] setTintColor:[UIColor blackColor]];
return YES;
}
UISearchBar
49
Customizing
→
+
Bar Button Item
+
Round Rect Button
50
Customizing
+
Type: Custom
Title: vacío
Image: comun-back-button.png
51
Customizing
→
52
Customizing
53
Customizing
54
Customizing
// VideoCell.h
#import <UIKit/UIKit.h>
@interface VideoCell : UITableViewCell
@property (nonatomic, strong) IBOutlet UILabel *titleLabel;
@property (nonatomic, strong) IBOutlet UILabel *authorLabel;
@end
55
Customizing
TableView Cell - Style: Custom
Custom Class - Class:VideoCell
56
Customizing
57
Customizing
Conectar labels con titleLabel y authorLabel
58
Customizing
// MasterViewController.m
#import "VideoCell.h"
// ...
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [object valueForKey:@"title"];
}
59
Customizing
// MasterViewController.m
#import "VideoCell.h"
// ...
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
if([cell isKindOfClass:[VideoCell class]]) {
VideoCell *videoCell = (VideoCell *)cell;
videoCell.titleLabel.text = [object valueForKey:@"title"];
videoCell.authorLabel.text = [object valueForKey:@"author"];
} else {
cell.textLabel.text = [object valueForKey:@"title"];
}
}
60
Testing
OCUnit
61
Testing
OCUnit
validate:
“Devuelve ‘cierto’ si título, autor y URL están
informados
y URL tiene el formato correcto.
Devuelve ‘falso’ en caso contrario.”
62
Testing
OCUnit
// MyVideosTests.m
- (void)testValidateMandatoryFields {
}
63
Testing
OCUnit
// MyVideosTests.m
- (void)testValidateMandatoryFields {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"http://vimeo.com/m/31158841"
};
}
64
Testing
OCUnit
// MyVideosTests.m
- (void)testValidateMandatoryFields {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"http://vimeo.com/m/31158841"
};
BOOL result = [viewController validate:values];
}
65
Testing
OCUnit
// MyVideosTests.m
- (void)testValidateMandatoryFields {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"http://vimeo.com/m/31158841"
};
BOOL result = [viewController validate:values];
!
STAssertTrue(result, @"validate: returned false");
}
66
Testing
OCUnit
// MyVideosTests.m
- (void)testValidateMandatoryFields {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"http://vimeo.com/m/31158841"
};
BOOL result = [viewController validate:values];
!
STAssertTrue(result, @"validate: returned false");
}
“result” should be true. validate: returned false
67
Testing
OCUnit
// MyVideosTests.m
- (void)testValidateMandatoryFields {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"http://vimeo.com/m/31158841"
};
BOOL result = [viewController validate:values];
!
STAssertTrue(result, @"validate: returned false");
}
// MasterViewController.m
- (BOOL)validate:(NSDictionary *)values {
! return NO;
}
“result” should be true. validate: returned false
68
Testing
OCUnit
// MyVideosTests.m
- (void)testValidateMandatoryFields {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"http://vimeo.com/m/31158841"
};
BOOL result = [viewController validate:values];
!
STAssertTrue(result, @"validate: returned false");
}
// MasterViewController.m
- (BOOL)validate:(NSDictionary *)values {
return([values objectForKey:@"title"]
&& [values objectForKey:@"author"]
&& [values objectForKey:@"url"]);
}
69
Testing
OCUnit
// MyVideosTests.m
- (void)testValidateMandatoryFields {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"http://vimeo.com/m/31158841"
};
BOOL result = [viewController validate:values];
!
STAssertTrue(result, @"validate: returned false");
}
// MasterViewController.m
- (BOOL)validate:(NSDictionary *)values {
return([values objectForKey:@"title"]
&& [values objectForKey:@"author"]
&& [values objectForKey:@"url"]);
}
Test Case ‘-[MyVideosTests testValidateMandatoryFields]’ passed
70
Testing
OCUnit
// MyVideosTests.m
- (void)testValidatetMalformedURL {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"not an url"
};
BOOL result = [viewController validate:values];
!
STAssertFalse(result, @"validate: returned true");
}
71
Testing
OCUnit
// MyVideosTests.m
- (void)testValidatetMalformedURL {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"not an url"
};
BOOL result = [viewController validate:values];
!
STAssertFalse(result, @"validate: returned true");
}
“result” should be false. validate: returned true
72
Testing
OCUnit
// MyVideosTests.m
- (void)testValidatetMalformedURL {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"not an url"
};
BOOL result = [viewController validate:values];
!
STAssertFalse(result, @"validate: returned true");
}
// MasterViewController.m
- (BOOL)validate:(NSDictionary *)values {
return([values objectForKey:@"title"]
&& [values objectForKey:@"author"]
&& [values objectForKey:@"url"]
&& [NSURL URLWithString:[values objectForKey:@"url"]]);
}
73
Testing
OCUnit
// MyVideosTests.m
- (void)testValidatetMalformedURL {
MasterViewController *viewController = [MasterViewController new];
NSDictionary *values = @{
@"title": @"Murmuration",
@"author": @"Islands & Rivers",
@"url": @"not an url"
};
BOOL result = [viewController validate:values];
!
STAssertFalse(result, @"validate: returned true");
}
// MasterViewController.m
- (BOOL)validate:(NSDictionary *)values {
return([values objectForKey:@"title"]
&& [values objectForKey:@"author"]
&& [values objectForKey:@"url"]
&& [NSURL URLWithString:[values objectForKey:@"url"]]);
}
Test Case ‘-[MyVideosTests testValidateMalformedURL]’ passed
74

Más contenido relacionado

La actualidad más candente

Node js mongodriver
Node js mongodriverNode js mongodriver
Node js mongodriverchristkv
 
Nodejs do teste de unidade ao de integração
Nodejs  do teste de unidade ao de integraçãoNodejs  do teste de unidade ao de integração
Nodejs do teste de unidade ao de integraçãoVinícius Pretto da Silva
 
Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Eyal Vardi
 
Angular 2.0 Views
Angular 2.0 ViewsAngular 2.0 Views
Angular 2.0 ViewsEyal Vardi
 
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the AirAvitoTech
 
Zabbix LLD from a C Module by Jan-Piet Mens
Zabbix LLD from a C Module by Jan-Piet MensZabbix LLD from a C Module by Jan-Piet Mens
Zabbix LLD from a C Module by Jan-Piet MensNETWAYS
 
AngularJS Services
AngularJS ServicesAngularJS Services
AngularJS ServicesEyal Vardi
 
Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8Wilson Su
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
 
Обзор фреймворка Twisted
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка TwistedMaxim Kulsha
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingSamuel ROZE
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
CQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationCQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationSamuel ROZE
 
iOS. EventKit Framework. Work with calendars and reminders
iOS. EventKit Framework. Work with calendars and remindersiOS. EventKit Framework. Work with calendars and reminders
iOS. EventKit Framework. Work with calendars and remindersVoityuk Alexander
 

La actualidad más candente (20)

Node js mongodriver
Node js mongodriverNode js mongodriver
Node js mongodriver
 
Nodejs do teste de unidade ao de integração
Nodejs  do teste de unidade ao de integraçãoNodejs  do teste de unidade ao de integração
Nodejs do teste de unidade ao de integração
 
Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0
 
The zen of async: Best practices for best performance
The zen of async: Best practices for best performanceThe zen of async: Best practices for best performance
The zen of async: Best practices for best performance
 
Angular 2.0 Views
Angular 2.0 ViewsAngular 2.0 Views
Angular 2.0 Views
 
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
 
Zabbix LLD from a C Module by Jan-Piet Mens
Zabbix LLD from a C Module by Jan-Piet MensZabbix LLD from a C Module by Jan-Piet Mens
Zabbix LLD from a C Module by Jan-Piet Mens
 
AngularJS Services
AngularJS ServicesAngularJS Services
AngularJS Services
 
Django quickstart
Django quickstartDjango quickstart
Django quickstart
 
Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8
 
Jest
JestJest
Jest
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Обзор фреймворка Twisted
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка Twisted
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event Sourcing
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
CQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationCQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony application
 
Why Sifu
Why SifuWhy Sifu
Why Sifu
 
iOS. EventKit Framework. Work with calendars and reminders
iOS. EventKit Framework. Work with calendars and remindersiOS. EventKit Framework. Work with calendars and reminders
iOS. EventKit Framework. Work with calendars and reminders
 

Similar a Formacion en movilidad: Conceptos de desarrollo en iOS (IV)

Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCAWhymca
 
Formacion en movilidad: Conceptos de desarrollo en iOS (III)
Formacion en movilidad: Conceptos de desarrollo en iOS (III) Formacion en movilidad: Conceptos de desarrollo en iOS (III)
Formacion en movilidad: Conceptos de desarrollo en iOS (III) Mobivery
 
Core Data with multiple managed object contexts
Core Data with multiple managed object contextsCore Data with multiple managed object contexts
Core Data with multiple managed object contextsMatthew Morey
 
MobileCity:Core Data
MobileCity:Core DataMobileCity:Core Data
MobileCity:Core DataAllan Davis
 
Core Data with Swift 3.0
Core Data with Swift 3.0Core Data with Swift 3.0
Core Data with Swift 3.0Korhan Bircan
 
Google App Engine Developer - Day3
Google App Engine Developer - Day3Google App Engine Developer - Day3
Google App Engine Developer - Day3Simon Su
 
Codeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept ImplementationCodeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept ImplementationAbdul Malik Ikhsan
 
Taking a Test Drive
Taking a Test DriveTaking a Test Drive
Taking a Test DriveGraham Lee
 
Get the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Get the Most Out of iOS 11 with Visual Studio Tools for XamarinGet the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Get the Most Out of iOS 11 with Visual Studio Tools for XamarinXamarin
 
Apple Templates Considered Harmful
Apple Templates Considered HarmfulApple Templates Considered Harmful
Apple Templates Considered HarmfulBrian Gesiak
 
Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScriptAndrew Dupont
 
iOS for ERREST - alternative version
iOS for ERREST - alternative versioniOS for ERREST - alternative version
iOS for ERREST - alternative versionWO Community
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...DroidConTLV
 
Protractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applicationsProtractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applicationsLudmila Nesvitiy
 
10 tips for a reusable architecture
10 tips for a reusable architecture10 tips for a reusable architecture
10 tips for a reusable architectureJorge Ortiz
 
Models, controllers and views
Models, controllers and viewsModels, controllers and views
Models, controllers and viewspriestc
 
Optimize CollectionView Scrolling
Optimize CollectionView ScrollingOptimize CollectionView Scrolling
Optimize CollectionView ScrollingAndrea Prearo
 

Similar a Formacion en movilidad: Conceptos de desarrollo en iOS (IV) (20)

Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCA
 
Formacion en movilidad: Conceptos de desarrollo en iOS (III)
Formacion en movilidad: Conceptos de desarrollo en iOS (III) Formacion en movilidad: Conceptos de desarrollo en iOS (III)
Formacion en movilidad: Conceptos de desarrollo en iOS (III)
 
Core Data with multiple managed object contexts
Core Data with multiple managed object contextsCore Data with multiple managed object contexts
Core Data with multiple managed object contexts
 
MobileCity:Core Data
MobileCity:Core DataMobileCity:Core Data
MobileCity:Core Data
 
I os 11
I os 11I os 11
I os 11
 
iOS
iOSiOS
iOS
 
Core Data with Swift 3.0
Core Data with Swift 3.0Core Data with Swift 3.0
Core Data with Swift 3.0
 
I os 04
I os 04I os 04
I os 04
 
Google App Engine Developer - Day3
Google App Engine Developer - Day3Google App Engine Developer - Day3
Google App Engine Developer - Day3
 
Codeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept ImplementationCodeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept Implementation
 
Taking a Test Drive
Taking a Test DriveTaking a Test Drive
Taking a Test Drive
 
Get the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Get the Most Out of iOS 11 with Visual Studio Tools for XamarinGet the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Get the Most Out of iOS 11 with Visual Studio Tools for Xamarin
 
Apple Templates Considered Harmful
Apple Templates Considered HarmfulApple Templates Considered Harmful
Apple Templates Considered Harmful
 
Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScript
 
iOS for ERREST - alternative version
iOS for ERREST - alternative versioniOS for ERREST - alternative version
iOS for ERREST - alternative version
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
 
Protractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applicationsProtractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applications
 
10 tips for a reusable architecture
10 tips for a reusable architecture10 tips for a reusable architecture
10 tips for a reusable architecture
 
Models, controllers and views
Models, controllers and viewsModels, controllers and views
Models, controllers and views
 
Optimize CollectionView Scrolling
Optimize CollectionView ScrollingOptimize CollectionView Scrolling
Optimize CollectionView Scrolling
 

Más de Mobivery

Jornada Empresa UOC - Desarrollo de Aplicaciones para Formación en RRHH
Jornada Empresa UOC - Desarrollo de Aplicaciones para Formación en RRHHJornada Empresa UOC - Desarrollo de Aplicaciones para Formación en RRHH
Jornada Empresa UOC - Desarrollo de Aplicaciones para Formación en RRHHMobivery
 
Modelo start up: Una forma de encontrar trabajo
Modelo start up: Una forma de encontrar trabajo Modelo start up: Una forma de encontrar trabajo
Modelo start up: Una forma de encontrar trabajo Mobivery
 
¿Persona o empleado? Algo está cambiando en nuestras empresas
¿Persona o empleado? Algo está cambiando en nuestras empresas¿Persona o empleado? Algo está cambiando en nuestras empresas
¿Persona o empleado? Algo está cambiando en nuestras empresasMobivery
 
Móvil y Retail: Cambiando las reglas del juego
Móvil y Retail: Cambiando las reglas del juegoMóvil y Retail: Cambiando las reglas del juego
Móvil y Retail: Cambiando las reglas del juegoMobivery
 
Presentación de Mobivery en el FET2013
Presentación de Mobivery en el FET2013Presentación de Mobivery en el FET2013
Presentación de Mobivery en el FET2013Mobivery
 
Curso de formación en Movilidad (Parte III) - Tecnología de Servidor
Curso de formación en Movilidad (Parte III) - Tecnología de ServidorCurso de formación en Movilidad (Parte III) - Tecnología de Servidor
Curso de formación en Movilidad (Parte III) - Tecnología de ServidorMobivery
 
Curso de formación en Movilidad (Parte II) - Personalización
Curso de formación en Movilidad (Parte II) - Personalización Curso de formación en Movilidad (Parte II) - Personalización
Curso de formación en Movilidad (Parte II) - Personalización Mobivery
 
Curso de formación en Movilidad (Parte I) - Mobile Device Management
Curso de formación en Movilidad (Parte I) - Mobile Device ManagementCurso de formación en Movilidad (Parte I) - Mobile Device Management
Curso de formación en Movilidad (Parte I) - Mobile Device ManagementMobivery
 
Formacion en movilidad: Conceptos de desarrollo en iOS (II)
Formacion en movilidad: Conceptos de desarrollo en iOS (II) Formacion en movilidad: Conceptos de desarrollo en iOS (II)
Formacion en movilidad: Conceptos de desarrollo en iOS (II) Mobivery
 
Formacion en movilidad: Conceptos de desarrollo en iOS (I)
Formacion en movilidad: Conceptos de desarrollo en iOS (I) Formacion en movilidad: Conceptos de desarrollo en iOS (I)
Formacion en movilidad: Conceptos de desarrollo en iOS (I) Mobivery
 
Formación en movilidad: Conceptos de desarrollo en iOS (V)
Formación en movilidad: Conceptos de desarrollo en iOS (V) Formación en movilidad: Conceptos de desarrollo en iOS (V)
Formación en movilidad: Conceptos de desarrollo en iOS (V) Mobivery
 
Hoy es Marketing 2013: El móvil en la cadena de distribución
Hoy es Marketing 2013: El móvil en la cadena de distribuciónHoy es Marketing 2013: El móvil en la cadena de distribución
Hoy es Marketing 2013: El móvil en la cadena de distribuciónMobivery
 
Introducción Mobile Apps
Introducción Mobile AppsIntroducción Mobile Apps
Introducción Mobile AppsMobivery
 
UrbanSensing - Escuchando la ciudad digital
UrbanSensing  - Escuchando la ciudad digitalUrbanSensing  - Escuchando la ciudad digital
UrbanSensing - Escuchando la ciudad digitalMobivery
 
Mobile Health - Nuevos retos y oportunidades. El caso de éxito de iPediatric
Mobile Health - Nuevos retos y oportunidades. El caso de éxito de iPediatricMobile Health - Nuevos retos y oportunidades. El caso de éxito de iPediatric
Mobile Health - Nuevos retos y oportunidades. El caso de éxito de iPediatricMobivery
 
Marketing de Apps
Marketing de Apps Marketing de Apps
Marketing de Apps Mobivery
 
Aplicaciones móviles: Usabilidad y Experiencia de Usuario
Aplicaciones móviles: Usabilidad y Experiencia de UsuarioAplicaciones móviles: Usabilidad y Experiencia de Usuario
Aplicaciones móviles: Usabilidad y Experiencia de UsuarioMobivery
 
Workshop I: Diseño de aplicaciones para iPhone
Workshop I: Diseño de aplicaciones para iPhoneWorkshop I: Diseño de aplicaciones para iPhone
Workshop I: Diseño de aplicaciones para iPhoneMobivery
 
Cómo monetizar tus apps: Cantidad y Calidad
Cómo monetizar tus apps: Cantidad y CalidadCómo monetizar tus apps: Cantidad y Calidad
Cómo monetizar tus apps: Cantidad y CalidadMobivery
 
Formación Aecomo Academy - Monetización de aplicaciones
Formación Aecomo Academy - Monetización de aplicacionesFormación Aecomo Academy - Monetización de aplicaciones
Formación Aecomo Academy - Monetización de aplicacionesMobivery
 

Más de Mobivery (20)

Jornada Empresa UOC - Desarrollo de Aplicaciones para Formación en RRHH
Jornada Empresa UOC - Desarrollo de Aplicaciones para Formación en RRHHJornada Empresa UOC - Desarrollo de Aplicaciones para Formación en RRHH
Jornada Empresa UOC - Desarrollo de Aplicaciones para Formación en RRHH
 
Modelo start up: Una forma de encontrar trabajo
Modelo start up: Una forma de encontrar trabajo Modelo start up: Una forma de encontrar trabajo
Modelo start up: Una forma de encontrar trabajo
 
¿Persona o empleado? Algo está cambiando en nuestras empresas
¿Persona o empleado? Algo está cambiando en nuestras empresas¿Persona o empleado? Algo está cambiando en nuestras empresas
¿Persona o empleado? Algo está cambiando en nuestras empresas
 
Móvil y Retail: Cambiando las reglas del juego
Móvil y Retail: Cambiando las reglas del juegoMóvil y Retail: Cambiando las reglas del juego
Móvil y Retail: Cambiando las reglas del juego
 
Presentación de Mobivery en el FET2013
Presentación de Mobivery en el FET2013Presentación de Mobivery en el FET2013
Presentación de Mobivery en el FET2013
 
Curso de formación en Movilidad (Parte III) - Tecnología de Servidor
Curso de formación en Movilidad (Parte III) - Tecnología de ServidorCurso de formación en Movilidad (Parte III) - Tecnología de Servidor
Curso de formación en Movilidad (Parte III) - Tecnología de Servidor
 
Curso de formación en Movilidad (Parte II) - Personalización
Curso de formación en Movilidad (Parte II) - Personalización Curso de formación en Movilidad (Parte II) - Personalización
Curso de formación en Movilidad (Parte II) - Personalización
 
Curso de formación en Movilidad (Parte I) - Mobile Device Management
Curso de formación en Movilidad (Parte I) - Mobile Device ManagementCurso de formación en Movilidad (Parte I) - Mobile Device Management
Curso de formación en Movilidad (Parte I) - Mobile Device Management
 
Formacion en movilidad: Conceptos de desarrollo en iOS (II)
Formacion en movilidad: Conceptos de desarrollo en iOS (II) Formacion en movilidad: Conceptos de desarrollo en iOS (II)
Formacion en movilidad: Conceptos de desarrollo en iOS (II)
 
Formacion en movilidad: Conceptos de desarrollo en iOS (I)
Formacion en movilidad: Conceptos de desarrollo en iOS (I) Formacion en movilidad: Conceptos de desarrollo en iOS (I)
Formacion en movilidad: Conceptos de desarrollo en iOS (I)
 
Formación en movilidad: Conceptos de desarrollo en iOS (V)
Formación en movilidad: Conceptos de desarrollo en iOS (V) Formación en movilidad: Conceptos de desarrollo en iOS (V)
Formación en movilidad: Conceptos de desarrollo en iOS (V)
 
Hoy es Marketing 2013: El móvil en la cadena de distribución
Hoy es Marketing 2013: El móvil en la cadena de distribuciónHoy es Marketing 2013: El móvil en la cadena de distribución
Hoy es Marketing 2013: El móvil en la cadena de distribución
 
Introducción Mobile Apps
Introducción Mobile AppsIntroducción Mobile Apps
Introducción Mobile Apps
 
UrbanSensing - Escuchando la ciudad digital
UrbanSensing  - Escuchando la ciudad digitalUrbanSensing  - Escuchando la ciudad digital
UrbanSensing - Escuchando la ciudad digital
 
Mobile Health - Nuevos retos y oportunidades. El caso de éxito de iPediatric
Mobile Health - Nuevos retos y oportunidades. El caso de éxito de iPediatricMobile Health - Nuevos retos y oportunidades. El caso de éxito de iPediatric
Mobile Health - Nuevos retos y oportunidades. El caso de éxito de iPediatric
 
Marketing de Apps
Marketing de Apps Marketing de Apps
Marketing de Apps
 
Aplicaciones móviles: Usabilidad y Experiencia de Usuario
Aplicaciones móviles: Usabilidad y Experiencia de UsuarioAplicaciones móviles: Usabilidad y Experiencia de Usuario
Aplicaciones móviles: Usabilidad y Experiencia de Usuario
 
Workshop I: Diseño de aplicaciones para iPhone
Workshop I: Diseño de aplicaciones para iPhoneWorkshop I: Diseño de aplicaciones para iPhone
Workshop I: Diseño de aplicaciones para iPhone
 
Cómo monetizar tus apps: Cantidad y Calidad
Cómo monetizar tus apps: Cantidad y CalidadCómo monetizar tus apps: Cantidad y Calidad
Cómo monetizar tus apps: Cantidad y Calidad
 
Formación Aecomo Academy - Monetización de aplicaciones
Formación Aecomo Academy - Monetización de aplicacionesFormación Aecomo Academy - Monetización de aplicaciones
Formación Aecomo Academy - Monetización de aplicaciones
 

Último

Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 

Último (20)

Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 

Formacion en movilidad: Conceptos de desarrollo en iOS (IV)

  • 1. Televisió de Catalunya Formación en movilidad Conceptos de desarrollo en iOS 4ª sesión mayo 2013 1
  • 2. Qué veremos hoy Alert Search Bar Action Sheet Activity Customizing Testing 2
  • 3. Alert UIAlertView “Use the UIAlertView class to display an alert message to the user” 3
  • 4. Alert UIAlertView // MasterViewController.m - (void)insertNewObject:(NSDictionary *)values { // ... if (![context save:&error]) { // ... } else { UIAlertView *notice = [[UIAlertView alloc] initWithTitle:@"Nuevo vídeo" message:@"Se a creado un nuevo vídeo correctamente" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [notice show]; } 4
  • 5. Alert UIAlertView // MasterViewController.m - (void)insertNewObject:(NSDictionary *)values { // ... if (![context save:&error]) { // ... } else { UIAlertView *notice = [[UIAlertView alloc] initWithTitle:@"Nuevo vídeo" message:@"Se a creado un nuevo vídeo correctamente" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [notice show]; } 5
  • 6. Alert UIAlertView // MasterViewController.m - (void)insertNewObject:(NSDictionary *)values { // ... if (![context save:&error]) { // ... } else { UIAlertView *notice = [[UIAlertView alloc] initWithTitle:@"Nuevo vídeo" message:@"Se a creado un nuevo vídeo correctamente" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:@"Deshacer", nil]; [notice show]; } 6
  • 7. Alert UIAlertView // MasterViewController.m - (void)insertNewObject:(NSDictionary *)values { // ... if (![context save:&error]) { // ... } else { UIAlertView *notice = [[UIAlertView alloc] initWithTitle:@"Nuevo vídeo" message:@"Se a creado un nuevo vídeo correctamente" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:@"Deshacer", nil]; [notice show]; } 7
  • 8. “The UISearchBar object does not actually perform any searches.You use the UISearchBarDelegate protocol to implement the actions when text is entered and buttons are clicked” Search Bar 8
  • 10. Search Bar UISearchBar Placeholder ‘Buscar por título o autor’ Marcar ‘Shows Cancel Button’ Seleccionar ‘Correction: No’ Conectar ‘Search Bar’ delegate con ‘MasterView Controller’ 10
  • 11. Search Bar UISearchBarDelegate // MasterViewController.m @interface MasterViewController () - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath; - (void)performSearch:(NSString *)searchText; @end 11
  • 12. Search Bar UISearchBarDelegate // MasterViewController.m @interface MasterViewController () - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath; - (void)performSearch:(NSString *)searchText; @end Declarar método privado performSearch: 12
  • 13. Search Bar UISearchBarDelegate // MasterViewController.m @interface MasterViewController () - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath; - (void)performSearch:(NSString *)searchText; @end - (NSFetchedResultsController *)fetchedResultsController { // ... NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; // ... } 13
  • 14. Search Bar UISearchBarDelegate // MasterViewController.m @interface MasterViewController () - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath; - (void)performSearch:(NSString *)searchText; @end - (NSFetchedResultsController *)fetchedResultsController { // ... NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; // ... } Anular uso de caché en initWithFetchRequest: 14
  • 15. Search Bar UISearchBarDelegate // MasterViewController.m #pragma mark - UISearchBarDelegate - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { } - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { } - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { } Acciones para botones ‘Search’ y ‘Cancel’ e introducción de texto 15
  • 16. Search Bar UISearchBarDelegate // MasterViewController.m #pragma mark - UISearchBarDelegate - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { [self performSearch:searchBar.text]; [searchBar resignFirstResponder]; [self.tableView reloadData]; } - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { } - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { } searchBarSearchButtonClicked: 16
  • 17. Search Bar UISearchBarDelegate // MasterViewController.m #pragma mark - UISearchBarDelegate - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { [self performSearch:searchBar.text]; [searchBar resignFirstResponder]; [self.tableView reloadData]; } - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { [searchBar resignFirstResponder]; } - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { } searchBarCancelButtonClicked: 17
  • 18. Search Bar UISearchBarDelegate // MasterViewController.m #pragma mark - UISearchBarDelegate - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { [self performSearch:searchBar.text]; [searchBar resignFirstResponder]; [self.tableView reloadData]; } - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { [searchBar resignFirstResponder]; } - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { [self performSearch:searchText]; } searchBar:textDidChange: 18
  • 19. Search Bar UISearchBarDelegate + Core Data // MasterViewController.m #pragma mark - Private - (void)performSearch:(NSString *)searchText { NSPredicate *predicate; NSError *error = nil; if(searchText && searchText.length > 0) { predicate = [NSPredicate predicateWithFormat: @"title contains[cd] %@ or author contains[cd] %@", searchText, searchText]; [self.fetchedResultsController.fetchRequest setPredicate:predicate]; } else { [self.fetchedResultsController.fetchRequest setPredicate:nil]; } if(![self.fetchedResultsController performFetch:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } [self.tableView reloadData]; } Implementar método privado performSearch: 19
  • 20. Search Bar UISearchBarDelegate + Core Data // MasterViewController.m #pragma mark - Private - (void)performSearch:(NSString *)searchText { NSPredicate *predicate; NSError *error = nil; if(searchText && searchText.length > 0) { predicate = [NSPredicate predicateWithFormat: @"title contains[cd] %@ or author contains[cd] %@", searchText, searchText]; [self.fetchedResultsController.fetchRequest setPredicate:predicate]; } else { [self.fetchedResultsController.fetchRequest setPredicate:nil]; } if(![self.fetchedResultsController performFetch:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } [self.tableView reloadData]; } contains[cd] is case and diacritic insensitive 20
  • 21. Search Bar UISearchBarDelegate + Core Data // MasterViewController.m #pragma mark - Private - (void)performSearch:(NSString *)searchText { NSPredicate *predicate; NSError *error = nil; if(searchText && searchText.length > 0) { predicate = [NSPredicate predicateWithFormat: @"title contains[cd] %@ or author contains[cd] %@", searchText, searchText]; [self.fetchedResultsController.fetchRequest setPredicate:predicate]; } else { [self.fetchedResultsController.fetchRequest setPredicate:nil]; } if(![self.fetchedResultsController performFetch:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } [self.tableView reloadData]; } Anular criterios = Buscar todos 21
  • 23. “Use the UIActionSheet class to present the user with a set of alternatives for how to proceed with a given task” Action Sheet 23
  • 26. Action Sheet Seleccionar ‘Identifier:Action’ Conectar ‘Bar Button Item - Action’ con DetailView Controller Connection:Action Name: shareByEmail Type: id 26
  • 27. Action Sheet TARGETS : MyVideos : Build Phases : Link With Binary Libraries MessageUI.framework 27
  • 28. Action Sheet UIActionSheet // DetailViewController.h #import <UIKit/UIKit.h> #import <MessageUI/MessageUI.h> #import <MessageUI/MFMailComposeViewController.h> @interface DetailViewController : UIViewController < UISplitViewControllerDelegate, UIWebViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate> // ... @end Importar MessageUI.h y MFMailComposeViewController.h 28
  • 29. Action Sheet UIActionSheet // DetailViewController.h #import <UIKit/UIKit.h> #import <MessageUI/MessageUI.h> #import <MessageUI/MFMailComposeViewController.h> @interface DetailViewController : UIViewController < UISplitViewControllerDelegate, UIWebViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate> // ... @end UIActionSheetDelegate 29
  • 30. // DetailViewController.h #import <UIKit/UIKit.h> #import <MessageUI/MessageUI.h> #import <MessageUI/MFMailComposeViewController.h> @interface DetailViewController : UIViewController < UISplitViewControllerDelegate, UIWebViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate> // ... @end Action Sheet UIActionSheet MFMailComposeViewControllerDelegate 30
  • 31. Action Sheet UIActionSheet // DetailViewController.m - (IBAction)shareByEmail:(id)sender { UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Compartir" delegate:self cancelButtonTitle:@"Cancelar" destructiveButtonTitle:nil otherButtonTitles:@"Email", nil]; [actionSheet showInView:self.view]; } initWithTitle: 31
  • 32. Action Sheet UIActionSheet showInView: // DetailViewController.m - (IBAction)shareByEmail:(id)sender { UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Compartir" delegate:self cancelButtonTitle:@"Cancelar" destructiveButtonTitle:nil otherButtonTitles:@"Email", nil]; [actionSheet showInView:self.view]; } 32
  • 33. Action Sheet UIActionSheetDelegate // DetailViewController.m #pragma mark - UIActionSheetDelegate - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { } @end Implementar actionSheet:clickedButtonAtIndex: 33
  • 34. Action Sheet UIActionSheetDelegate // DetailViewController.m #pragma mark - UIActionSheetDelegate - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { if(buttonIndex == 0 && [MFMailComposeViewController canSendMail]) { NSString *subject = @"Mira este vídeo!"; NSArray *recipients = @[ @"sergi.hernando@mobivery.com" ]; NSString *url = self.webView.request.URL.absoluteString; NSString *body = [NSString stringWithFormat:@"Échale un ojo: %@", url]; } } @end Parámetros del email 34
  • 35. Action Sheet UIActionSheetDelegate // DetailViewController.m #pragma mark - UIActionSheetDelegate - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { if(buttonIndex == 0 && [MFMailComposeViewController canSendMail]) { NSString *subject = @"Mira este vídeo!"; NSArray *recipients = @[ @"sergi.hernando@mobivery.com" ]; NSString *url = self.webView.request.URL.absoluteString; NSString *body = [NSString stringWithFormat:@"Échale un ojo: %@", url]; MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init]; } } @end Instanciar mail compose view controller 35
  • 36. Action Sheet UIActionSheetDelegate // DetailViewController.m #pragma mark - UIActionSheetDelegate - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { if(buttonIndex == 0 && [MFMailComposeViewController canSendMail]) { NSString *subject = @"Mira este vídeo!"; NSArray *recipients = @[ @"sergi.hernando@mobivery.com" ]; NSString *url = self.webView.request.URL.absoluteString; NSString *body = [NSString stringWithFormat:@"Échale un ojo: %@", url]; MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init]; [mailComposer setSubject:subject]; [mailComposer setToRecipients:recipients]; [mailComposer setMessageBody:body isHTML:YES]; [mailComposer setMailComposeDelegate:self]; } } @end Asignar parámetros a mail compose view controller 36
  • 37. Action Sheet UIActionSheetDelegate // DetailViewController.m #pragma mark - UIActionSheetDelegate - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { if(buttonIndex == 0 && [MFMailComposeViewController canSendMail]) { NSString *subject = @"Mira este vídeo!"; NSArray *recipients = @[ @"sergi.hernando@mobivery.com" ]; NSString *url = self.webView.request.URL.absoluteString; NSString *body = [NSString stringWithFormat:@"Échale un ojo: %@", url]; MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init]; [mailComposer setSubject:subject]; [mailComposer setToRecipients:recipients]; [mailComposer setMessageBody:body isHTML:YES]; [mailComposer setMailComposeDelegate:self]; [self presentViewController:mailComposer animated:YES completion:nil]; } } @end Mostrar mail compose view controller 37
  • 38. Action Sheet MFMailComposeViewControllerDelegate Implementar mailComposeController:didFinishWithResult:error: #pragma mark - MFMailComposeViewControllerDelegate - (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error { } 38
  • 39. Action Sheet MFMailComposeViewControllerDelegate Cerrar mail compose view controller * [mailComposer setMailComposeDelegate:self]; #pragma mark - MFMailComposeViewControllerDelegate - (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error { ! [self dismissViewControllerAnimated:YES completion:nil]; } 39
  • 41. Activity UIActivityViewController // DetailViewController.m - (IBAction)shareByEmail:(id)sender { NSString *url = self.webView.request.URL.absoluteString; NSString *body = [NSString stringWithFormat:@"Échale un ojo a este vídeo: %@", url]; } 41
  • 42. Activity UIActivityViewController // DetailViewController.m - (IBAction)shareByEmail:(id)sender { NSString *url = self.webView.request.URL.absoluteString; NSString *body = [NSString stringWithFormat:@"Échale un ojo a este vídeo: %@", url]; UIActivityViewController *activity; activity = [[UIActivityViewController alloc] initWithActivityItems:@[body] applicationActivities:nil]; } 42
  • 43. Activity UIActivityViewController // DetailViewController.m - (IBAction)shareByEmail:(id)sender { NSString *url = self.webView.request.URL.absoluteString; NSString *body = [NSString stringWithFormat:@"Échale un ojo a este vídeo: %@", url]; UIActivityViewController *activity; activity = [[UIActivityViewController alloc] initWithActivityItems:@[body] applicationActivities:nil]; activity.excludedActivityTypes = @[UIActivityTypeMessage, UIActivityTypeMail, UIActivityTypePostToWeibo]; } 43
  • 44. Activity UIActivityViewController // DetailViewController.m - (IBAction)shareByEmail:(id)sender { NSString *url = self.webView.request.URL.absoluteString; NSString *body = [NSString stringWithFormat:@"Échale un ojo a este vídeo: %@", url]; UIActivityViewController *activity; activity = [[UIActivityViewController alloc] initWithActivityItems:@[body] applicationActivities:nil]; activity.excludedActivityTypes = @[UIActivityTypeMessage, UIActivityTypeMail, UIActivityTypePostToWeibo]; [self presentViewController:activity animated:YES completion:nil]; } 44
  • 46. Customizing UIAppearance // AppDelegate.m - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // ... return YES; } application:didFinishLaunchingWithOptions: 46
  • 47. Customizing UIAppearance // AppDelegate.m - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // ... [[UINavigationBar appearance] setTintColor:[UIColor blackColor]]; return YES; } UINavigationBar 47
  • 48. Customizing UIAppearance // AppDelegate.m - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // ... [[UINavigationBar appearance] setTintColor:[UIColor blackColor]]; [[UIBarButtonItem appearance] setTintColor:[UIColor blackColor]]; return YES; } UIBarButtonItem 48
  • 49. Customizing UIAppearance // AppDelegate.m - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // ... [[UINavigationBar appearance] setTintColor:[UIColor blackColor]]; [[UIBarButtonItem appearance] setTintColor:[UIColor blackColor]]; [[UISearchBar appearance] setTintColor:[UIColor blackColor]]; return YES; } UISearchBar 49
  • 55. Customizing // VideoCell.h #import <UIKit/UIKit.h> @interface VideoCell : UITableViewCell @property (nonatomic, strong) IBOutlet UILabel *titleLabel; @property (nonatomic, strong) IBOutlet UILabel *authorLabel; @end 55
  • 56. Customizing TableView Cell - Style: Custom Custom Class - Class:VideoCell 56
  • 58. Customizing Conectar labels con titleLabel y authorLabel 58
  • 59. Customizing // MasterViewController.m #import "VideoCell.h" // ... - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath]; cell.textLabel.text = [object valueForKey:@"title"]; } 59
  • 60. Customizing // MasterViewController.m #import "VideoCell.h" // ... - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath]; if([cell isKindOfClass:[VideoCell class]]) { VideoCell *videoCell = (VideoCell *)cell; videoCell.titleLabel.text = [object valueForKey:@"title"]; videoCell.authorLabel.text = [object valueForKey:@"author"]; } else { cell.textLabel.text = [object valueForKey:@"title"]; } } 60
  • 62. Testing OCUnit validate: “Devuelve ‘cierto’ si título, autor y URL están informados y URL tiene el formato correcto. Devuelve ‘falso’ en caso contrario.” 62
  • 64. Testing OCUnit // MyVideosTests.m - (void)testValidateMandatoryFields { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"http://vimeo.com/m/31158841" }; } 64
  • 65. Testing OCUnit // MyVideosTests.m - (void)testValidateMandatoryFields { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"http://vimeo.com/m/31158841" }; BOOL result = [viewController validate:values]; } 65
  • 66. Testing OCUnit // MyVideosTests.m - (void)testValidateMandatoryFields { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"http://vimeo.com/m/31158841" }; BOOL result = [viewController validate:values]; ! STAssertTrue(result, @"validate: returned false"); } 66
  • 67. Testing OCUnit // MyVideosTests.m - (void)testValidateMandatoryFields { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"http://vimeo.com/m/31158841" }; BOOL result = [viewController validate:values]; ! STAssertTrue(result, @"validate: returned false"); } “result” should be true. validate: returned false 67
  • 68. Testing OCUnit // MyVideosTests.m - (void)testValidateMandatoryFields { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"http://vimeo.com/m/31158841" }; BOOL result = [viewController validate:values]; ! STAssertTrue(result, @"validate: returned false"); } // MasterViewController.m - (BOOL)validate:(NSDictionary *)values { ! return NO; } “result” should be true. validate: returned false 68
  • 69. Testing OCUnit // MyVideosTests.m - (void)testValidateMandatoryFields { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"http://vimeo.com/m/31158841" }; BOOL result = [viewController validate:values]; ! STAssertTrue(result, @"validate: returned false"); } // MasterViewController.m - (BOOL)validate:(NSDictionary *)values { return([values objectForKey:@"title"] && [values objectForKey:@"author"] && [values objectForKey:@"url"]); } 69
  • 70. Testing OCUnit // MyVideosTests.m - (void)testValidateMandatoryFields { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"http://vimeo.com/m/31158841" }; BOOL result = [viewController validate:values]; ! STAssertTrue(result, @"validate: returned false"); } // MasterViewController.m - (BOOL)validate:(NSDictionary *)values { return([values objectForKey:@"title"] && [values objectForKey:@"author"] && [values objectForKey:@"url"]); } Test Case ‘-[MyVideosTests testValidateMandatoryFields]’ passed 70
  • 71. Testing OCUnit // MyVideosTests.m - (void)testValidatetMalformedURL { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"not an url" }; BOOL result = [viewController validate:values]; ! STAssertFalse(result, @"validate: returned true"); } 71
  • 72. Testing OCUnit // MyVideosTests.m - (void)testValidatetMalformedURL { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"not an url" }; BOOL result = [viewController validate:values]; ! STAssertFalse(result, @"validate: returned true"); } “result” should be false. validate: returned true 72
  • 73. Testing OCUnit // MyVideosTests.m - (void)testValidatetMalformedURL { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"not an url" }; BOOL result = [viewController validate:values]; ! STAssertFalse(result, @"validate: returned true"); } // MasterViewController.m - (BOOL)validate:(NSDictionary *)values { return([values objectForKey:@"title"] && [values objectForKey:@"author"] && [values objectForKey:@"url"] && [NSURL URLWithString:[values objectForKey:@"url"]]); } 73
  • 74. Testing OCUnit // MyVideosTests.m - (void)testValidatetMalformedURL { MasterViewController *viewController = [MasterViewController new]; NSDictionary *values = @{ @"title": @"Murmuration", @"author": @"Islands & Rivers", @"url": @"not an url" }; BOOL result = [viewController validate:values]; ! STAssertFalse(result, @"validate: returned true"); } // MasterViewController.m - (BOOL)validate:(NSDictionary *)values { return([values objectForKey:@"title"] && [values objectForKey:@"author"] && [values objectForKey:@"url"] && [NSURL URLWithString:[values objectForKey:@"url"]]); } Test Case ‘-[MyVideosTests testValidateMalformedURL]’ passed 74