Snabb, interaktiv prototypning med Xcode Playgrounds

Vad du ska skapa

Introduktion

Sedan deras introduktion i Xcode 6 tillsammans med Swift, till deras nuvarande iteration i Xcode 7.3.1, har lekplatser kommit långt. Med nya funktioner och bättre stabilitet utvecklas de till ett lönsamt verktyg för snabb prototyper eller snabbt hacka ihop ett bevis på konceptet.

Som utvecklare har du ibland en inspirationsspridning i form av en intressant idé för en app och du vill snabbt koda upp en prototyp som representerar din kärnans kärna. Eller du vill bara verifiera din förståelse för hur en del UIKIT-kod kommer att verka. Om du är som jag vill du hellre undvika besväret och det mentala ansvaret för att skapa ett Xcode-projekt och ha att hantera en mängd olika faktorer, t.ex. enhetstyper och upplösningar, och bygga inställningar. Dessa beslut kan skjutas fram tills du har gjort uppfattning om att kärnidén är värd att driva.

I den här handledningen skapar vi ett kortbaserat minnesspel allihop inom en lekplats. Det är ett vanligt, välkänt spel, så ingen kredit för originalitet där. Spelet består av åtta par identiska kort (så totalt 16 kort) placeras nedåt i ett 4x4-nät.

Spelaren behöver flipa två kort vars ansikten är kort avslöjda och sedan snabbt tillbaka. Målet med spelet är att spelaren ska försöka komma ihåg kortens positioner och avslöja identiska par som sedan tas bort från spelet. Spelet är över när gallret rensas.

Spelet är beröringsbaserat och innehåller enkla visningsanimeringar. Du lär dig hur du kan göra ändringar i din app och se resultatet av dina ändringar live.

1. Komma igång

Släck upp Xcode och välj Ny> Lekplats ... från Xcode s Fil meny. Ge lekplatsen ett namn, till exempel MemoryGameXCPTut, uppsättning Plattform till iOS, och rädda lekplatsen. Jag använder Xcode 7.3.1 för denna handledning.

Hitta vägen runt lekplatsen

Låt oss spendera lite tid att bekanta oss med lekplatsgränssnittet. Känn dig fri att skumma på det här avsnittet om du redan är bekant med lekplatser.

En lekplats kan ha flera sidor, var och en förknippad med sin egen levande visning och sina egna källor / resursmappar. Vi använder inte flera sidor i denna handledning. Lekplatser stödjer markupformatering som låter dig lägga till rik text på en lekplats och länk mellan lekplatsen.

Det första du ser när du skapat en lekplats är lekplatsens källredaktör. Här skriver du kod, som direkt påverkar livevisningen. Ett av sätten att byta ut (det) utseendet på Project Navigator använder genvägen Kommando-0. I Project Navigator, Du kan se två mappar, källor och Medel.

källor

I källor mapp kan du lägga till hjälpkod i en eller flera Swift-filer, t.ex. anpassade klasser, visa kontroller och visningar. Även om huvuddelen av koden som definierar din prototyps logik går där, är det en hjälp i den meningen att den ligger i bakgrunden när du tittar på din app live.

Fördelen med att sätta hjälpkoden i källor mappen är att den automatiskt sammanställs varje gång du ändrar och sparar filen. På så sätt får du snabbare återkoppling i livevisningen från ändringar som gjorts på lekplatsen. Tillbaka på lekplatsen kan du komma åt offentlig egenskaper och metoder som du exponerar i hjälpkoden som påverkar hur din app beter sig.

Medel

Du kan lägga till externa resurser, till exempel bilder, i Medel mapp.

I denna handledning behöver du ofta hoppa mellan en Swift-fil som vi skapar i källor mapp och lekplatsfilen (tekniskt också en Swift-fil, förutom att du inte kommer att referera till den med dess filnamn). Vi använder också av Assistent Editor i handledningen, med att visa den tidslinje, för att se live-utgången sida vid sida med lekplatsen. Eventuella förändringar du gör på lekplatsen återspeglas direkt (väl inom några sekunder) i live-utmatningen. Du kan också snabba med interaktionen med levande vyn och dess användargränssnitt. För att säkerställa att du kan göra allt detta, ta en snabb blick på bilden nedan.

