screen~~POS=TRUNC

Velkommen til del seks av Mobiletuts + Beginning iOS Development-serien. Denne avgiften vil dekke grunnleggende Xcode-feilsøking. Det vil inneholde en kort mengde programvare feilsøking teori og en praksis applikasjon for å demonstrere bruken av breakpoints og Xcode debugger. Artikkelen vil konkludere med noen generelle tips og beste praksis, samt en liste over nyttige ressurser som er tilgjengelige for deg å fortsette din læring.

screen~~POS=TRUNC:

Feil ved å se på media over? Få tilgang til full versjon av denne videoen i sin opprinnelige, MOV-format.

Tutorial Transcript:

I stedet for å bygge en ny applikasjon spesifikt for denne opplæringen har jeg tatt FortuneCrunch-programmet som vi opprettet i del to av denne serien, og jeg har introdusert en rekke forskjellige feil i kildekoden. Last ned BrokenCrunch, den ødelagte versjonen av FortuneCrunch som følger med dette innlegget, å følge med som jeg demonstrerer hvordan du bruker Xcode debugging verktøy.

Feilsøkingsteori

Før vi begynner å feilsøke BrokenCrunch, la oss prate et øyeblikk om programvare feilsøkingsteori. Generelt kan programvarefeil (også kjent som "bugs") kategoriseres som følger:

  • Kompileringstidsfeil
  • Run-time feil
  • Logiske feil

Kompileringstidsfeil

Som navnet antyder, oppstår en kompileringstidspause når du forsøker å kompilere programkilden din. I Xcode skjer dette når du velger "Build and Run" eller "Build and Debug" for å starte programmet på enheten eller simulatoren. Når det oppstår en kompileringstidsfeil, vil det bokstavelig talt forhindre at søknaden din blir lansert. Som vi vil se, kan feil i denne kategorien enten oppstå fra usynlige eller feil setningsoppgavene eller fra problemer som oppstår i koblingsfasen i søknadsbyggingen din. Generelt sett er kompileringstidsfeil det enkleste av de tre kategoriene som skal løses fordi kompilatoren typisk vil utstede en meningsfeil feilmelding eller advarselmelding som vil varsle deg om problemets art.

Run-time feil

Driftsfeil oppstår etter at søknaden din er blitt samlet og lansert i simulatoren eller på en enhet. En programkrasj eller minnelekkasje som oppstår som følge av dårlig objektminneadministrasjon er et eksempel på en run-time-feil.

Logiske feil

En logisk feil oppstår i løpet av fasen av en applikasjon og resulterer i uventet eller uønsket applikasjonsadferd som er i konflikt med programvarens utvikleres eller prosjektinteressenters forventede utfall. Et godt eksempel på en logisk feil er en matematisk formel som har blitt implementert feil. Tenk på pythagorasetningen:

Hvis en programvareutvikler utilsiktet implementerte denne formelen som:

Resultatet vil være en logisk feil, men det vil mest sannsynlig ikke føre til at søknaden krasjer. Det er det som gjør logiske feil så farlige: Programmet kan tilsynelatende kjøre "feilfri" til utvikleren mens det faktisk produserer ugyldig eller uønsket utgang.

Feilsøking BrokenCrunch

Med denne teoretiske kunnskapen på plass, åpne BrokenCrunch og la oss komme i gang. Etter at du har lastet inn vårt utvalgsprogram, velger du Bygg> Bygg og feilsøk. Du vil merke at programmet ikke starter, og kompilatoren har generert en rekke feil. Hvis du vil vise resultatene av forsøket på kompilering, velger du Bygg> Bygg resultater.

Hvis du velger feilene som er oppført, tar du deg direkte til koden hvor feilen blir rapportert. En viktig ting å huske på er imidlertid at antall feil som blir rapportert av kompilatoren og linjenumrene til disse feilene, bør betraktes som den "beste gjetningen" av hva som er galt med søknaden din, ikke en avgjørende uttalelse.

Faktisk kan en enkel syntaksfeil føre til at flere feil blir rapportert av kompilatoren som tilsynelatende ikke er relatert til problemet. For eksempel, ta en titt på "Forventet brakett før" setImage "" feillinje. Hvis du undersøker den aktuelle linjen, bør du oppdage at syntaksen er perfekt. Som det viser seg, er problemet her ikke rapportert på linjen, men linjen rett over det. Ser du problemet?

