Foutopsporing in iOS - essentiële tips

Of u nu probeert uit te zoeken waarom uw array 3 objecten heeft in plaats van 5 of waarom uw game achteruit speelt sinds de nieuwe persoon is gestart, het debuggen is een essentieel onderdeel van het ontwikkelingsproces. Aan het einde van dit artikel, zult u een goed begrip hebben van de belangrijkste debug-faciliteiten die voor u beschikbaar zijn en hoe u ze kunt gebruiken om uw bugs in minder tijd te verpletteren.

We zullen bespreken hoe:

  • Inspecteer de status van uw applicaties met behulp van de console
  • Voer logboekregistratie uit en ga verder dan NSLog
  • Volg geheugengebruik door de levenscyclus van een object te volgen

Inspectie met behulp van de console

Die kleine zwarte doos onderaan Xcode zou je beste vriend moeten zijn als het gaat om foutopsporing. Het voert log berichten, foutmeldingen en allerlei andere nuttige dingen uit die u zullen helpen bij het opsporen van fouten. Naast het rechtstreeks lezen van de uitvoer van het logboek, kunnen we ook stoppen op een bepaald punt in ons programma en verschillende delen van onze applicatie inspecteren.

Voorwaardelijk gebroken

Ik ga ervan uit dat je weet hoe breekpunten werken (en als je dat niet doet, maak je geen zorgen, je pakt het op aan het einde van dit!). Breekpunten zijn van onschatbare waarde om te zien waar onze applicatie zich op een bepaald moment bevindt, maar het kan een pijn zijn om door een lus of recursieve functie te stappen nadat een breekpunt is geactiveerd totdat ons object gelijk is aan een bepaalde waarde. Voorwaardelijke onderbrekingspunten invoeren!

Voorwaardelijke breekpunten zijn breekpunten die alleen zullen breken als aan een bepaalde voorwaarde is voldaan. Stel je voor dat we alleen willen breken als een object zich in een bepaalde staat bevindt, of bij de 'nth'-iteratie van een lus. Voeg een breekpunt toe aan uw code door op de 'goot' van de Xcode-editor te klikken, klik met de rechtermuisknop op het breekpunt en selecteer vervolgens 'Breekpunt bewerken' om speciale voorwaarden in te stellen.

U kunt een voorwaarde opgeven (bijvoorbeeld i == 12) of het aantal keren dat het onderbrekingspunt moet worden genegeerd. U kunt ook acties toevoegen die automatisch na de pauze plaatsvinden, bijvoorbeeld een foutopsporingscommando dat een waarde afdrukt.

Tip: De sneltoets voor het toevoegen / verwijderen van een breekpunt is command + \

Een andere belangrijke breekpunttruc om te implementeren, is het toevoegen van het 'uitzonderingsbreekpunt'. Ooit opgevallen dat X% 99% van de tijd dat we op een uitzondering stoten, ons meeneemt naar de autorelease-pool in onze hoofdmethode?


Bedankt Xcode ... erg nuttig!

Door een uitzonderingsbreekpunt in te stellen, kunt u de exacte regel code gebruiken die de uitzondering met een onderbrekingspunt heeft veroorzaakt. Hiertoe opent u het tabblad Breekpunt uitzonderingen (opdracht + 6). Linksonder in het venster staat een knop "+". Selecteer dit om een ​​'uitzonderingsbreekpunt' toe te voegen. Wanneer Xcode nu een uitzondering tegenkomt, zal het breken waar in de code het voorkomt.

Handmatig afdrukken vanaf de console

Als we op een bepaald punt in onze app in het algemeen gesproken hebben gebroken, komt dat omdat we willen zien in welke staat onze objecten zich bevinden. Xcode geeft ons de 'variabelenweergave', die weergave onderaan Xcode naast de console. In theorie geeft het de huidige status weer van alle waarden die relevant zijn in de huidige context. In de praktijk blijkt dit soms een kleine buggy te zijn. Soms worden er geen waarden vermeld of worden ze niet bijgewerkt wanneer u er doorheen gaat.

Gelukkig kunnen we specifieke objecten zelf inspecteren met behulp van een aantal zeer bruikbare console-opdrachten. Door 'po' in de console te typen, kunnen we direct informatie krijgen over een bepaald object (bij scalaire waarden gebruiken we 'p').