Motsvarar de gröna siffrorna jag har lagt till i figuren:

  1. Den här knappen döljer Assistent Editor så att endast huvudredaktören är synlig.
  2. Denna knapp avslöjar Assistent Editor. De Assistent Editor är synlig till höger om huvudredaktören. Den här redigeraren kan hjälpa till med att visa oss relevanta filer, till exempel motparten av filen i huvudredigeraren.
  3. Från vänster till höger används dessa två knappar för att växla utseendet på Project Navigator och debug-konsolen. I konsolen kan vi bland annat inspektera utdata från utskriftsdeklarationer.
  4. De hoppa baren högst upp i huvudredigeraren kan också användas för att navigera till en viss fil. Genom att klicka på projektnamnet två gånger kommer du tillbaka till lekplatsen. Alternativt kan du också använda Project Navigator.

Ibland, när du tittar på lekplatsen, måste du se till att Assistent Editor visar tidslinje istället för någon annan fil. Nedanstående bild visar hur man gör det här. I Assistent Editor, Välj tidslinje, lekplatsens motstycke i stället för Manuell, vilket låter dig visa vilken fil som helst i Assistent Editor.

När du redigerar en källfil från källor mapp, som dess motsvarighet, Assistent Editor visar gränssnittet till din kod, det vill säga deklarationer och funktionsprototyper utan deras implementeringar. Jag föredrar att gömma Assistent Editor när jag jobbar på en fil i källor mapp och bara avslöja Assistent Editor på lekplatsen för att se den levande utsikten.

För att komma åt de speciella förmågorna på lekplatser måste du importera XCPlayground-modulen.

importera XCPlayground

Du ställer in realtidsbild egenskapen hos nuvarande sida av XCPlaygroundPage motsätta sig ett objekt som överensstämmer med  XCPlaygroundLiveViewable protokoll. Detta kan vara en anpassad klass eller det kan vara en UIView eller UIViewController exempel.

Lägga till filer i källan / resursmappen

Jag har lagt till några bilder vi kan arbeta med i denna handledning. Ladda ner bilderna, extrahera arkivet och lägg till bilderna i Bilder mapp till Medel mapp på lekplatsen i Project Navigator.

Se till att du bara drar bilderna så att varje bildfil finns i Medel mapp, inte i Resurser / Bilder.

Ta bort koden på lekplatsen. Högerklicka på källor mapp och välj Ny fil från menyn. Ange namnet på filen till Game.swift.

2. Skriva hjälparklasser och metoder

Lägg till följande kod till Game.swift. Se till att du sparar filen efter varje kodtillägg.

import UIKit import XCPlayground import GameplayKit // (1) public extension UIImage // (2) allmän bekvämlighet init? (färg: UIColor, storlek: CGSize = CGSize (bredd: 1, höjd: 1)) låt rekt = CGRect ursprunget: .init (CGImage: cgImage) låt cardWidth = CGFloat (120) // (3) låt cardHeight = CGFloat (141) allmän klass Card: UIImageView // (4) public let x: Int public let init (bild: UIImage ?, x: Int, y: Int) self.x = x self.y = y super.init (bild: bild) self.backgroundColor = .grayColor () self.layer.cornerRadius = 10.0 själv .userInteractionEnabled = true krävs public init? (kodare aDecoder: NSCoder) fatalError ("init (kodare :) har inte implementerats")

Jag har lagt till några nummererade kommentarer för att förklara vissa delar av implementeringen:

  1. Dessutom UIKit och XCPlayground, Vi importerar också GamePlayKit. Denna ram innehåller en bekväm metod som hjälper oss att implementera en metod för att slumpmässigt blanda en array.
  2. Denna förlängning på UIImage tillåter oss, med hjälp av UIKit metoder, för att göra bilder med en fast färg av vilken storlek som helst vi vill ha. Vi använder detta för att ställa in den första bakgrundsbilden för spelkorten.
  3. De cardHeight och cardWidth konstanter representerar kortbildstorlekarna baserat på vilka vi kommer att beräkna andra storlekar.
  4. De Kort klass, arv från UIImageView, representerar ett kort. Även om vi satt några egenskaper i Kort klassen är huvudformålet med att skapa den här klassen att hjälpa oss att identifiera och iterera över de undervisningar som motsvarar spelkort i spelet. Korten har också egenskaper x och y att komma ihåg sin position i rutnätet.

