Best practices en hulpmiddelen voor iOS-projecten

Met een open source Xcode-projectsjabloon

Bij het werken aan greenfield iOS-projecten moest ik vaak een nieuw project helemaal opnieuw beginnen. Terwijl ik dat deed, besteedden ik en mijn team altijd veel tijd aan basisprojectinstallatie, zoals het integreren van tools, het opzetten van de projectstructuur, het schrijven van basisklassen, het integreren van externe bibliotheken, enz.

Ik besloot dat de tijd die werd besteed aan het opstarten van een project kon worden bespaard en het proces grotendeels kon worden geautomatiseerd. Ik heb alle gebruikelijke best practices en tools die we gebruikten opgeschreven en een projectsjabloon opgesteld die ik en mijn team konden gebruiken bij het starten van nieuwe projecten. Deze sjabloon moet de tijd voor het opzetten van een project besparen en biedt ook een gemeenschappelijke basis waaraan elk teamlid gewend zal zijn, zodat u niet hoeft na te denken en de projectstructuur en -stichtingen te verkennen. Ze zullen altijd hetzelfde zijn.

Elke tool of best practice in de sjabloon verdient een afzonderlijk artikel, maar ik wilde proberen elk punt samen te vatten en een korte uitleg geven waarom ik ze heb opgenomen.

Cocoapods

Ik denk niet dat deze een introductie nodig heeft. Dit is de bibliotheek voor het beheren van externe afhankelijkheden voor iOS-projecten. Het bestaat al lang en is robuust en getest in duizenden (zo niet miljoenen) projecten. Er zijn alternatieve afhankelijkheidsbeheerders zoals Carthage, maar ik besloot om voor Cocoapods te gaan omdat het het breedste scala aan open source-projecten heeft dat het ondersteunt. Het gebruik van Cocoapods is heel eenvoudig en wordt geleverd met een zoekindex waarmee u eenvoudig pakketten kunt vinden die u nodig heeft.

Het sjabloonproject wordt geleverd met een eenvoudige Podfile met Swiftlint en R.swift. De sjabloon bevat ook een Gemfile voor het beheer van de Cocoapods-versie die wordt gebruikt om de afhankelijkheden op te lossen. Dit is een vaak over het hoofd geziene verbetering die problemen voorkomt wanneer ontwikkelaars in uw team afhankelijkheden installeren met verschillende versies van Cocoapods zelf. De Gemfile dwingt het gebruik van dezelfde Cocoapods-versie door het hele team.

Swiftlint

Swiftlint is een zeer handig hulpmiddel voor het afdwingen van bepaalde regels en codeerstijlen voor elke programmeur in het team. Je kunt het beschouwen als een geautomatiseerd systeem voor codebeoordeling dat de programmeur waarschuwt voor gevaarlijke dingen zoals geforceerd uitpakken, geforceerde casts, geforceerde pogingen enz., Maar ook een gemeenschappelijke coderingsstijl afdwingt door ervoor te zorgen dat alle programmeurs dezelfde "codestijl" gerelateerde regels volgen zoals inspringen of regelafstand. Dit heeft enorme voordelen doordat het niet alleen codebeoordelingstijd bespaart door die basiscontroles uit te voeren, maar het zorgt er ook voor dat alle bestanden in het project er vertrouwd uitzien, wat hun leesbaarheid en bijgevolg hun begrip door alle ontwikkelaars verhoogt. U vindt hier een lijst met alle regels. In de sjabloon wordt Swiftlint geïnstalleerd via Cocoapods en opgenomen in de stap Build-fasen, zodat het de ontwikkelaar kan linten en waarschuwt bij elke project-build.

R.swift