Dit kan handig zijn om te zien of een object al bestaat (dit wordt afgedrukt nul als dit niet het geval is), de waarde van een object bepalen, achterhalen wat een array / woordenboek bevat tijdens runtime en zelfs twee objecten vergelijken. Omdat met deze opdracht het geheugenadres van het relevante object wordt afgedrukt, kunt u twee objecten afdrukken waarvan u denkt dat ze dezelfde zijn en zien of ze hetzelfde geheugenadres hebben om zeker te zijn.

Een andere bruikbare maar verborgen opdracht die u kunt gebruiken om uw inzichten eenvoudig te inspecteren is de recursiveDescription commando. Roep dit op in een weergave om een ​​afdruk uit de weergavehiërarchie te krijgen.


Effectieve logging

Er zijn bepaalde tijden dat we bij het debuggen van ons programma een bepaald bericht naar de console willen loggen. Met de 'NSLog'-functie kunnen we alle gewenste uitvoer naar de console afdrukken. Dit kan belangrijk zijn als we bepaalde paden door onze applicatie willen volgen of willen testen wat een waarde is, zonder dat we op elke mogelijke manier expliciet breekpunten moeten plaatsen. NSLog volgt hetzelfde formaat als [NSString StringWithFormat] methode (zoals je kunt zien in de snelkoppeling hieronder).

Tip: Nieuw bij het formatteren van strings in Objective-C? Bekijk Apples String Programming Guide

Smart worden met NSLog

Hoewel NSLog handig is, moeten we slim zijn over hoe we het implementeren. Alles dat wordt afgedrukt vanuit NSLog, gaat in productiecode en is daarom voor iedereen zichtbaar. Als iemand het apparaat in de organizer zou pluggen en naar de console zou kijken, zou hij elk logbericht kunnen zien. Zoals je je kunt voorstellen, kan dat serieuze gevolgen hebben! Stel je voor dat je een geheime logica van het algoritme of het wachtwoord van de gebruiker op de console hebt afgedrukt! Hierdoor worden apps soms geweigerd als Apple te veel output detecteert naar de console in een productie-build.

Gelukkig is er een betere manier om te loggen. Afhankelijk van hoeveel moeite je wilt doen, zijn er verschillende manieren om dit aan te pakken. Misschien is de gemakkelijkste manier om een ​​macro te gebruiken die alleen NSLog bevat in debug-builds. Als u dit opneemt in een globaal toegankelijk header-bestand, kunt u zoveel logs als u wilt invoegen in uw code, anders gaat er niets naar de productie (op voorwaarde dat u de standaard pre-processor macrowaarden niet wijzigt en als u niet weet wat die zijn, maak je geen zorgen).

 # ifdef DEBUG #define DMLog (...) NSLog (@ "% s% @", __PRETTY_FUNCTION__, [NSString stringWithFormat: __ VA_ARGS__]) #else #define DMLog (...) do  while (0)

Als u nu DMLog gebruikt (of wat u ook kiest om de uwe te bellen), zal dit alleen worden afgedrukt tijdens een debug-build. Elke productieversie zal niets doen. __PRETTY_FUNCTION__ helpt ook door de naam af te drukken van de functie waarvan de logging afkomstig is.

De volgende stap nemen

Hoewel NSLog geweldig is, heeft het een aantal beperkingen:

  • Het drukt alleen lokaal af
  • Je kunt een log niet een 'niveau' geven. (Bijvoorbeeld kritiek, waarschuwing, alles, enz.)
  • NSLog is traag. Het kan uw programma drastisch vertragen bij het uitvoeren van een grote hoeveelheid verwerking

Voor degenen die hardcore over logging willen krijgen, zijn er frameworks die sommige of al deze limities overwinnen, afhankelijk van hoeveel moeite je in wilt doen. Ik raad aan om de volgende tools te bekijken:

  • Cocoa LumberJack - Een van de bekende en veelzijdige houtkapkaders voor Cocoa. Een beetje een leercurve maar het is erg krachtig
  • SNLog - Een daling in vervanging voor NSLog

Volgende objectlevenscycli

Hoewel de introductie van Automatic Reference Counting (ARC) ervoor heeft gezorgd dat geheugenbeheer niet de enorme tijdvampier is die het vroeger was, is het nog steeds belangrijk om belangrijke gebeurtenissen in de levenscycli van ons object te volgen. ARC neemt immers niet de mogelijkheid van geheugenlekken weg of probeert toegang te krijgen tot een vrijgegeven voorwerp (het maakt dit eenvoudigweg moeilijker te doen). Hiertoe kunnen we een aantal processen en hulpmiddelen implementeren om ons in de gaten te houden wat onze objecten aan het doen zijn.

Belangrijke evenementen loggen