De NSLog () uttalelsen ble ikke avsluttet med et semikolon. Dette betyr at kompilatoren ikke vet at du har tenkt å avslutte linjen etter siste parentes, og ser alt fra NSLog til den endelige avslutningsbraketten og semikolonet etter UIControlStateNormal som en uttalelse.

Legg til semikolon for å fullføre NSLog uttalelse:

 NSLog (@ "I crunchCookie"); 

Lagre kildefilen, og klikk på "Build and Debug" igjen. To av de tre feilene som opprinnelig ble vist, bør nå løses.

Deretter velger du "Ingen erklæring om eiendom" feil. Som du kan se, rapporterer denne feilen at eiendommen vi forsøker å syntetisere, ikke eksisterer. For å bekrefte dette, åpne filen FortuneCrunchViewController.h der eiendommen skulle ha blitt erklært. Hvis du undersøker linje 17, er syntaksen riktig, men vi har feil samsvar mellom egenskapen vi har erklært og den vi forsøker å syntetisere. Mål-C er et saksensitivt språk, noe som betyr at "C" i informasjonskapsel må aktiveres for å matche eiendommen vi forsøker å syntetisere. Oppdater eiendomserklæringen i headerfilen som skal leses:

 @property (nonatomic, behold) IBOutlet * fortuneCookieButton; 

Lagre kildefilen og bygg og feilsøk igjen. Denne gangen, i stedet for å åpne byggresultatene fra Bygg> Bygg og feilsøk, bare klikk på feilikonet i nederste høyre hjørne av Xcode.

Ett skritt fremover, fire skritt tilbake. Feilen vedrørende syntetiseringsegenskapen er borte, men vi har en helt ny liste over feil. Hva skjedde?

Dette er en god tid å legge merke til at de forskjellige faser blir vist i vinduet Bygg resultat:

Legg merke til at vi har en advarsel under «Kompilere» -delen av byggresultatsutgangen. Dette er den samme delen som våre tidligere feil ble rapportert inn. Nå som de tre foregående feilene har blitt løst, har vi gått fra kompileringsfasen til koblingsfasen i vår applikasjonsbygg, og alle de nye feilene er koblingsfeil. Når du opplever en koblingsfeil, er det vanligvis fordi du prøver å bruke funksjoner fra et rammeverk som du ikke faktisk har tatt med i søknaden din. I dette tilfellet refererer Byggresultater til en funksjon som kalles _UIApplicationMain i main.o filen. Main.o er den kompilerte maskinkoden versjon av main.m. La oss ta en titt på kildekoden i den filen. På linje 13 kan du se et funksjonsanrop til UIApplicationMain:

 int retVal = UIApplicationMain (argc, argv, null, null); 

UIApplicationMain er en sentral funksjon for alle iOS-applikasjoner, men hvordan kan du finne ut mer om det og finne ut hvilken ramme det er inkludert i? Heldigvis kommer iOS SDK med stor dokumentasjon. Hvis du holder nede alternativet (eller alt) og dobbeltklikker på funksjonsnavnet, starter du et abstrakt fra den offisielle iOS SDK-dokumentasjonen som diskuterer denne funksjonen. Klikk på "bok" -ikonet øverst til høyre for å se full dokumentasjon tilgjengelig. Du kan se at du så lanserte funksjonsreferansedokumentasjonen for UIKit-rammen. Bingo, vi har vårt manglende rammeverk. Men før vi legger til rammen for prosjektet, la oss undersøke en annen metode som du kunne ha brukt til å bestemme opprinnelsen til UIApplicationMain.

Lukk dokumentasjonsvinduet. Hold nede kommandoknappen og dobbeltklikk på UIApplicationMain funksjon. Du ser nå på kilden til UIApplication.h, headerdeklarasjonsfilen som inneholder UIApplicationMain funksjonsdeklarasjon. Hvis du ruller til toppen av vinduet, vil du se at denne filen importerer flere andre UIKit-overskrifter, og at kommentaren øverst inneholder "UIKit" -rammenavnet.