3. Visa kontrollenhet

Lägg till följande kod till Game.swift, omedelbart efter föregående kod:

offentliga klass GameController: UIViewController // (1): offentliga variabler så att vi kan manipulera dem på lekplatsen public var padding = CGFloat (20) / * didSet resetGrid () * / public var backImage: UIImage = UIImage färg: .redColor (), storlek: CGSize (bredd: cardWidth, height: cardHeight))! // (2): beräknade egenskaper var viewWidth: CGFloat get return 4 * cardWidth + 5 * padding var viewHeight: CGFloat get return 4 * cardHeight + 5 * padding var shuffledNumbers = [Int] // butiker blandade kortnummer // var firstCard: Card? // uncomment senare public init () super.init (nibName: nil, bunt: nil) preferredContentSize = CGSize (bredd: viewWidth, height: viewHeight) shuffle () setupGrid () // ej kommenterad senare: // let tap = UITapGestureRecognizer (mål: själv, åtgärd: #selector (GameController.handleTap (_ :))) // view.addGestureRecognizer (tryck) krävs public init? (kodare aDecoder: NSCoder) fatalError ("init (kodare :) har inte varit implementerad ") public override func loadView () view = UIView () view.backgroundColor = .blueColor () view.frame = CGRect (x: 0, y: 0, bredd: viewWidth, height: viewHeight) // 3): Använda GameplayKit API för att generera en blandning av arrayen [1, 1, 2, 2, ..., 8, 8] func shuffle () låt siffror = (1 ... 8) .flatMap [$ 0, $ 0] shuffledNumbers = GKRandomSource.sharedRandom (). arrayByShufflingObjectsInArray (nummer) som! [Int] // (4): Konvertera från kortposition till rutnät till index i de blandade kortnumren array func cardNumberAt (x: Int, _y: Int) -> Int assert <= x && x < 4 && 0 <= y && y < 4) return shuffledNumbers[4 * x + y]  // (5): Position of card's center in superview func centerOfCardAt(x: Int, _ y: Int) -> CGPoint assert (0 <= x && x < 4 && 0 <= y && y < 4) let (w, h) = (cardWidth + padding, cardHeight + padding) return CGPoint( x: CGFloat(x) * w + w/2 + padding/2, y: CGFloat(y) * h + h/2 + padding/2)  // (6): setup the subviews func setupGrid()  for i in 0… <4  for j in 0… <4  let n = cardNumberAt(i, j) let card = Card(image: UIImage(named: String(n)), x: i, y: j) card.tag = n card.center = centerOfCardAt(i, j) view.addSubview(card)    // (7): reset grid /* func resetGrid()  view.frame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight) for v in view.subviews  if let card = v as? Card  card.center = centerOfCardAt(card.x, card.y)    */ override public func viewDidAppear(animated: Bool)  for v in view.subviews  if let card = v as? Card  // (8): failable casting UIView.transitionWithView( card, duration: 1.0, options: .TransitionFlipFromLeft, animations:  card.image = self.backImage , completion: nil)    
  1. De två egenskaperna, stoppning och backImage, deklareras offentlig så att vi kan komma åt dem på lekplatsen senare. De representerar det tomma utrymmet kring korten på gallret och bilden som visas på baksidan av respektive kort. Observera att båda egenskaperna har givits initialvärden, som representerar en fyllning på 20 och en solid röd färg för kortets sida utan sida. Du kan ignorera den kommenterade koden för nu.
  2. Vi beräknar den önskade bredden och höjden av vyerna med hjälp av beräknade egenskaper. För att förstå viewWidth beräkning, kom ihåg att det finns fyra kort i varje rad och vi måste också ta hänsyn till vadderingen på varje kort. Samma idé gäller för viewHeight beräkning.
  3. Koden (1 ... 8) .flatMap [$ 0, $ 0] är ett koncist sätt att producera matrisen [1, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8]. Om du inte känner till funktionell programmering kan du också skriva en för-slinga för att generera arrayen. Använda metoder från GamePlayKit ramar, blandar vi numren i arrayen. Siffrorna motsvarar de åtta paren kort. Varje nummer representerar kortbilden med samma namn (till exempel ett värde på 1 i shuffledArray motsvarar 1.png).
  4. Vi skrev en metod som kartlägger platsen för ett kort på 4x4-nätet till dess plats i shuffledNumbers uppsättning av längd 16. Faktorn 4 i den aritmetiska beräkningen speglar det faktum att vi har fyra kort per rad.
  5. Vi har också en metod som räknar ut ett korts position (dess Centrum egendom) i gallret baserat på kortdimensioner och vaddering.
  6. De setupGrid () Metoden heter under visningskontrollörens initialisering. Det lägger ut 4x4 Kort rutnät. Det tilldelar också varje korts identitet baserat på shuffledNumbers array och lagrar den i märka egendom som ärvt från kortets grundklass, UIView. I spellogiken jämför vi märka värden för att räkna ut om två kort matchar eller inte. Detta ganska rudimentära modelleringsschema tjänar tillräckligt bra för våra nuvarande behov.
  7. Det här oanvända kodstycket hjälper oss att omplacera korten om polstret ändras. Kom ihåg att vi förklarade stoppning egendom som en offentlig egendom så vi kan komma åt det på lekplatsen.
  8. Koden i viewDidAppear (_ :) körs omedelbart efter det att vystyrningens synvinkel syns. Vi repeterar genom vyens undervyer och, om undervyn är en instans av Kort klass, (kontrolleras genom som? failable downcasting operatör) kroppen av om-uttalande definierar övergången att utföra. Här kommer vi att ändra bilden som visas på korten, från tecknadbilden som definierar ansiktet på varje kort till den (vanliga) backImage av alla korten. Denna övergång åtföljs av en vänster-höger flip-animering som gör att korten utmärker sig fysiskt. Om du inte är bekant med hur UIView animeringar fungerar, det kan se lite udda ut. Trots att vi lade varje kort animation i följd i en slinga, delas animationerna in i en enda animationstransaktion och körs samtidigt, det vill säga att korten vänder tillsammans.

