Appen Swift Playgrounds för iPad har alltid varit lite sliten mellan två vitt skilda användningsområden. Å ena sidan byggdes den helt klart med ett primärt fokus på utbildning och att vara ett bra verktyg för nybörjare – men å andra sidan fungerar den också som det enda sättet för professionella utvecklare att köra Swift-kod lokalt på sin iPad.

Interessant nog försätter det Swift Playgrounds i en väldigt likartad position som iPad i sin helhet – i och med att den både måste tillgodose avslappnade och enkla användningsfall, men också fungera som ett kapabelt verktyg för mer avancerade, särskilt med tanke på den ökande populariteten för iPad Pro som en komplett datorplattform.

Denna vecka ska vi ta en titt på hur väl den nya 3.0-versionen av Swift Playgrounds klarar av den balansen mellan enkelhet och kraft, och hur några av de nya funktionerna verkligen förbättrar de sätt på vilka det kan användas som ett mycket portabelt, avancerat Swift-utvecklingsverktyg.

Instabug: Lös buggar, krascher och andra problem mycket snabbare med hjälp av de detaljerade stack-traces, nätverksloggar och UI-händelser som Instabug automatiskt bifogar till varje felrapport. Används både av mig och tusentals iOS-utvecklingsteam runt om i världen. Prova det gratis och integrera det med bara en enda kodrad.

Arbete, lek och utbildning

Det tar inte lång tid att inse att huvudsyftet med Swift Playgrounds är att fungera som ett verktyg för studenter, lärare och för personer som vill börja lära sig att koda. Direkt efter att ha öppnat appen presenterar den tydligt olika kodningslektioner och inlärningsutmaningar – och allt från det språk som används för menyalternativ och kommandon, till appens versionsanteckningar på App Store, har ett tydligt utbildningsfokus.

När du väl har öppnat en tom lekplats och börjat koda har appens faktiska möjligheter alltid varit ganska imponerande – från hur den ger full tillgång till iOS SDK och Foundation, till hur den låter oss rendera vyer och view controllers nativt med hjälp av PlaygroundPage.current.liveView, till kompilatorns snabbhet – särskilt på de senaste iPad Pro-modellerna.

Version 3.0 tillför också några mycket välkomna förbättringar till mixen. Till att börja med har kompilatorn nu uppdaterats till Swift 5.0-versionen, och den övergripande stabiliteten hos editorn och dess sätt att interagera med kompilatorn har också förbättrats. När en krasch eller ett körtidsfel inträffar visar appen inte längre en enkel varningsvy som säger att något gick fel, utan presenterar istället fylliga felmeddelanden bredvid den kodrad som orsakade felet – och kompileringsfel visas nu i en ”Issues”-lista, liknande den som finns i Xcode.

Moduler enkelt gjorda

Den kanske största förbättringen för utvecklare som vill använda Swift Playgrounds som ett riktigt utvecklingsverktyg, är det tillagda stödet för moduler som innehåller flera källfiler. Swift-moduler är i huvudsak den ”rena Swift”-ekvivalenten till ett bibliotek eller ramverk, och det sätt på vilket de har integrerats i Playgrounds-appen är helt enkelt fantastiskt.

En ny dokumentikon finns nu i det övre vänstra hörnet av redigeringsverktyget – och genom att trycka på den öppnas en popover-fönsterruta som gör det möjligt för oss att bläddra i, och ändra, den aktuella playgrounds källfiler och moduler. Både nya filer och nya moduler kan läggas till med några få tryckningar, och varje ny källfil öppnas automatiskt som en ny flik i redigeraren. Det är smidigt, snabbt och gör det trivialt att börja dela upp ett större kodstycke i separata moduler. Varje modul importeras också automatiskt till lekplatsen, samtidigt som det fortfarande krävs explicit import mellan moduler.

Växla ovanstående med hur många steg det tar att lägga till ett nytt Swift-ramverk i Xcode.

Modularisering kan ofta vara nyckeln för att göra det lättare att underhålla ett projekt – särskilt när mängden funktioner och källkodsfiler växer. Genom att dela upp saker och ting i separata moduler, var och en med sitt eget ansvar och sin egen domän, kan vi både säkerställa en rimlig grad av separering av problem – och även enkelt identifiera arkitektoniska problem, till exempel när två olika delar av koden är för starkt kopplade, eller när en vy gör för många antaganden om de data som den renderar (eftersom det för att få tillgång till sådan information nu skulle krävas att man importerar en annan modul).