La oss fortsette å løse disse koblingsfeilene ved å inkludere UIKit-rammen. For å gjøre det, høyreklikk eller kontroller klikk på rammen Rammer i panelet Grupper og filer, og velg legg til> eksisterende rammer. Finn UIKit-rammeverket og klikk på Legg til. For å teste arbeidet vårt, velg Bygg og feilsøk igjen.

Som du kan se, ble simulatoren lansert, og vi kan se vår søknad. Dette betyr at vi har løst alle kompileringstidsfeilene i vår søknad.

Gå videre og klikk på formuekaken ... som du kan se, klikker du på informasjonskapselresultatet i en run-time-feil, og programmet har krasjet. Meldingen som vises nederst til venstre på Xcode-skjermen, er ikke så nyttig, så la oss ta en nærmere titt ved å åpne konsollen.

Konsollen viser både en anropsstabel av hva som skjedde i vår programutførelse på tidspunktet for krasj, samt en mer detaljert forklaring: "Avsluttende app på grunn av uncaught unntak ... FortuneCrunchViewController cookieCruncher: ukjent velger sendt til forekomst." Denne meldingen betyr at vår knapp ringer feil väljare for hendelsen som vi fyrte ved å klikke på informasjonskapsel. Siden grensesnittet til FortuneCrunch ble bygd i Interface Builder, la oss åpne Interface Builder XIB-filen for "FortuneCrunchViewController" for å se nærmere på.

Velg informasjonsknappen og kontroll klikk eller høyreklikk for å vise en liste over tilkoblede handlinger:

Du kan se at Touch Up Inside-hendelsen refererer til et mål som ikke eksisterer, angitt med den gule teksten. Fjern det ikke-eksisterende "cookieCruncher" målet og koble touchUpInside til File Owner igjen ved å velge "crunchCookie" målet som vises i rullegardinmenyen. Lagre arbeidet ditt i Interface Builder, bytt tilbake til Xcode, og start programmet på nytt.

Hvis du klikker på formuekaken, resulterer det igjen i en run-time-feil. Denne gangen er konsollmeldingen ikke så nyttig, den viser bare "EXC_BAD_ACCESS".

Ta en titt på byggresultatene ved å velge Bygg> Bygg resultater. Var du oppmerksom på advarselen tidligere? Compiler advarsler er ofte en indikasjon på en potensiell run-time-feil, men fordi det ikke er noe feil med den faktiske syntaksen av linjen advarselen er utstedt, kan kompilatoren fortsatt bygge programmet vellykket. Selvfølgelig er det tider når en kompilervarsel er et "falskt flagg" og ikke vil resultere i en run-time-feil, men oppover 95% av tiden, hvis kompilatoren har utstedt en advarsel, gjør du noe feil.

Klikk på advarselen for å hoppe til linjen i kildekoden der den skjedde.

Advarselen henviser til inkompatible pekertyper. Ser du problemet? Metoden ImageNamed forventer et NSString-objekt, men denne linjen med kode leverer metoden med en bokstavlig C-stilstreng. Legg til i "@" -symbolet for å gjøre dette til en mål-C-streng:

 [FortuneCookieButton setImage: [UIImage imageNamed: @ "cookie-closed.png"] forState: UIControlStateNormal]; 

Lagre fremgangen din og kjør programmet igjen.

Denne gangen, når du klikker på formuekaken, møter du en logisk feil: programmet krasjer ikke og etiketten "Happy iPhone Hacking" vises som forventet, men bakgrunnsbildet forblir som den lukkede informasjonskapselen.

For å fikse dette, la oss se på funksjonen som er ansvarlig for overgangen: (IBAction) crunchCookie. Linje 19 er ansvarlig for å endre bakgrunnsbildet, og du kan se at det setter det nye bakgrunnsbildet til "cookie-closed.png". Hvis du tar en titt på cookie-stengt i Resources-mappen, ser du at dette faktisk er det samme bildet som vises når appen lastes inn. Vi må bytte den linjen til overgang til "cookie-crunched.png":

 [FortuneCookieButton setImage: [UIImage imageNamed: @ "cookie-crunched.png"] forState: UIControlStateNormal]; 

Bygg og kjør programmet igjen ... og nå tapper informasjonskapselresultatet i det forventede bakgrunnsbildet med etiketten som vises riktig.

Gratulerer! Du har nettopp gått gjennom prosessen med å fikse kompileringstidsfeil, run-time-feil og logiske feil i et program. Hele tiden har vi knapt tappet inn i de kraftige feilsøkingsverktøyene som er tilgjengelige for deg med Xcode.