De twee belangrijkste methoden in de levenscyclus van een objectief-C-object zijn de in het en dealloc methoden. Het is een geweldig idee om deze gebeurtenissen bij uw console te registreren, zodat u kunt kijken wanneer uw objecten tot leven komen en, nog belangrijker, ervoor zorgen dat ze weggaan wanneer ze worden verondersteld.

 - (id) init self = [super init]; if (self) NSLog (@ "% @:% @", NSStringFromSelector (_cmd), self);  terugkeer zelf;  - (void) dealloc NSLog (@ "% @:% @", NSStringFromSelector (_cmd), self); 

Hoewel het typen van deze code misschien vervelend lijkt om te beginnen, zijn er manieren om het proces te automatiseren en eenvoudiger te maken. Ik kan garanderen dat het van pas zal komen als je applicatie zich gedraagt ​​zoals anders. Je kunt ook enkele trucjes gebruiken die je hebt geleerd in het logboekgedeelte, dus dit wordt niet afgedrukt in een productie-build (of zelfs, maak er zelf een macro voor!).

De statische analysator en de inspecteur

Er zijn twee tools bij Xcode die we kunnen gebruiken om onze code op te schonen en onze code minder foutgevoelig te maken. De Static Analyzer-tool is een handige manier voor Xcode om verbeteringen aan te bevelen aan onze code, van ongebruikte objecten tot mogelijk onder of over vrijgegeven objecten (nog steeds een probleem met ARC voor Core Foundation-objecten). Om deze aanbevelingen te bekijken, gaat u naar Product en selecteert u 'Anlayze'.

De inspecteur is een krachtig hulpmiddel waarmee we verschillende aspecten van onze toepassing nauwgezet kunnen 'inspecteren' met betrekking tot geheugengebruik, activiteit op het bestandssysteem en het biedt zelfs manieren om UI-interactie te automatiseren. Om uw applicatie te 'inspecteren', selecteert u 'Profiel' in het vervolgkeuzemenu 'Product'.

Dit opent het venster Instrumenten waarin u een profielsjabloon kunt selecteren om uit te voeren. De meest voorkomende om uit te voeren zijn zombies (we zullen dit later bespreken), activiteitsmonitor en lekken. Lekken is misschien wel de meest bruikbare sjabloon om eventuele geheugenlekken die mogelijk aanwezig zijn in uw toepassing op te sporen.

Zombies zijn je vriend

Hoewel het veel moeilijker is om de gevreesde EXC_BAD_ACCESS-fout tegen te komen nu ARC op zijn plaats is, kan het nog steeds onder bepaalde omstandigheden gebeuren. Wanneer het gaat om UIPopoverController of kernfundament-objecten, kunnen we nog steeds proberen toegang te krijgen tot een te sterk vrijgegeven object. Normaal gesproken is het voor altijd als we een object in het geheugen vrijgeven. Wanneer Zombies zijn ingeschakeld, wordt het object echter alleen gemarkeerd als vrijgegeven maar blijft het in het geheugen. Op die manier kunnen we bij het benaderen van een Zombie-object ons laten weten dat je probeerde toegang te krijgen tot een object dat er normaal niet zou zijn. Omdat het nog steeds weet wat het is, kan het u laten weten waar en wanneer het is gebeurd.

Je kunt Zombies op twee manieren opsporen. Ofwel door de inspecteur te gebruiken en een Zombie-profielsjabloon uit te voeren, of door het in te schakelen als een diagnostische optie binnen de 'Run' build-optie. Klik naast de stopknop op de schemanaam en klik vervolgens op 'Schema bewerken'. Onderlopen klikt u op het diagnosetabblad en selecteert u 'Zombie-objecten inschakelen'. Merk op dat foutopsporing in de Zombie-modus alleen beschikbaar is bij foutopsporing in de simulator, je kunt het niet op een echt apparaat doen.


Conclusie

Hopelijk gaf het bovenstaande u een paar inzichten in hoe u uw applicaties effectiever kunt debuggen. Het gaat er allemaal om manieren te vinden om tijdrovende bugfixatie te verminderen, zodat we meer tijd kunnen besteden aan het doen van wat belangrijk is, geweldige apps bouwen!

Dit is geenszins een uitgebreide lijst. Er zijn veel andere technieken die hier niet zijn besproken, zoals debuggingproblemen bij de productie, bugrapportage op afstand, crashrapportage en meer. Heb je een techniek die je wilt delen? Misschien heb je een vraag in verband met een van de bovenstaande punten? Plaats het hieronder in de reacties!

Happy Programming!