R.swift is een hulpmiddel voor het verkrijgen van sterk getypte, autocomplete bronnen zoals afbeeldingen, lettertypesegmenten en lokalisaties. Het doet dit door uw project te scannen en snelle klassen te genereren die nodig zijn om de middelen te krijgen. Het grootste verkoopargument van deze bibliotheek is dat tijdens het gebruik van bronnen uw code wordt gemaakt:

  • Volledig getypt - minder casten en raden wat een methode zal opleveren
  • Compileertijd gecontroleerd - geen onjuiste tekenreeksen meer die ervoor zorgen dat uw app tijdens runtime crasht
  • Automatisch voltooid - hoef nooit meer die naam van afbeelding / penpunt / storyboard te raden

Overweeg de volgende code met behulp van de officiële tekenreeks-API:

let icon = UIImage (genaamd: "custom-icon")

Als u de afbeeldingsnaam verkeerd spelt, krijgt u hier een nul. Als een lid van uw team de naam van de afbeeldingsresource wijzigt, retourneert deze code nul of crasht als u de afbeelding geforceerd uitpakt. Bij het gebruik van R.swift wordt dit:

let icon = R.image.customIcon ()

Nu kunt u er zeker van zijn dat het pictogram echt bestaat (de compiler waarschuwt u als dit niet te danken is aan tijdcontroles) en u bent zeker dat u geen typefout in de pictogramnaam zult maken, omdat u autocomplete zult gebruiken.

R.swift wordt geïnstalleerd via Cocoapods en geïntegreerd in de sjabloon als een build-fase en genereert de Swift-wrapper-klassen voor elke build. Dat betekent dat als u een bestand / afbeelding / lokalisatie / lettertype / kleur / penpunt enz. Toevoegt, het voor u beschikbaar is met R.swift zodra u het project compileert.

Afzonderlijke app Delegeren voor tests

Een vaak over het hoofd gezien goede praktijk is om een ​​aparte TestAppDelegate-klasse te hebben tijdens het uitvoeren van tests. Waarom is het een goed idee? Nou, meestal doet de klasse AppDelegate veel werk bij het opstarten van de app. Het zou een venster kunnen opzetten, de basis UI-structuur van de app kunnen bouwen, zich kunnen registreren voor meldingen, een database kunnen opzetten en soms zelfs API-oproepen kunnen doen naar een backend-service. Eenheidstests mogen geen bijwerkingen hebben. Wil je echt willekeurige api-oproepen doen en de hele UI-structuur van je app instellen, alleen om wat unit-tests uit te voeren?

De TestAppDelegate is ook een geweldige plek om code te hebben die u maar één keer wilt uitvoeren tijdens de uitvoering van uw testsuite. Het kan code bevatten die mocks, stubs netwerkverzoeken etc. genereert.

De sjabloon bevat een main.swift-bestand dat het belangrijkste toegangspunt voor de app is. Dit bestand heeft methoden die controleren wat de omgeving is die de app momenteel uitvoert en als het de testomgeving is, roept deze de TestAppDelegate op.

Vlaggen van compilerprestaties

Swift is een geweldige taal, gemakkelijker te gebruiken en veel veiliger dan Objective-C (IMO). Maar toen het voor het eerst werd geïntroduceerd, had het een groot nadeel: compileer tijden. In de Swift 2 dagen werkte ik aan een project dat ongeveer 40k regels Swift-code had (een middelgroot project). De code was erg zwaar met generieke typen en type-inferenties en het duurde bijna 5 minuten om een ​​schone build te compileren. Wanneer u zelfs een kleine wijziging aanbracht, zou het project opnieuw worden gecompileerd en duurde het ongeveer 2 minuten om de wijziging te zien. Dat was een van de slechtste ontwikkelaarservaringen die ik ooit heb gehad en daarom ben ik bijna gestopt met het gebruik van Swift.

De enige oplossing in die tijd was om te proberen de compilatietijden van het project te profileren en te proberen uw code zodanig te wijzigen dat de compiler sneller zou worden. Om dit te helpen introduceert Apple een aantal niet-officiële compileervlaggen die u waarschuwen wanneer het compileren van een methode of het oplossen van het type expressie te lang duurde. Ik heb die vlaggen aan het sjabloonproject toegevoegd, zodat je vanaf het begin wordt gewaarschuwd over lange compilatietijden voor je app.