For å fortsette utforskningen av de mer avanserte feilsøkingsverktøyene som er tilgjengelige, la oss prøve å utvide FortuneCrunch-appen for å gjøre det litt mer interessant. I stedet for å vise den statiske snoren "Happy iPhone Hacking!" Hver gang kaken er knust, la oss bygge en rekke flere NSString verdier som kan vises.

Bytt tilbake til Xcode og åpne filen FortuneCrunchViewController.h. Legg til følgende data medlem:

 NSArray * formuer; 

Denne gruppen vil bli brukt til å holde våre tilfeldige formue strenger.

Nå legger du til følgende metode signatur:

 -(NSString *) generateRandomFortune; 

Denne linjen vil erklære en ny metode i vår klasse som vil bli brukt til å velge en tilfeldig formue fra vår formue.

Deretter bytter du til FortuneCrunchViewController.m. Siden denne klassen vil bli startet fra vår XIB-fil, må vi overstyre initWithCoder metode og allokere gruppen vi erklærte i .h-filen, initialisere den med noen nye formuer:

 -(id) initWithCoder: aDecoder self = [super initWithCoder: aDecoder]; hvis (selv) fortunes = [[NSArray alloc] initWithObjects: @ "Den som kaster skitt, mister jorden.", @ "En lukket munn samler ingen føtter.", @ "Hjelp! Jeg er en fange i et bakeri! ", Nil];  returner selv;  

Nå som vi har opprettet en ny NSArray, ikke glem å slippe det i dealloc metode:

 -(void) dealloc [fortunes release]; 

La oss fortsette å kodes generateRandomFortune funksjon:

 -(NSString *) generateRandomFortune int selected_index = arc4random ()% 3 * 10; return [fortunes objectAtIndex: selected_index];  

Disse linjene genererer ganske enkelt et nytt, tilfeldig indeksnummer som vi skal bruke for å returnere den tilsvarende formuestrengen.

Endelig, endre crunchCookie metode for å bruke en av våre tilfeldige formuer fremfor den statiske teksten "Happy iPhone Hacking!":

 fortuneLabel.text = [self generateRandomFortune]; 

Bygg og kjør programmet etter å ha lagret disse endringene. Hvis du klikker på cookien, vil du opprette en run-time-feil. For å finne ut hvorfor dette skjer, skal vi bruke Xcode debugger og tilpassede bruddpunkter.

Et bruddpunkt er et flagg som signalerer til søknaden din at programutførelsen skal "pause" når linjen med bruddpunktet er nådd. Kjører programmet i "Bygg og feilsøkingsmodus" lar deg bruke bruddpunkter. For å angi et brytepunkt, klikker du bare på redigeringen "renn" på linjen du vil utløse et brytepunkt. For å finne ut hva som skjer i vår søknad, skal vi sette vårt bruddpunkt på NSLog linje, like etter at crunchCookie-metoden heter:

Bygg og feilsøk applikasjonen med dette nye brytepunktet på plass.

Etter at søknaden er lastet, klikker du på cookien. Hvis du ser nederst til venstre på Xcode, vil du se statusmeldingen "Stoppet ved bruddpunkt 1". Dette betyr at debuggeren har sluttet å stoppe programkjøp på pausepunktet du angir. Du vil også merke at en rød pil indikerer den gjeldende utførelseslinjen der feilsøkingsprogrammet har "pauset" programmet.

Så hva kan du gjøre med debugger? Mer enn det kan dekkes i en enkelt opplæring. Det er imidlertid tre grunnleggende handlinger du kan ta på dette punktet: Gå over, gå inn og gå ut. Alle disse alternativene er tilgjengelige for deg fra in-code debugger menylinjen.

Hvis du trykker på "trinn over" -knappen på kodemodus-menyen, vil du legge merke til at programkjøringen fortsetter til neste linje. "Steg over" vil ganske enkelt fortsette å utføre en linje om gangen i den gjeldende metoden, men det følger ikke kjøringen din hvis den gaffel til en annen metode. Hvis du virkelig vil følge kodekjøringen til andre metodeanrop i koden din, må du bruke "trinn inn" -knappen.

