SlideShare ist ein Scribd-Unternehmen logo
1 von 74
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Was ist angesagt?

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
 

Was ist angesagt? (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
 

Ähnlich wie 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
 

Ähnlich wie 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
 

Mehr von 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
 

Mehr von 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
 

Kürzlich hochgeladen

Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 

Kürzlich hochgeladen (20)

Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 

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