Tegenwoordig zijn de bouwtijden drastisch verbeterd en hoeft u zelden uw code aan te passen om de bouwtijden te verbeteren. Maar toch is het beter om van te voren te weten dan om te proberen het probleem op te lossen wanneer het project te groot wordt.

Dev / Staging / Production-configuraties

Een andere goede praktijk (of kan ik de noodzaak zeggen) is om afzonderlijke configuraties en omgevingsvariabelen te hebben voor de ontwikkel-, staging- en productieomgevingen. Bijna elke app moet tegenwoordig verbinding maken met een soort backend-service en meestal worden die services in meerdere omgevingen geïmplementeerd. De ontwikkelomgeving wordt gebruikt voor dagelijkse implementaties en voor ontwikkelaars om hun code te testen. De staging-omgeving wordt gebruikt voor stabiele releases voor testers en clients om te testen. We weten allemaal waar de productieomgeving voor is.

Een manier om meerdere omgevingen in een iOS-project te ondersteunen, is door configuraties op projectniveau toe te voegen.

Configuraties op projectniveau

Nadat u de configuraties hebt gedefinieerd, kunt u een Configuration.plist-bestand maken met de variabelen voor elke omgeving.

Configuration.plist

Tijdens het uitvoeren van het project kunt u opgeven welke configuratie moet worden gebruikt. U kunt dit doen in het buildschema.

U moet vervolgens een extra eigenschap toevoegen aan het project Info.plist-bestand. De waarde van deze eigenschap wordt tijdens runtime dynamisch omgezet naar de naam van de huidige configuratie.

Dit is allemaal vooraf voor u geconfigureerd in de sjabloon.

Het enige dat overblijft is om een ​​klasse te schrijven die deze variabelen tijdens runtime kan ophalen, afhankelijk van de configuratie die is geselecteerd in het buildschema. De sjabloon bevat een klasse ConfigurationManager die de variabelen voor de huidige omgeving kan ophalen. Je kunt de implementatie van die klasse op Github controleren om te zien hoe het werkt.

Leesmij

Elk project moet een basis-leesmij hebben met ten minste instructies voor het installeren van afhankelijkheden en het uitvoeren van het project. Het moet ook een beschrijving van de projectarchitectuur en modules bevatten. Helaas schrijven ontwikkelaars niet graag documentatie (een readme maakt daar deel van uit) en ik heb een project gezien dat al maanden werd ontwikkeld en ze hadden zelfs een basis-readme. Om de last van het schrijven van dit eenvoudige leesmij weg te nemen, bevat de sjabloon een standaard leesmij die installatie- en projectstructuur omvat. Wanneer u een nieuw project instelt met behulp van de sjabloon, wordt het Leesmij automatisch opgenomen.

gitignore

Tegenwoordig gebruiken de meeste projecten GIT als hun versiebeheersysteem. Bij het gebruik van GIT negeert u meestal sommige bestanden of mappen in het project, zoals de buildmap of de afgeleide datamap. Om u de moeite te besparen een gitignore-bestand te zoeken dat bij uw iOS-project past, bevat de sjabloon een standaard gitignore van Github-bijdragers.

Basisklassen voor het verwerken van deeplinks en meldingen

Bijna elke app moet tegenwoordig deeplinks en meldingen verwerken. Hiertoe moet een ontwikkelaar een hoeveelheid boilerplate-code schrijven in de klasse AppDelegate. De sjabloon heeft dat bedekt en biedt ook basisklassen die het werken met deeplinks en meldingen eenvoudiger maken.

Samenvatting

Samenvattend: de sjabloon probeert best practices op te nemen en integreert handige tools van derden. Dit zou u en ons team uren moeten spenderen aan het opzetten van een nieuw project en tevens een gemeenschappelijke en sterke basis vormen voor de rest van het project. Moge het u goed van dienst zijn!

PS: als je problemen hebt of een verzoek voor een functie voor de sjabloon, laat me dan een probleem op Github achter. Ik zal proberen het in mijn vrije tijd op te lossen.