Som du kan se, har du tatt inn faktisk har tatt oss inn i generateRandomFortune metode, som er akkurat det vi vil ha. Klikk på "Step over" igjen for å se hva som skjer når arc4random () er kalt. Ville det ikke vært fint hvis vi visste hva variabelen selected_index har blitt satt til? Heldigvis kan vi! En av de beste funksjonene ved å bruke debuggeren er muligheten til å bare musen over variabler for raskt å se deres verdi.

Klart, den chosen_index verdien er mye større enn lengden på vårt utvalg. I motsetning til noen andre programmeringsspråk, vil den randomiseringsfunksjonen vi bruker, returnere et heltall, så det er ikke nødvendig å konvertere fra et desimal til et helt tall ved å multiplisere verdien med 10. Oppdater linjen for å lese:

 int selected_index = arc4random ()% 3; 

Vi er ferdige med å gjøre endringer i denne funksjonen, så bruk "Step Out" -knappen for å gå ut av denne underfunksjonen og gå tilbake til crunchCookie. Vær oppmerksom på at selv om vi ikke så det, ble resten av funksjonen utført som normalt.

Til slutt, ta hensyn til "Aktiver / Deaktiver" pause-knappen og "Fortsett utførelse" -knappen på menyfeltet i kodekodefelt. "Fortsett å gjennomføre" vil bare tillate at programutførelsen fortsetter som normalt. Du kan tenke på det som "unpause" -knappen. Gå videre og trykk dette nå.

Før vi fortsetter å slå av bruddpunkter, er det et problem å takle: Det du nettopp har opplevd kalles "in-code debugger". Det er veldig kraftig, men det finnes også to andre feilsøkingsmoduser tilgjengelig for deg: hele debugger-vinduet og mini-debugger-perspektivet.

For å få tilgang til hele debugger-vinduet, klikk på "debugging" -ikonet på menyfeltet i kodekodefeil. Dette vinduet har betydelig mer informasjon enn in-code debugger. Til venstre har du en stakkespor som viser sammenhengen mellom programgjennomføring (du har også muligheten til å velge fra noen av de gjeldende tråden). Til høyre kan du se en rask visning av de forskjellige variablene som for øyeblikket holdes i minnet. Hvis du velger en annen call-stack-signatur, endres visningen din i Debugger. Du kan endre Debugger-vinduets layout ved å gå til Kjør> Debugger-skjerm.

Endelig er mini-debugger enda et feilsøkingsperspektiv tilgjengelig for deg. Jeg bruker sjelden dette perspektivet, men det er tilgjengelig for deg fra Kjør> Mini-Debugger.

Siden vi bare løst feilen introdusert i vår tilfeldige formuekode, trenger vi ikke lenger debuggeren å være på. Slå av brytepunkter. Men før vi bygger applikasjonen igjen, la oss justere skriftstørrelsen på vår formue.

Åpne Interface Builder, velg etiketten og endre skrift i Inspector til Arial Black, 9 poeng, og velg deretter "Juster til passform" -boksen og endre minste skriftstørrelse til 6 poeng. Nå, bygg og kjør prosjektet igjen.

Voila! Vår søknad fungerer nå som vi ment.

Feilsøkingstips og triks

Nå som du har blitt introdusert til grunnleggende om å bruke Debugger i Xcode, bør du vurdere følgende retningslinjer i din daglige utviklingsprosess:

Test i både simulatoren og på en fysisk enhet

Mens simulatoren er en nyttig metode for å teste et program i utviklingsfasen av produktet, er det ikke en erstatning for testing på en fysisk enhet. Dette skyldes at simulatoren og en iOS-enhet er forskjellige på viktige og grunnleggende måter. For eksempel kjører simulatoren åpenbart i OS X, og filsystemet på OS X er ikke saksfølsomt. Imidlertid er filsystemet på iOS saksfølsomt. Så refererer til filen cookie-CRUNChed.png, i stedet for cookie-crunched.png, vil fungere fint i simulatoren, men mislykkes på en faktisk iOS-enhet. En annen viktig faktor er at simulatoren har mye mer minne tilgjengelig enn en faktisk enhet, og dette faktum vil ofte ha stor innvirkning på brukeropplevelsen. Endelig er ikke alle standardprogrammene som leveres med iOS, tilgjengelige i simulatoren, inkludert Maps og App Store-programmene. Dette betyr at du ikke vil kunne teste koden som genererer veibeskrivelser med Maps-appen eller kryssfremmende programmer i App Store i simulatoren. Dette er bare noen av forskjellene som eksisterer. Jeg anbefaler sterkt testing på så mange fysiske iOS-enheter som kjører så mange forskjellige målrettede versjoner av iOS som mulig.