Revisera lekplatsen och ersätt eventuell text i redigeraren med följande:

importera XCPlayground import UIKit låt gc = GameController () XCPlaygroundPage.currentPage.liveView = gc

Se till att tidslinjen är synlig. Utsiktskontrollerns syn ska vara livlig och visa oss ett 4x4-raster med kort med söta tecknade djur som viker över för att visa oss baksidan av korten. Just nu kan vi inte göra mycket med den här uppfattningen eftersom vi inte har programmerat någon interaktion i det ännu. Men det är definitivt en start.

4. Ändra variabler på lekplatsen

Låt oss nu ändra kortets baksidor från fast rött till en bild, speciellt b.pngMedel mapp. Lägg till följande rad längst ner på lekplatsen.

gc.backImage = UIImage (benämnd: "b")!

Efter en sekund eller två ser du att kortens baksida har ändrats från vanlig röd till en tecknadshand.

Låt oss nu försöka ändra stoppning egendom, som vi tilldelade ett standardvärde på 20 in Game.swift. Utrymmet mellan korten bör öka som ett resultat. Lägg till följande rad längst ner på lekplatsen:

gc.padding = 75

Vänta på levande visning för att uppdatera och se det ... ingenting har ändrats.

5. En kort omväg

För att förstå vad som händer måste du komma ihåg att enheter, som visningskontrollanter och deras associerade visningar, har en komplicerad livscykel. Vi kommer att fokusera på den senare, det vill säga åsikter. Att skapa och uppdatera en vystyrningens vy är en flerdagsprocess. Vid specifika punkter i livscykeln i vyn utfärdas meddelanden till UIViewController, informera om vad som händer. Ännu viktigare kan programmeraren ansluta sig till dessa meddelanden genom att infoga kod för att direktera och anpassa denna process.

De loadView () och viewDidAppear (_ :) metoder är två metoder som vi brukade knyta till livscykeln. Detta ämne är något inblandat och bortom omfattningen av denna diskussion, men det som är viktigt för oss är att koden på lekplatsen, efter uppdragsgivarens uppgift som lekplatsens realtidsbild, utförs en viss tid mellan samtalet till viewWillAppear (_ :) och samtalet till viewDidAppear (_ :). Du kan verifiera detta genom att ändra någon egendom på lekplatsen och lägga till utskriftsdeklarationer i dessa två metoder för att visa värdet på den här egenskapen.