Moduler gör det också möjligt för oss att använda oss av internal åtkomstkontrollnivån och göra typer och funktioner som endast är avsedda för internt bruk inom en modul otillgängliga utanför den modulen. Eftersom internal är standardåtkomstnivån i Swift innebär det också att vi uttryckligen måste markera de typer och funktioner som vi vill sälja som en del av vår moduls offentliga API som public. Även om vissa utvecklare kanske anser att detta är lite av en ”syssla”, så tvingar det oss på sätt och vis att ta för vana att utforma tydligare och mer väldefinierade API:er.

Xcode-kompatibilitet

Och även om Swift Playgrounds nu har fått en hel del kraft och flera nya funktioner som gör det till ett mycket mer kapabelt utvecklingsverktyg, så är det långt ifrån en fullständig Xcode-ersättning för de flesta användningsfall – och försöker inte heller att vara det. Det finns goda skäl till att det kallas ”Swift Playgrounds” och inte ”Xcode för iPad” (även om vi förhoppningsvis kommer att få se det sistnämnda någon gång också). Det är ett verktyg för att leka med idéer, för lätt kodning på språng och för att bygga prototyper och isolerade moduler – snarare än att vara ett komplett IDE med stöd för komplexa projekt.

Så eftersom Swift Playgrounds – för de flesta utvecklare – troligen kommer att fungera som ett komplement till Xcode, snarare än som en ersättare, hur enkelt är det då att flytta projekt och kod mellan de två? Svaret är tyvärr, för det mesta, inte så enkelt. Även om appar som Working Copy (disclaimer: tidigare sponsor) och verktyg som Shapeshift (disclaimer: skrivet av mig) gör det ganska trivialt att flytta källkod mellan Mac och iPad – finns det tyvärr väldigt lite direkt kompatibilitet mellan Swift Playgrounds och Xcode.

För det första använder de olika filformat. Xcode använder fortfarande .xcodeproj buntformatet som det har använt i flera år, och även om Xcode-skapade .playground-filer kan öppnas på iPad, använder de playgrounds som skapas i själva appen Playgrounds det iPad-unika .playgroundbook-formatet.

Det enda som Xcode 10 kan göra med Swift Playgrounds-böcker är att visa en ikon – förhoppningsvis kommer det att ändras till årets WWDC.

Detta innebär att även om vi nu enkelt kan skapa moduler och filhierarkier på iPad, så måste vi, när vi väl vill flytta vår kod tillbaka till Mac (vilket vi måste göra någon gång om vi bygger en app), omorganisera koden till något som är Xcode-kompatibelt – till exempel genom att lägga till filer till Xcode-projekt och skapa ramverk för våra moduler.

Förhoppningsvis kommer framtida versioner av både Swift Playgrounds och Xcode att medföra ett mer normaliserat projektformat (hur fantastiskt skulle det inte vara om alla Apples utvecklarverktyg använde Swift Package Manager och dess Package.swift manifest för att definiera projekt?), vilket skulle göra det mycket enklare att överföra hela projekt till och från iPad – vilket skulle kunna öppna upp för ännu mer avancerade användningsområden och göra det möjligt för oss att redigera hela appar när vi är på språng.

Möjliggöra testbarhet

En annan aspekt av Swift-utveckling som saknas i Swift Playgrounds på iPad är stöd för enhets- och UI-tester. Inte nog med att appen inte erbjuder något slags inbyggt sätt att köra tester, den levereras inte ens med det XCTest ramverk som de flesta Swift-utvecklare förlitar sig på när det gäller någon form av automatiserad testning.

Så betyder det att det är helt uteslutet att skriva tester på iPad? Tack och lov inte. Trots alla sina begränsningar innehåller Swift Playgrounds fortfarande den kompletta Swift-kompilatorn, och eftersom XCTest – i slutändan – inte är något annat än kod, kan vi ganska enkelt återimplementera några av de centrala aspekterna av den direkt i själva Swift Playgrounds!

(Det skulle inte vara en Swift by Sundell-artikel utan några kodprover, eller hur? 😉)