Bruk Clang Static Analyzer

The Clang Static Analyzer er et spesielt C / Objective-C statisk analyseverktøy som leveres med Xcode. Dette verktøyet kan analysere koden din for feil eller uoverensstemmelser som ellers kan gå ubemerket.

Mens detaljene om hvordan analysatoren fungerer, er utenfor rammen av denne artikkelen, er det heldigvis veldig enkelt å bruke det. For å utføre en statisk analyse av koden, velg bare Bygg> Bygg og analyser fra Xcode build-menyen.

Hvis du vil lære mer om hvordan alternativet "Bygg og analyser" fungerer, kan du lese om Statisk kodeanalyse og Clang Static Analyzer online.

Sett et globalt brytepunkt på objc_exception_throw

I denne opplæringen lærte vi om hvordan breakpoints fungerer ved å angi prosjektspesifikke bruddpunkter i vår kode. I tillegg til å prosjektlegge spesifikke bruddpunkter, vil Xcode også gi deg mulighet til å sette "globale" bruddpunkter som gjelder for alle iOS-prosjektene du lager i Xcode. Setter et globalt brytepunkt på objc_exception_throw lar deg automatisk starte feilsøkeren når et unntak (en type run-time-feil) oppstår. For å lese mer om fordelene med denne tilnærmingen og hvordan du implementerer den i kode, se iOS Quick Tips på objc_exception_throw og globale bruddpunkter.

Behandle advarsler som feil

Som nevnt tidligere i denne opplæringen, bør det store flertallet av kompilatoradvarsler som er utstedt, løses før du starter prosjektet ditt, og det bør egentlig aldri være et scenario når kode som genererer kompilervarsler forbli uendret for at en søknad skal fungere skikkelig. Derfor anbefaler noen programmerer å behandle alle kompilervarsler som feil, og tvinger dem til å løses som en del av den normale utviklingsprosessen.

For alle, men noen få frynser, støtter jeg denne ideen, og Xcode gjør det enkelt å implementere. Gå til Prosjekt> Rediger prosjektinnstillinger og velg deretter kategorien Bygg. Skriv "Behandle advarsel" i søkefeltet, og du vil se en boolesk verdi som heter "Behandle advarsler som feil." Merk av i denne boksen for å aktivere funksjonen.

Bygg og valider før App Store Innlevering

Et annet skritt du kan ta for å øke oddsen for at søknaden din blir akseptert første gang du sender den til iTunes Store, er å aktivere "Bygg og validere" -flagget i prosjektbyggingsinnstillingene. Skriv inn "validere" i søkeboksen til prosjektinnstillingene, og klikk deretter på "Validate Build Product." Dette alternativet kjører noen av testene som ble utført av Apple-korrekturleserne, slik at du potensielt kan forhindre en App Store-avvisning. Det bør bemerkes at å sjekke denne boksen ikke er en garanti for at appen din vil passere App Store-gjennomgang, men det er bedre enn ingenting.

Ekstra Feilsøkingsverktøy

I tillegg til konsollen, bygge resultater og Debugger, er det noen andre gode feilsøkings- og optimaliseringsverktøy du bør være oppmerksom på i utviklingsarbeidet. For videre lesing, ta en titt på dokumentasjonen for følgende verktøy:

  • instrumenter
  • Hai
  • Topp / Spinnkontroll
  • Stor topp

Konklusjon

Dette har vært en hvirvelvind-gjennomgang av feilsøking med iOS SDK. Det er fortsatt mye mer som kan gjøres, men forhåpentligvis har denne leksjonen vært nok til å hjelpe deg med å løse feilene i dine egne programmer raskere og skrive bedre programvare! Hvis du vil høre mer om noen av de avanserte verktøyene som er omtalt i denne opplæringen, som for eksempel Instrumenter, Shark eller SpinControl, eller hvis du vil høre mer om feilsøking generelt, legg igjen en kommentar nedenfor og gi meg beskjed!