Cum să creezi o aplicaţie simplă pentru iPhone în iOS 5: Partea 3/3

Ray Wenderlich

Acest articol este de asemenea disponibil în: Chineza simplificată, Engleză, Franceză, Japoneză, Spaniolă, Arabică, Ungară, Indoneziană, Coreană

Probabil cea mai înfricoşătoare insectă dintre toate!

Probabil cea mai înfricoşătoare insectă dintre toate!

Actualizare 2/20/12: Complet actualizat pentru iOS 5.

Acest articol este partea finală a seriei de trei părţi despre cum să creezi o aplicaţie simplă pentru iPhone pentru începători. Iar în acest caz aplicaţia este despre evaluarea insectelor înfricoşătoare!

În prima parte a seriei am creat o aplicaţie care conţinea o listă de insecte într-un tabel.

În a doua parte a seriei, am tratat crearea unei interfeţe grafice detaliate pentru insecte.

În acest articol vom trata cum să adăugăm noi insecte, cum să adăugăm o iconiţă şi o imagine implicită proiectului nostru şi cum să gestionăm operaţiunile cu timp de desfăşurare îndelungat.

Aşa că hai să finalizăm aplicaţia asta!

Adăugarea şi ştergerea insectelor

Totul funcţionează foarte bine până acum, dar până acum aceasta nu este o aplicaţie foarte prietenoasă pentru utilizator! Adică ce vreau să spun este că primul lucru pe care oricine ar dori să-l facă este să-şi adauge propria insectă, şi până acum singura modalitate de a face asta este prin editarea codului!

Din fericire, deoarece am scris DetailViewController-ul nostru pentru a ne permite să edităm insecte şi utilizăm un UITableViewController pentru controlul grafic principal RootViewController, cea mai mare parte din infrastructură este deja la locul ei! Sunt doar patru modificări pe care trebuie să le facem, dar le voi explica pas cu pas pentru ca lucrurile să fie mai uşor de înţeles:

1) Setează butoanele barei de navigare

În fişierul MasterViewController.m, adaugă următoarele linii de cod la metoda viewDidLoad:

self.navigationItem.leftBarButtonItem = self.editButtonItem;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] 
    initWithBarButtonSystemItem:UIBarButtonSystemItemAdd 
    target:self action:@selector(addTapped:)];

Aici setăm nişte butoane în bara de navigare. Aşa cum “title” este o proprietate specială în controalele grafice utilizate de către controlul de navigare, “navigationItem” este o alta. Ceea ce setezi pentru leftBarButtonItem şi rightBarButtonItem va apare în bara de navigare atunci când controlul de navigare afişează controlul tău grafic.

Pentru leftBarButtonItem folosim un buton standard numit “editButtonItem.” Acest buton este etichetat cu mesajul “Edit” şi trece tabelul din modul de editare (în care poţi şterge rânduri de exemplu) în modul normal standard.

Pentru rightBarButtonItem creăm un buton pe care utilizatorul îl poate apăsa pentru a crea o nouă insectă. Se pare că există deja un element standard de sistem pentru adăugare (care arată ca simbolul +), deci îl folosim şi setăm ca metoda “addTapped:” să fie apelată atunci când butonul este apăsat.

Observă că le poţi seta şi în editorul grafic Storyboard, dar le setez aici în cod ca să-ţi arăt că poţi face lucrurile şi astfel.
2) Implementează metoda tableView:commitEditingStyle:forRowAtIndexPath

Tot în fişierul MasterViewController.m, decomentează metoda tableView:commitEditingStyle:forRowAtIndexPath şi înlocuieşte conţinutul său cu următoarele:

if (editingStyle == UITableViewCellEditingStyleDelete) {        
    [_bugs removeObjectAtIndex:indexPath.row];
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}

Această metodă este apelată atunci când utilizatorul alege să modifice un rând într-un fel sau altul. Noi verificăm dacă utilizatorul încearcă să şteargă rândul şi dacă acest lucru se întâmplă îl ştergem. Observă că trebuie să îl ştergem atât din modelul nostru de date (_bugs) ŞI să informăm tabelul că unul dintre rânduri a fost şters, prin intermediul metodei deleteRowsAtIndexPaths.

