I den första artikeln i den här serien satte vi upp ett nytt XCode-projekt, installerade CocoaPods, konfigurerade SwiftLint och aktiverade lokaliseringsstöd i appen. Vi fortsätter exakt där vi slutade, så om du missade den första artikeln , läs den först!
Nu är det dags att börja fundera på projektarkitektur. Det finns många iOS-arkitekturmönster som vi kan använda:
Vi kommer att använda MVVM- arkitekturmönstret för vår SwiftUI-app eftersom det praktiskt taget är inbyggt i SwiftUI och är enkelt att använda för både utveckling och testning. Apple rekommenderar det även för SwiftUI. Vi har inte tillräckligt med utrymme för att jämföra och diskutera alla dessa arkitekturer i den här artikeln, så jag råder dig att undersöka olika SwiftUI-arkitekturer för att se vilka för- och nackdelar var och en har.
När du arbetar med ett arkitekturmönster, kom ihåg att det är praktiskt taget omöjligt att följa det till 100 %, och att du kommer att anpassa din projektarkitektur och kod som du tycker passar, beroende på dina krav. Se helt enkelt den här versionen som en utgångspunkt, som kommer att växa och förändras organiskt tillsammans med din app.
Med det sagt, låt oss börja!
Varje projektarkitektur börjar med ett beslut om hur man ska organisera mappar och filer. Det finns två vanligaste metoderna: funktionsbaserade och funktionsbaserade . Vi kommer att använda den funktionsbaserade metoden i vår app eftersom den är mycket tydligare och enklare att underhålla i längden.
Eftersom det är en funktionsbaserad metod är det första steget att definiera vilka funktioner vi kommer att ha. Låt oss anta att vår app kommer att ha följande funktioner:
Det betyder att vi kommer att ha tre mappar: Inloggning, Hem, och Inställningar inuti vår Drag mapp, som kommer att finnas i vår Koda mapp, så det kommer att se ut så här:

Eftersom vi använder MVVM behöver vi speciella mappar i varje funktion för att lagra alla våra filer för future view, modell och view model. Därför kommer var och en av våra funktionsmappar att innehålla undermappar: Visningar, Modelleroch VisaModeller.

Men enligt min erfarenhet skulle det vara mycket bra för läsbarheten att faktiskt skilja mellan vyer som representerar våra appskärmar och vyer som bara är små atomkomponenter, såsom knappar eller etiketter (vi kommer att använda dem på våra skärmar). Så, låt oss skapa en annan mapp som heter Skärmar, var vi ska placera dessa containervyer.
Det är också bra att ha en särskild plats (mapp) i varje funktion som innehåller kod som hanterar API-förfrågningar som funktionen kommer att använda. Detta är viktigt av två skäl. Den första anledningen är att vi inte vill att våra vymodeller ska vara för stora genom att fylla dem med API-hanteringskod. Den andra, ännu viktigare anledningen, är att vi vill hålla vår affärslogik (som hör hemma i en vymodell) separat från vår API-logik, som ska vara mycket enkel och bara bry sig om att göra API-förfrågan och avkoda svaret.
Låt oss placera våra API-förfrågningar i en speciell mapp som heter ÅtgärderAllt våra åtgärder kommer att göra är att skapa API-förfrågningar, avkoda svar och skicka resultaten till vymodellen. Inget mer. All anpassad logik som sker efter att vi mottagit svaret kommer att hanteras i vymodellen. På så sätt kan vi alltid anropa åtgärder från våra vymodeller när vi behöver göra en API-förfrågan och behandla dem som svarta lådor.
Du kommer definitivt att ha filer som inte tillhör en enskild funktion utan kan användas i olika delar av din app. Ett exempel på detta skulle vara en knapp som du använder på många olika skärmar i din app. Ett annat exempel är en API-förfrågan som du gör på global nivå, till exempel att hämta loggad användardata. Det betyder att vi också behöver en Gemensam funktionsmapp för att lagra alla filer som påverkar mer än en enda funktion.
Slutligen, låt oss sortera alla dessa undermappar efter namn, så att de är konsekventa. Med alla dessa ändringar på plats kommer vår mappstruktur nu att se ut så här:

Okej! Nu kan vi enkelt hitta våra funktioner och få en tydlig överblick över var allt finns i vår app. Den här metoden gör det också väldigt enkelt att lägga till eller ta bort funktioner utan att det påverkar en massa filer i olika mappar över hela projektet. Även om den här mappstrukturen kan verka överväldigande till en början är det definitivt rätt sätt att go om du bygger en app som förväntas växa i storlek, eftersom du alltid enkelt kan hitta och arbeta med dina filer, oavsett hur många funktioner du har. Även om din app har 20 funktioner kan du helt enkelt fokusera på den funktionsmapp du arbetar med just nu och ignorera (de flesta av) de andra mapparna i projektet.
Eftersom inställningsfunktionen bara nämndes för demonstration och vi inte kommer att skapa någon inställningsfunktion i den här serien, låt oss ta bort inställningsmappen och radera hela funktionen från det här projektet. Ja, det är så enkelt!
Tänk på att detta bara är en skelett av vad du kan behöva och att det förväntas växa och anpassas över tid allt eftersom du fortsätter att lägga till funktioner i din app. Du kan till exempel behöva lägga till en ViewModifiers mappen i din Gemensam mappen där du kommer att lägga alla dina vymodifierarfiler.
Naturligtvis kanske du inte ens behöver alla dessa undermappar för varje funktion. Om din funktion till exempel inte har några åtgärder, finns det ingen anledning att ha den Handling mapp i den.
Nu ska vi fundera på vad vi mer behöver i vår app så att vi kan skapa motsvarande mappar. Eftersom vi planerar att täcka vår app med tester behöver vi definitivt en Tester mapp. Vi kommer säkert att ha någon form av resursfiler i projektet, till exempel animationer, teckensnitt, JSON-filer, bilder eller till och med videofiler. Dessa kan go i Resurser mapp. En annan mycket bra idé är att skapa en Konfiguration mapp där vi kommer att lägga alla våra konfigurationsfiler, till exempel appmiljöer, appkonfigurationer, startargument och alla anpassade konfigurationsfiler vi kommer att använda.
Vår mappstruktur på översta nivån (funktionsmapparna är hopfällda i den här skärmdumpen för att spara utrymme) kommer nu att se ut så här:

Innan vi dyker in i att skapa funktioner är det nu ett bra tillfälle att rensa upp våra filer lite. Låt oss börja med att flytta våra .swiftlint konfigurationsfilen till Konfiguration mappen, där den hör hemma. Men om du gör detta kommer vår konfigurationsfil att sluta fungera eftersom platsen har ändrats! För att åtgärda detta måste vi uppdatera SwiftLint-byggskriptet som vi lade till tidigare med rätt filplats:
"${PODS_ROOT}/SwiftLint/swiftlint" --config "$SRCROOT/SwiftUIBlueprint/Config/.swiftlint.yml"Nu kommer vårt byggskript att se ut så här:

Nästa steg är att lägga våra Innehållsvy och SwiftUIBlueprintApp någonstans, så att de inte hänger sig i rotmappen. Detta är bara min personliga preferens. Jag gillar helt enkelt inte att ha massor av filer i rotmappen, eftersom projektnavigatorn snabbt kan bli ful. Vi kunde flytta dessa filer någonstans inom vår Koda mapp eftersom, tekniskt sett, De är inget mer än kod. Men dessa två filer är väldigt unika och speciella för projektet. SwiftUIBlueprintApp, till exempel är vår App-fil vars syfte är att starta Innehållsvy, vilket är vår rotvy som startar hela appen. Så, låt oss behålla dessa filer i Stödjande filer mapp, där vi alltid enkelt kan hitta dem utan att behöva söka för mycket.
Slutligen har vi vår tillgångskatalogfil som heter Tillgångar.xkassetterDen kan användas för många olika ändamål, som att hålla appikonen, alla bilder vi behöver i appen, eller till och med hålla våra appfärger. Men allt eftersom vår app växer kommer fler och fler resurser att läggas till i den här filen, och det kommer att bli omöjligt att hålla reda på hundratals olika resurser i en enda katalogfil.
Det är mycket bättre att hålla var och en av dessa olika resurstyper i en separat fil – en resurskatalog för bilder, en annan för appikonen, kanske en tredje för landflaggikoner (om vi någonsin behöver dem), och så vidare. För tillfället ska vi bara byta namn på den här filen till AppIcon, och vi kommer endast att använda den för att lagra appikonen. När vi behöver bilder eller någon annan resurskatalog skapar vi en ny .xcassets fil för det ändamålet. Eftersom tillgångar är resurser, låt oss skapa en mapp som heter Bilder i vår Resurser mapp och lägg vår AppIcon filen där.
Efter allt detta är detta vår uppdaterade mapp- och filstruktur:

Och så här ser det ut som det är hopfällt:

Ganska snyggt, eller hur? 😉
Nu har vi allt vi behöver, så vi är officiellt redo att faktiskt skriva lite kod och fylla i några av dessa mappar!
Om du vill ladda ner ett projekt som innehåller allt vi har gjort hittills kan du göra det genom att klicka här .
” Bygg din första SwiftUI-app ” är en del av en artikelserie som är utformad för att hjälpa dig att komma igång med iOS-apputveckling.
Om du har några frågor kring någon av ovanstående tankar, dela dem gärna i kommentarsfältet.
Klicka här för att läsa del 1: Projektuppbyggnad
Vi har förberett vår projektstruktur och är nu redo för kodning.
I nästa artikel kommer vi att börja utforma vår inloggningsfunktion, så håll utkik!