Problemet med värdet av stoppning Att inte ha den förväntade visuella effekten är att vid den tiden har vyn och dess undervisningar redan lagts fram. Tänk på att, när du ändrar koden, spelar lekplatsen från början. I den meningen är denna fråga inte specifik för lekplatser. Även om du utvecklade kod för att köras på simulatorn eller på en fysisk enhet, skulle du ofta behöva skriva ytterligare kod för att säkerställa att ändringen i en egenskaps värde har den önskade effekten på visningen eller innehållet.

Du kanske frågar varför vi kunde ändra värdet på backImage egendom och se resultatet utan att göra något speciellt. Observera att backImage egendom används faktiskt för första gången i viewDidAppear (_ :), vid vilken tidpunkt det redan har tagit upp sitt nya värde.

6. Observera egenskaper och vidta åtgärder

Vårt sätt att hantera denna situation är att övervaka förändringar i värdet av stoppning och ändra storlek / omposition av vyn och undervyer. Lyckligtvis är det lätt att göra med Swifts praktiska egendom observera funktion. Börja med att inte kommentera koden för resetGrid () metod i Game.swift:

// (7): Återställ grid func resetGrid () view.frame = CGRect (x: 0, y: 0, bredd: viewWidth, height: viewHeight) för v i view.subviews om låt kortet = v som? Kort card.center = centerOfCardAt (card.x, card.y)

Denna metod rekomputerar positionen för vyens ram och den för varje Kort objekt baserat på de nya värdena på viewWidth och viewHeight. Minns att dessa egenskaper beräknas baserat på värdet av stoppning, som just har ändrats.

Ändra också koden för stoppning att använda didSet observatör vars kropp, som namnet indikerar, exekveras när vi bestämmer värdet av stoppning:

// (1): offentliga variabler så att vi kan manipulera dem på lekplatsen public var padding = CGFloat (20) didSet resetGrid ()

De resetGrid () Metoden sparkar in och utsikten är uppdaterad för att återspegla det nya avståndet. Du kan verifiera detta på lekplatsen.

Det verkar som om vi kunde fixa saker ganska enkelt. I själva verket när jag bestämde mig för första gången ville jag kunna interagera med stoppning egendom, jag var tvungen att gå tillbaka och göra ändringar i koden i Game.swift. Till exempel var jag tvungen att sammanfatta Kort centrumberäkning i en separat funktion (centerOfCardAt (_: _ :)) för att rent och självständigt (re) beräkna kortens positioner när de behövde läggas ut.

Att skapa beräknade egenskaper för viewWidth och viewHeight hjälpte också. Medan denna typ av omskrivning är något du borde vara förberedd för som ett kompromiss med att inte göra mycket förhandsdesign, kan det minskas med viss förethought och erfarenhet.

7. Game Logic & Touch Interaction

Det är dags att genomföra spelets logik och göra det möjligt för oss att interagera med det genom beröring. Börja med att inte kommentera firstCard fastighetsdeklaration i Spelkontroll klass:

var förstaCard: Kort?

Minns att logiken i spelet innebär att avslöja två kort, en efter en. Denna variabel håller reda på om ett kortflip som spelas av spelaren är det första av de två eller inte.

Lägg till följande metod i botten av Spelkontroll klass, före den avslutande locket

func handleTap (gr: UITapGestureRecognizer) let v = view.hitTest (gr.locationInView (view), withEvent: nil)! om låt kortet = v som? Kort UIView.transitionWithView (kort, varaktighet: 0.5, alternativ: .TransitionFlipFromLeft, animeringar: card.image = UIImage (namngiven: String (card.tag))) // efterföljande hanteringshandlare: _ i card.userInteractionEnabled = falskt om låt pCard = self.firstCard om pCard.tag == card.tag UIView.animateWithDuration (0.5, animeringar: card.alpha = 0.0, slutförd: _ i card.removeFromSuperview ()) UIView.animateWithDuration (0.5, animeringar: pCard.alpha = 0.0, slutförande: _ i pCard.removeFromSuperview ()) else UIView.transitionWithView (kort, duration: 0.5, alternativ: .TransitionFlipFromLeft, animeringar: card.image = self.backImage) _ i card.userInteractionEnabled = true UIView.transitionWithView (pCard, duration: 0.5, alternativ: .TransitionFlipFromLeft, animeringar: pCard.image = self.backImage) _ i pCard.userInteractionEnabled = true  self.firstCard = nil else self.firstCard = card