3) Gestionează adăugarea unei noi insecte

Apoi adaugă această nouă metodă în fişierul MasterViewController.m:

- (void)addTapped:(id)sender {
    ScaryBugDoc *newDoc = [[ScaryBugDoc alloc] initWithTitle:@"New Bug" rating:0 thumbImage:nil fullImage:nil];
    [_bugs addObject:newDoc];
     NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_bugs.count-1 inSection:0];
    NSArray *indexPaths = [NSArray arrayWithObject:indexPath];    
    [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:YES];
    [self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
    [self performSegueWithIdentifier:@"MySegue" sender:self];    
}

Am setat lucrurile la pasul 1 în aşa fel încât atunci când utilizatorul apasă butonul această metodă se apelează.

Aici creăm un obiect de tipul ScaryBugDoc cu nişte valori implicite şi îl adăugăm în vectorul de insecte. Observă că trebuie să actualizăm şi tabelul pentru a şti că există un nou rând.

Apoi apelăm nişte cod pentru a face tabelul să se comporte ca şi cum uilizatorul a selectat noul rând, deci afişăm imediat interfaţa grafică de editare pentru noua insectă. Mai întâi selectăm rândul în tabel şi apoi facem manual tranziţia pe care am setat-o în editorul grafic Storyboard.

Observă că de fapt până acum nu i-am dat niciodată tranziţiei numele de “MySegue” în editorul grafic Storyboard, aşa că hai să facem asta ca pasul nostru final.

4) Numeşte tranziţia

Deschide MainStoryboard.storyboard şi dă click pe săgeata cu o iconiţă între controlul grafic principal şi cel detaliat – aceasta este tranziţia ta.

Apoi în a patra opţiune din bara laterală (Inspectorul de atribute) setează proprietatea Identifier la valoarea MySegue. În acest mod putem să o rulăm manual când dorim din cod.

Numirea unei tranziţii în Xcode

Asta este tot! Dacă compilezi şi rulezi codul, ar trebui acum să poţi să adaugi propriile tale insecte, ca de exemplu aceasta:

O insectă din Objective-C

Adăugarea unei iconiţe şi a unei imagini implicite

Bine, aplicaţia noastră arată destul de distractiv şi amuzant, aşa că hai să o vindem şi să ne îmbogăţim!

Doar că ar fi destul de ciudat dacă am face asta chiar acum, deoarece nu avem nici măcar o iconiţă!

Din fericire, acest lucru este destul de uşor de corectat. Mai devreme am adăugat o iconiţă la proiectul nostru (logo1.png) din arhiva ExtraStuffForScaryBugs2.zip. Hai să setăm acest fişier să fie iconiţa proiectului nostru!

Pentru a face asta, cea mai uşoară modalitate este de a selecta proiectul tău ScaryBugs în navigatorul de proiect şi apoi selectează sursa ta ScaryBugs. Asigură-te că opţiunea Summary este selectată şi parcurge ecranul în jos până la secţiunea App Icons. Ţine apăsată tasta Ctrl, dă click pe prima iconiţă şi alege Select File:

Schimbarea iconiţei pentru o aplicaţie în Xcode

Alege fişierul logo1.png din directorul proiectului, acceptă orice atenţionări şi ar trebui să vezi că imaginea asociată apare. Dacă primeşti o atenţionare că mărimea imaginii nu corespunde, redimensionează logo1.png la 57×57 (o versiune mai veche a fişierului avea dimensiunile mai mari decât cele standard).

Observă că aceasta este o variantă mai rapidă pentru editarea fişierului ScaryBugs-Info.plist, unde setările aplicaţiei tale ca de exemplu aceasta sunt stocate. Poţi verifica acest lucru deschizând ScaryBugs-Info.plist şi ar trebui să vezi următoarele:

Ce setări să setezi pentru a seta iconiţa unei aplicaţii în fişierul de proprietăţi al aplicaţiei info.plist