Låt oss börja med att definiera en ”trimmad” version av XCTestCase-klassen, men som ett protokoll istället. Vi kommer att kräva att alla testfall har en tom initialiserare (så att vi dynamiskt kan skapa instanser), metoder för att sätta upp och riva ner varje testkörning, samt en Swift Package Manager-inspirerad allTests-egenskap för att ge vår testkörare tillgång till varje testmetod som vi vill köra:

protocol XCTestCase { init() func setUp() func tearDown() static var allTests: { get }}

Vidare kunde vi ha implementerat XCTestCase som en konkret klass istället, och använda oss av Objective-C-körtiden för att identifiera testmetoder – precis som XCTest gör det på Apple-plattformar – men det skulle kräva att vi markerar varje metod med @objc, och det skulle också göra vår kod mindre portabel om vi vill distribuera den på plattformar som Linux.

Nästan, låt oss utöka vårt XCTestCase-protokoll med en metod som låter oss köra ett givet testfall (genom att räkna upp alla dess metoder och anropa var och en av dem), samt tomma standardimplementationer av setUp och tearDown:

Med ovanstående på plats kan vi nu definiera testfall, men vi behöver också ett sätt att utföra verifieringar och påståenden när vi skriver vår faktiska testlogik. För att underlätta detta börjar vi med att implementera funktionen XCTFail, som låter oss misslyckas med ett test om ett visst villkor inte uppfylls. Vi ger den ett valfritt reason-argument, och vi registrerar automatiskt namnet på testfunktionen där den anropades, samt radnumret – så här:

Med hjälp av ovanstående kan vi nu implementera XCTAssertEqual-funktionen, som låter oss bekräfta att resultatet av en operation visade sig vara likvärdigt med det resultat vi förväntade oss:

Det är egentligen allt vi behöver för att börja skriva några grundläggande tester. Här är till exempel hur vi nu skulle kunna verifiera en att en Playlist typ korrekt håller reda på sina låtar, samt se till att dess serialiseringskod fungerar som förväntat:

För att köra våra ovanstående tester anropar vi helt enkelt run() på testfallets typ:

try PlaylistTests.run()

Det kanske inte är en fullständig omimplementering av XCTest, och vi skulle behöva fortsätta att lägga till varje assertion-funktion och testfunktion som vi behöver manuellt – men det visar att många olika avancerade utvecklingsfunktioner är tekniskt möjliga på iPad – ibland behöver vi bara lite tid och kreativitet för att förverkliga dem.

Support Swift by Sundell genom att kolla in denna sponsor:

Instabug: Lös buggar, krascher och andra problem mycket snabbare med hjälp av de detaljerade stack-traces, nätverksloggar och UI-händelser som Instabug automatiskt bifogar till varje felrapport. Används både av mig och tusentals iOS-utvecklingsteam runt om i världen. Prova den gratis och integrera den med bara en enda kodrad.

Slutsats

Versionen 3.0 av Swift Playgrounds för iPad är en fantastisk uppdatering av en redan fantastisk app – som lägger till kraftfulla nya funktioner och gör kärnutvecklingsfunktioner, som felrapportering, mycket mer kapabla – samtidigt som den behåller sitt fokus på användarvänlighet och utbildningsinnehåll.

Swift 5, moduler, redigering med flikar och källfilshantering är alla fantastiska funktioner som gör den här versionen av Swift Playgrounds till den mest kapabla hittills – och det är ett stort steg mot att göra det möjligt att utföra många fler Swift-utvecklingsuppgifter på iPad. Precis som när det gäller att arbeta på iPad i allmänhet kräver användningen av Swift Playgrounds ibland lite extra tålamod och lösningar, men resultatet kan ofta ge en kraftfull utvecklingsmiljö på en mycket bärbar enhet.

Swift Playgrounds är fortfarande inte en ”Xcode-dödare”, och kommer förmodligen aldrig att bli det, men det är okej. Även om bättre interoperabilitet med Xcode (särskilt när det gäller filformat och projektstruktur) och mer avancerade redigeringsfunktioner (som verktyg för refaktorisering och textersättning) definitivt skulle vara mer än välkomna, så länge jag snabbt kan skriva Swift-kod på språng är jag mer än nöjd – åtminstone i väntan på att ”Xcode för iPad” ska anlända.