Det är en lång metod. Det beror på att det paketerar all nödvändig beröringshantering, spellogik och associerade animeringar i en metod. Låt oss se hur den här metoden fungerar:

  • För det första finns det en check för att säkerställa att användaren faktiskt rörde en Kort exempel. Detta är detsamma som? konstruera som vi använde tidigare.
  • Om användaren rörde på a Kort till exempel vi vänder det över med en animering som liknar den som vi implementerade tidigare. Den enda nya aspekten är att vi använder färdigställningshanteraren, som körs efter att animeringen slutförts, för att tillfälligt inaktivera beröringsinteraktioner för det aktuella kortet genom att ställa in userInteractionEnabled kortets egendom. Detta förhindrar att spelaren bläddrar över samma kort. Notera _ i konstruktion som används flera gånger i denna metod. Det här är bara att säga att vi vill ignorera Bool parameter som slutföringshanteraren tar.
  • Vi utför kod baserat på om firstCard har fått ett icke-nollvärde med valfri bindning, Swifts bekanta om låt konstruera.
  • Om firstCard är icke-noll, då var detta det andra kortet i sekvensen som spelaren vände över. Vi behöver nu jämföra ansiktet på detta kort med den föregående (genom att jämföra märka värden) för att se om vi har en match eller inte. Om vi ​​gjorde, animerar vi korten som bleknar (genom att ställa in deras alfa till 0). Vi tar också bort dessa kort från vyn. Om taggarna inte är lika, vilket betyder att korten inte stämmer överens, vänder vi dem bara neråt och nedåt userInteractionEnabled till Sann så att användaren kan välja dem igen.
  • Baserat på nuvärdet av firstCard, vi ställde det till heller noll eller till nuvarande kort. Så här byter du kodens beteende mellan två på varandra följande berör.

Slutligen, kommentera följande två uttalanden i Spelkontrolls initialiserare som lägger till en knappbehållare igen. När knapptrycksgenkännaren upptäcker en kran, handleTap () Metoden åberopas:

låt tryck = UITapGestureRecognizer (mål: self, action: #selector (GameController.handleTap (_ :))) view.addGestureRecognizer (tryck)

Gå tillbaka till lekplatsens tidslinje och spela minnesspelet. Känn dig fri att minska den stora stoppning vi tilldelade lite tidigare.

Koden i handleTap (_ :) är ganska mycket den ojämförliga versionen av det jag skrev första gången. Man kan hävda invändningen att det som en enda metod gör det för mycket. Eller att koden inte är objektorienterad nog och att kortets flikande logik och animationer ska vara snyggt abstraherade i metoder för Kort klass. Medan dessa invändningar inte är ogiltiga i sig, kom ihåg att snabb prototyper är fokus för denna handledning och eftersom vi inte förutsåg något behov av att interagera med den här delen av koden på lekplatsen, hade vi råd att vara lite mer "hack-ish".

När vi har någonting jobbar och vi bestämmer att vi vill fortsätta idén ytterligare, skulle vi verkligen behöva överväga att koda refactoring. Med andra ord, först gör det att fungera, gör det snabbt / elegant / vackert / ...

8. Tryck på Hantering på lekplatsen

Medan huvuddelen av handledningen nu är över, som en intressant sida, vill jag visa dig hur vi kan skriva beredskapskod direkt på lekplatsen. Vi lägger först till en metod till Spelkontroll klass som gör att vi kan kika på kortens ansikten. Lägg till följande kod till Spelkontroll klass, omedelbart efter handleTap (_ :) metod:

public func quickPeek () för v i view.subviews om låt kortet = v som? Kort card.userInteractionEnabled = false UIView.transitionWithView (kort, duration: 1.0, alternativ: .TransitionFlipFromLeft, animeringar: card.image = UIImage (namngiven: String (card.tag))) _ i UIView.transitionWithView , duration: 1.0, alternativ: .TransitionFlipFromLeft, animeringar: card.image = self.backImage) _ i card.userInteractionEnabled = true