Ai fi putut să adaugi manual aceste setări în acest fişier, dar e mai uşor să foloseşti interfaţa grafică cu utilizatorul GUI când aceasta este disponibilă.

Şterge şi reinstalează aplicaţia în simulatorul sau pe telefonul tău şi ar trebui să vezi că apare noua iconiţă!

Noua iconiţă pentru Scary Bugs

Mai este un alt lucru pe care trebuie de asemenea să îl corectăm. Dacă încerci să rulezi ScaryBugs, s-ar putea să observi că după ce apeşi pe iconiţă există o pauză în care apare doar un ecran negru înainte ca primul ecran al aplicaţiei să apară. Acesta este un comportament destul de ciudat – arată ca şi cum aplicaţia nu este foarte interactivă.

Conform documentaţiei Apple, cel mai bun lucru de făcut în acest caz este să afişezi un ecran ce arată exact ca şi primul ecran al aplicaţiei tale, dar fără date încărcate în el încă. Asta este destul de simplu de făcut. Pur şi simplu deschide fişierul MasterController.m şi fă următoarea modificare:

// Înlocuieşte instrucţiunea de returnare din metoda tableView:numberOfRowsInSection: cu următoarea linie de cod:
return 0; //return _bugs.count;

Apoi rulează proiectul pe dispozitivul tău (simulator sau telefon) şi după ce aplicaţia se încarcă vei vedea un tabel gol. În Xcode dă click pe butonul Organizer din bara de instrumente (cea mai din dreapta), dă click pe dispozitivul tău, mergi la opţiunea Screenshots şi dă click pe “New Screenshot” (în partea dreapta – jos) pentru a obţine o captură a ecranului:

Realizarea unei capturi a ecranului în Xcode Organizer

Apoi dă click pe Save as Launch Image. Ai grijă ca spaţiul de lucru ScaryBugs să fie selectat, păstrează numele ca Default şi dă click pe Next.

Imaginea va fi salvată în proiectul tău şi va fi setată pentru tine ca şi imaginea de lansare a aplicaţiei – drăguţ, nu?

Poţi să vezi că imaginea a fost setată ca şi imagine de lansare accesând opţiunea de sumar a sursei proiectului tău:

Setarea imaginii de lansare în setările proiectului în XCode

Apoi reeditează metoda tableView:numberOfRowsInSection: la versiunea iniţială şi rulează aplicaţia din nou. Ar trebui să vezi un ecran implicit în loc de un ecran gol în timp ce aplicaţia se incarcă iar aplicaţia ar trebui să fie mult mai interactivă!

Bonus: Gestionarea operaţiunilor cu timp de desfăşurare îndelungat

Dacă rulezi aplicaţia pe simulator, totul probabil apare în regulă, dar dacă o rulezi pe telefon şi apeşi pe o poză pentru a o schimba, există o LUNGĂ întârziere până când selectorul de imagini UIImagePicker se încarcă. După ce se alege o poză, există o altă lungă întârziere până când imaginea este redimensionată (mai ales dacă este mare). Acesta este un lucru foarte rău, deoarece face ca aplicaţia ta să nu fie interactivă cu utilizatorii.

Regula principală pe care să o reţii este că nu trebuie să desfăşori niciodată operaţiuni cu timp de desfăşurare îndelungat pe firul de execuţie principal. Noi încălcăm în prezent această regulă în două locuri şi de aceea aplicaţia noastră nu pare interactivă.

Ce trebuie să faci în loc de asta este să implementezi operaţiunile cu timp de desfăşurare îndelungat pe un fir de execuţie secundar. Ideal, operaţiunea ar fi realizată în planul secundar în timp ce utilizatorul continuă să facă alte lucruri. Dar dacă operaţiunea trebuie să se desfăşoare înainte ca utilizatorul să poată continua (ca de exemplu încărcarea selectorului de imagini), atunci trebuie să afişezi cel puţin un fel de indicator de încărcare pentru ca utilizatorul să înţeleagă că aplicaţia funcţionează şi nu s-a blocat.

Deci asta vom face aici – rulăm codul cu timp de desfăşurare îndelungat pe un fir de execuţie separat şi afişăm o interfaţă grafică de încarcare pe firul de execuţie principal în timp ce aşteptăm ca operaţiunea să se termine.

Dorinţa de a afişa o interfaţă grafică de încărcare este o problemă tipică pentru dezvoltatorii de aplicaţii, deci foarte mulţi oameni au creat nişte biblioteci de indicatori de activitate pe care le putem folosi pentru a câştiga nişte timp pe care l-am consuma dacă le-am crea noi înşine. Am încercat câteva dintre ele şi preferata mea momentan este SVProgressHUD de Sam Vermette, aşa că hai să o încercăm. Poţi descărca o copie de la pagina Github a SVProgressHUD .

După ce ai descărcat SVProgressHUD, adaugă fişierele SVProgressHUD.h şi SVProgressHUD.m la proiectul tău în grupul “Views”. De asemenea trebuie să realizezi doi paşi de configurare:

  1. Adaugă librăria necesară. Dă click pe proiectul tău în navigatorul de proiect Project Navigator şi selectează sursa ta ScaryBugs. Selectează opţiunea Build Phases şi deschide secţiunea Link Binary with Libraries. Dă click pe butonul + şi adaugă biblioteca QuartzCore.framework.

Adăugarea librăriei necesare QuartzCore.framework în Xcode

  1. Compilează fără ajutor din partea contorului automat de referinţe ARC. SVNProgressHUD nu este momentan compatibil cu contorul automat de referinţe ARC, deci trebuie să-l compilăm fără ajutor din partea contorului automat de referinţe ARC. Pentru a face asta, deschide opţiunea Compile Sources şi dă dublu click pe secţiunea corespunzătoare fişierului SVProgressHUD.m. Tastează textul -fno-objc-arc în fereastra de dialog corespunzătoare pentru a compila fişierul fără ajutor din partea contorului automat de referinţe ARC.

    Actualizare 7/15/12: SVProgressHUD este acum compatibil cu contorul automat de referinţe ARC deci pasul de mai sus nu mai este necesar. Multumim Juan pentru că ne-ai semnalat acest lucru!

În această fază ar trebui să poţi compila proiectul tău fără să generezi erori.

Apoi fă următoarele schimbări în fişierul tău DetailViewController.m:

// La începutul fişierului
#import "SVProgressHUD.h"
// Înlocuieşte metoda addPictureTapped: cu următoarele:
- (IBAction)addPictureTapped:(id)sender {
    if (self.picker == nil) {   
        // 1) Arată starea curentă
        [SVProgressHUD showWithStatus:@"Loading picker..."];
        // 2) Obţine o coadă de aşteptare concurentă de la sistem
        dispatch_queue_t concurrentQueue =
        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        // 3) Încarcă selectorul de imagini în firul de execuţie secundar
        dispatch_async(concurrentQueue, ^{
           self.picker = [[UIImagePickerController alloc] init];
            self.picker.delegate = self;
            self.picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
            self.picker.allowsEditing = NO;    
           // 4) Afişează selectorul de imagini în firul de execuţie principal
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.navigationController presentModalViewController:_picker animated:YES];    
                [SVProgressHUD dismiss];
            });
      });        
 }  else {        
 [self.navigationController presentModalViewController:_picker animated:YES];    
    }
}

Sunt foarte multe idei noi aici, deci le vom parcurge pas cu pas.

  1. Aici utilizăm clasa ajutătoare SVProgressHUD pe care tocmai am adăugat-o pentru a afişa pe ecran o interfaţă grafică cu utilizatorul GUI cu mesajul “Loading” şi cu o animaţie de progres. În acest mod utilizatorul ştie că o operaţiune este în desfăşurare şi că aplicaţia nu s-a blocat pur şi simplu.
  2. Vrem să încărcăm selectorul de imagini în firul de execuţie secundar. Poţi face asta în iOS cu o tehnologie numită Grand Central Dispatch. Nu vom intra în prea multe detalii despre ea aici (dar dacă eşti curios, citeşte acest tutorial). Momentan tot ce trebuie să şti este că această instrucţiune creează o coadă de aşteptare pe care o poţi utiliza pentru a rula blocuri de cod într-un fir de execuţie secundar.
  3. Această linie de cod execută un bloc de cod care încarcă selectorul de imagini în firul de execuţie secundar. Dacă te derutează sintaxa blocurilor, uită-te peste acest tutorial.
  4. În final, afişăm selectorul de imagini în firul de execuţie principal. Reţine că trebuie să actualizezi întotdeauna interfaţa grafică cu utilizatorul GUI în coada de aşteptare principală – nu poţi face asta într-un fir de execuţie secundar.