Antag att vi vill ha möjlighet att aktivera eller avaktivera denna "snabba titt" -funktion från lekplatsen. Ett sätt att göra detta skulle vara att skapa en allmänhet Bool egendom i Spelkontroll klass som vi kunde sätta på lekplatsen. Och vi måste naturligtvis skriva en gesthandlare i Spelkontroll klass, aktiverad av en annan gest, som skulle åberopa snabbtitt().

Ett annat sätt är att skriva handbokskoden direkt på lekplatsen. En fördel med att göra det på så sätt är att vi kunde införliva vissa anpassade koden förutom att ringa snabbtitt(). Så här gör vi nästa. Lägg till följande kod längst ner på lekplatsen:

klassen LPGR static var counter = 0 @objc static func longPressed (lp: UILongPressGestureRecognizer) om lp.state == .Began gc.quickPeek () counter + = 1 print ("Du kikade \ .) Låt longPress = UILongPressGestureRecognizer (mål: LPGR.self, action: #selector (LPGR.longPressed)) longPress.minimumPressDuration = 2.0 gc.view.addGestureRecognizer (longPress)

För att aktivera funktionen Quick Look, använder vi en lång tryckning, det vill säga att spelaren håller fingret på skärmen under en viss tid. Vi använder två sekunder som tröskeln.

För att hantera gesten skapar vi en klass, LPGR (förkortning med lång tryckbegränsare förkortad), med a statisk variabel egenskap, disken, att hålla reda på hur många gånger vi kikade, och a statisk metod longPressed (_ :) att hantera gesten.

Genom att använda statisk kvalifierare kan vi undvika att skapa en LPGR Exempel på att de enheter som deklareras statiska är associerade med LPGR typ (klass) snarare än med en viss förekomst.

Bortsett från det finns det ingen särskild fördel för detta tillvägagångssätt. Av komplicerade skäl måste vi markera metoden som @objc för att hålla kompilatorn glad. Notera användningen av LPGR.self att hänvisa till typen av objektet. Observera också att i handbehandlaren kontrollerar vi om stat av gesten är .började. Detta beror på att den långa tryckfasen är kontinuerlig, det vill säga att handlaren skulle utföras upprepade gånger så länge som användaren höll fingret på skärmen. Eftersom vi bara vill att koden ska utföras en gång per fingerpress gör vi det när gesten först identifieras.

Den inkrementala räknaren är den anpassade koden som vi introducerade, som inte är beroende av funktionalitet som tillhandahålls av Spelkontroll klass. Du kan se produktionen av skriva ut(_:) funktion (efter att ha tittat ett par gånger) i konsolen längst ner.

Slutsats

Förhoppningsvis har denna handledning visat ett intressant exempel på snabb, interaktiv prototypning i Xcode-lekplatser. Bortsett från anledningen till att du använde lekplatser som jag nämnde tidigare kan du tänka på andra scenarier där de kan vara användbara. Till exempel:

  • demonstrera prototypfunktionalitet till klienter och låta dem välja alternativ och göra anpassningar med levande återkoppling och utan att behöva gräva in i de käftena detaljerna i koden.
  • utveckla simuleringar, som för fysik, där eleverna kan spela med några parametervärden och observera hur simuleringen påverkas. Faktum är att Apple har släppt en imponerande lekplats som visar deras interaktivitet och införlivandet av fysik via UIDynamics API. Jag uppmanar dig att kolla in det.

När du använder lekplatser för demonstration / undervisningssyfte som dessa, kommer du förmodligen att vilja göra liberal användning av lekplatser för markeringskapacitet för rik text och navigering.

Xcode-teamet verkar engagera sig för att förbättra lekplatser när nya versioner av IDE rullas ut. Den nya nyheterna är att Xcode 8, för närvarande i beta, kommer att innehålla lekplatser för iPad. Men uppenbarligen är lekplatser inte avsett att ersätta den fullständiga blåsade Xcode IDE och behovet av att testa på aktuella enheter när man utvecklar en komplett, funktionell app. I slutändan är de bara ett verktyg som ska användas när det är meningslöst men en väldigt användbar.