În mod similar, putem realiza şi redimensionarea imaginii într-un fir de execuţie secundar. Înlocuieşte metoda imagePickerController:didFinishPickingMediaWithInfo: cu asta:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {    
    [self dismissModalViewControllerAnimated:YES];
     UIImage *fullImage = (UIImage *) [info objectForKey:UIImagePickerControllerOriginalImage]; 
    // 1) Arată starea curentă
    [SVProgressHUD showWithStatus:@"Resizing image..."];
    // 2) Obţine o coadă de aşteptare concurentă de la sistem
    dispatch_queue_t concurrentQueue =
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 3) Redimensionează imaginea în firul de execuţie secundar
    dispatch_async(concurrentQueue, ^{
    UIImage *thumbImage = [fullImage imageByScalingAndCroppingForSize:CGSizeMake(44, 44)];
  // 4) Afişează imaginea în firul de execuţie principal
        dispatch_async(dispatch_get_main_queue(), ^{
            self.detailItem.fullImage = fullImage;
            self.detailItem.thumbImage = thumbImage;
            self.imageView.image = fullImage;
            [SVProgressHUD dismiss];
        });
});
}

Şi asta este tot! Rulează aplicaţia pe dispozitivul tău (simulator sau telefon) şi vei vedea o nouă animaţie în timp ce operaţiunea de lungă durată este în desfăşurare, ceea ce creează o interacţiune mult mai plăcută cu utilizatorul.

Utilizarea SVProgressHUD

Unde să mergi de aici?

Iată un proiect model ce conţine întreg codul sursă pe care l-am dezvoltat în această serie de tutoriale.

Felicitări – ai terminat de creat o aplicaţie simplă de tipul Principal/Detaliat Master/Detail pentru iOS! Ai parcurs un curs intens de pus o aplicaţie cap la cap şi poţi explora alte domenii de interes.

Iată ce îţi recomand să citeşti mai departe:

Îţi doresc foarte mult noroc în aventurile tale de programare în iOS şi sper că ţi-a plăcut să creezi această aplicaţie ScaryBugs! Dacă ai întrebări sau sugestii, te rog înscrie-te pe forumul de discuţii de mai jos!

Ray Wenderlich

Ray is an indie software developer currently focusing on iPhone and iPad development, and the administrator of this site. He’s the founder of a small iPhone development studio called Razeware, and is passionate both about making apps and teaching others the techniques to make them.

When Ray’s not programming, he’s probably playing video games, role playing games, or board games.

Comentariile utilizatorului

0 Comment

Other Items of Interest

Buletinul de ştiri lunar online al lui Ray

Înregistrează-te pentru a primi un buletin de știri lunar cu siteurile mele de dezvoltare preferate și primești un tutorial amplu gratuit ca și bonus!

Fă reclamă cu noi!

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in May: Procedural Level Generation in Games with Kim Pedersen.

Sign Up - May

Coming up in June: WWDC Keynote - Podcasters React! with the podcasting team.

Sign Up - June

Vote For Our Next Book!

Help us choose the topic for our next book we write! (Choose up to three topics.)

    Loading ... Loading ...

Cărțile noastre

Echipa noastră

Echipa de tutoriale

  • Matt Luedke

... 55 în totalitate!

Echipa editorială

  • Matt Galloway

... 21 în totalitate!

Code Team

  • Orta Therox

... 1 în totalitate!

Echipa de traducători

  • Victor Grushevskiy
  • Fabio Casado

... 38 în totalitate!

Experți în materie de subiecte

  • Richard Casey

... 4 în totalitate!