Projekt Zufall 9: Zufallszahlen

Wenn Sie einen echten, ungezinkten Würfel in die Hand nehmen und ihn auf einen Tisch werfen, dann erhalten Sie in der Regel ein zufälliges Würfelergebnis zwischen 1 und 6. Das funktioniert immer dann, wenn Sie durch Ihren Wurf so viel Komplexität in das physikalische System aus Hand, Würfel und Tisch bringen, dass es sich einer Berechnung entzieht, zum Beispiel indem Sie dem Würfel mit Ihrem Wurf noch eine zusätzliche Drehung verpassen.

Sobald es aber berechenbar wird, etwa weil Sie den Würfel einfach auf den Tisch legen oder einen gezinkten Würfel verwenden, dann ist das Ergebnis nicht mehr zufällig, sondern eben berechenbar. Zufallszahlen, die in einem Computer erzeugt werden, sind aber nun leider immer berechenbar, denn sie sind ja berechnet – vielleicht mit sehr guten Algorithmen, aber berechnet sind sie doch. Daher sind von einem Computer erstellte Zufallszahlen immer nur Pseudozufallszahlen.

Bei Pseudozufallszahlen kommt es darum sehr auf die Qualität des Algorithmus an. Die verwendeten Algorithmen sind denen für kryptografische Verfahren nicht unähnlich, und gute Kryptographie gehört mit zu dem kompliziertesten, was Menschen programmieren können. Hier ist alt und abgehangen oft besser als neu und dreimal schlauer.

Von den vielen Alternativen, die Ihnen in Swift zur Verfügung stehen, empfehle ich Ihnen zwei: Eine für Ganzzahlen – die benötigen wir für’s Würfeln – und eine für Gleitkommazahlen. Beides sind C-Funktionen, die aus OS X Systembibliotheken stammen, eben alt und abgehangen, aber problemlos in Swift verwendbar.

Ein zufälliger Integer

Für eine zufällige Integerzahl verwenden Sie bitte die Funktion arc4random_uniform(N). Sie gibt eine zufällige Zahl zwischen 0 und N-1 zurück. N ist hierbei, ebenso wie der Rückgabewert, vom Typ UInt32. Anders als drand48 (siehe unten) benötigt arc4random_uniform(N) keinen Startwert (Seed), Sie können die Funktion also direkt benutzen.

Beispielsweise gibt arc4random_uniform(6) eine Zahl zwischen 0 und 5 zurück.

Angepasst auf unseren Würfelwurf ergibt sich folgende Codezeile:

let wurfErgebnis = arc4random_uniform(6) + 1

Die Konstante wurfErgebnis wird hierbei von Swift als UInt32 inferiert.

Ein zufälliger Double

Die Funktion drand48() gibt einen Double zwischen [0.0, 1.0) zurück. Die mathematische Schreibweise mit einer eckigen und einer runden Klammer um das Intervall bedeutet, dass 0.0 zurückgegeben werden kann, 1.0 aber nicht (nur Zahlen sehr sehr nah an 1).

Diese Funkton benötigt aber einen Seed, einen Startwert, bevor sie verwendet werden kann. Üblicherweise verwendet man dafür die aktuelle Systemzeit, so dass der Seed bei jedem Programmstart unterschiedlich ist. Die C-Funktion time(..) gibt, wenn der Parmeter nil ist (sie also praktisch ohne Parameter aufgerufen wird), die Anzahl der Sekunden seit dem 1. Januar 1970 um 0 Uhr zurück. Und der Seed für drand48() wird mit Hilfe der Funktion srand48(..) einmalig gesetzt, so dass der Aufruf insgesamt lautet:

srand48(time(nil))
let doubleWurfErgebnis = drand48()

Beitragsbild: Ricky Jay dice in exhibit von Susan Gerbic in abgewandelter Form (CC BY SA 3.0)

Swiftkurs Plus mit PDF und ePUB Versionen

Einige von Ihnen hatten mir mitgeteilt, dass sie die Inhalte von Swiftkurs.de gerne auch als PDF oder ePUB Version hätten, um sie auch ohne Internet, z.B. auf dem iPad lesen zu können.

Über Swiftkurs Plus möchte ich Ihnen diese und im Laufe der Zeit auch noch weitere Inhalte zur Verfügung stellen. Die Inhalte von Swiftkurs Plus kosten nicht viel, aber ein wenig schon.

Aktuell stelle ich Ihnen dort die PDF und ePUB Versionen der beiden ersten Kapitel des Swift Programmierkurses zur Verfügung, dies wird sich mit weiteren Kapiteln fortsetzen, es kommen aber auch noch mehr Inhalte dazu, zum Beispiel zu den Projekten (incl. der Sourcen).

Die Kapitelpreise sind so gestaltet, dass sie sich für ein gesamtes Buch im unteren Bereich eines durchschnittlichen Lehrbuchs bewegen. Und wenn später beispielsweise der vollständige Swift Programmierkurs veröffentlicht wird, dann werde ich das, was Sie für einzelne Kapitel bezahlt haben, selbstvertändlich berücksichtigen.

Alle Swiftkurs Plus Inhalte sind DRM-frei, damit Sie sie lesen können, wie und wo immer Sie möchten.

Folgendes ist mir sehr wichtig:

Alles was sie brauchen, um auf Swiftkurs.de die Sprache Swift zu lernen steht Ihnen jetzt und auch weiterhin kostenlos über das Blog zur Verfügung. Ich freue mich über Sie als Leser des Blogs sehr und tue mein möglichstes, Ihnen den Spaß am Programmieren zu vermitteln, egal ob Sie etwas kaufen oder nicht.

Wenn Sie den Betrieb und den Aufwand, den ich jede Woche in Swiftkurs.de stecke unterstützen möchten, freue ich mich allerdings auch darüber, wenn Sie Swiftkurs Plus nutzen möchten.

Bitte teilen Sie mir gern mit, was Sie von Swiftkurs Plus halten, was Sie sich dort noch wünschen, oder ob Sie finden, dass Teile oder alles davon doch besser kostenlos sein sollten. An Ihrer Meinung hierzu bin ich sehr interessiert.

Projekt Zufall 8: Den Text des Labels ändern

Um den Wurf zum Beispiel eines Würfels durch diese Applikation zu simulieren, müssen wir das Ergebnis dieses Wurfs als Text ausgeben können. Um eine Textausgabe zu realisieren, haben Sie zunächst ein Label auf der GUI platziert, positioniert und schließlich als Outlet mit dem Code verbunden.

Dieses Outlet ist eine Variable vom Typ NSTextField (durch das Ausrufungszeichen die implizit unwrapped optionale Variante davon, aber das ist hier nicht von Bedeutung).

Ich werde Ihnen gleich zeigen, wie sie den Text eines NSTextField ändern können. Aber mal angenommen, Sie wollten das selbst herausfinden: Was Sie mit einem NSTextField so ganz allgemein anstellen können und eben ganz speziell, wie Sie den Text ändern können.

Positionieren Sie hierfür den Textcursor im Editorfenster in der Deklarationszeile des Outlets auf dem Klassennamen NSTextField! (bei mir in lila Schrift). Dann wählen Sie rechts – wenn das nicht bereits geschehen ist – den Quick Help inspector aus. Nun erhalten Sie eine kurze Schnellhilfe zum NSTextField (Abbildung 8.1).

Abbildung 8.1: Schnellhilfe zum NSTextField
Abbildung 8.1: Schnellhilfe zum NSTextField

Leider in Englisch, aber daran kommen Sie in dieser Xcode Hilfe nicht vorbei, finden Sie eine kurze Beschreibung, was ein NSTextField ist. Viel wichtiger aber ist die Reference: Klicken Sie auf NSTextField Class Reference, dann öffnet sich die Xcode Dokumentation für die Klasse NSTextField in einem separaten Fenster.

Hier finden Sie praktisch alles, was Sie mit NSTextFields machen können: Im Inhaltsverzeichnis auf der linken Seite können Sie über Tasks zu Ihrem Thema finden, oder sich einen Überblick verschaffen, zum Beispiel sehen Sie hier, wie Sie die Textfarbe ändern oder Selektionen handhaben. Eines finden Sie unter den Tasks aber nicht, nämlich wie Sie den Text ändern können.

Ganz am Anfang der Beschreibung, in der Overview, erfahren wir warum: Ein NSTextField ist abgeleitet von NSControl (so wie unser ViewController von NSViewController abgeleitet ist) und erbt von dort viele seiner Methoden und Eigenschaften, eben solche, die nicht nur für Textfelder gelten, sondern für Controls allgemein. Eine dieser Methoden ist die zum Ändern des Texts, oder genauer: Zum Ändern des String-Wertes (engl.: string value) des Controls. Netterweise steht gleich darauf auch, wie diese Methode heißt, nämlich setStringValue: (der Doppelpunkt zeigt an, dass diese Methode einen Parameter hat, nämlich den Wert, der gesetzt werden soll). Klicken Sie auf den Methodennamen, dann kommen Sie zur Beschreibung dieser Methode:

setStringValue, steht dort, setzt den Wert des empfangenden Objekts auf einen String. Und dort steht auch, dass stringValue unter Swift eine Variable vom Typ String ist. Wenn Sie unter Swift eine Variable ändern, dann nicht über ihren sogenannten Setter, die Methode setIrgendeineVariable, sondern direkt durch Zuweisung an die Variable irgendeineVariable selbst.

Jetzt also wissen wir’s: Um den Text eines Labels zu ändern, müssen wir dessen Variable stringValue einen neuen Wert zuweisen.

Sie müssen sich manchmal also schon ein bisschen durchfummeln und Dinge ausprobieren, bis sie gefunden haben, was Sie suchen. Am Anfang ist das sicher noch sehr schwierig, aber jetzt wissen Sie schon einmal so ungefähr, wie Sie die Dokumentation benutzen können.

Dies neu gewonnene Wissen setzen wir nun an zwei Stellen im Code ein: Beim Applikationsstart setzen wir den Text auf „Die Applikation ist gestartet.“ und nach einem Klick des Buttons auf „Der Button wurde geklickt.“ Nicht sehr einfallsreich, aber ein guter Test, ob wir alles richtig gemacht haben.

Der Quellcode (erneut ohne die anfänglichen Kommentare) der Klasse ViewController sieht nun so aus:

import Cocoa

class ViewController: NSViewController {

  @IBOutlet weak var resultLabel: NSTextField!

  override func viewDidLoad() {

    super.viewDidLoad()

    resultLabel.stringValue = "Die Applikation ist gestartet."
  }

  @IBAction func neuWürfelnButtonClicked(sender: NSButton) {

    resultLabel.stringValue = "Der Button wurde geklickt."
  }

}

Das super.viewDidLoad() haben wir in der Funktion viewDidLoad behalten, da es uns mögliche Grundfunktionalität bereitstellt, die viewDidLoad bebenötigt. Ansonsten sind zwei Zeilen hinzugekommen, die jeweils den Labeltext ändern, indem sie die Variable stringValue unseres Labels resultLabel auf einen neuen Wert setzen:

Einmal innerhalb von viewDidLoad, das aufgerufen wird, unmittelbar nachdem die Applikation gestartet ist, und einmal innerhalb von neuWürfelnButtonClicked:, das durch einen Buttonklick aufgerufen wird. Wenn Sie nun die Applikation starten und dann den Button klicken, sollten sie also beide Texte zu sehen bekommen. Bitte probieren Sie das einmal aus.

Beitragsbild: Ricky Jay dice in exhibit von Susan Gerbic in abgewandelter Form (CC BY SA 3.0)

Projekt Zufall 7: Die Controls mit dem Code verbinden

Um die Controls mit dem Code zu verbinden sollten wir Controls und Code gleichzeitig auf dem Bildschirm haben, also wechseln Sie (rechts oben) bitte vom Standard editor in den Assistant editor.

Im linken Editor belassen Sie bitte den Code der Klasse ViewController, und rechts wählen Sie Main.storyboard aus, indem Sie sich über Manual bis dorthin durchhangeln (Abb. 7.1)

Abbildung 7.1: Der Pfad zum Storyboard
Abbildung 7.1: Der Pfad zum Storyboard

Zuerst erstellen wir das Outlet des Labels. Dazu wählen Sie bitte im Storyboard das Label aus (mit einfachem Linksclick) und dann machen Sie auf dieses Label einen Rechtsclick, halten die Maustaste gedrückt, fahren mit dem Mauspfeil in den Quellcode (Abb. 7.2) und lassen unterhalb der Klassendeklaration die Maustaste wieder los. Dort erscheint eine Auswahl (Abb. 7.3).

Abbildung 7.2: Über dem Quellcode
Abbildung 7.2: Über dem Quellcode
Abbildung 7.3: Auswahl Outlet oder Action
Abbildung 7.3: Auswahl Outlet oder Action

Die Connection ist auf Outlet vorbelegt, das passt also. Als Name wählen Sie bitte „resultLabel“, so soll unser Label heißen. Der Type passt ebenfalls, denn unser Label ist ja von Typ NSTextField, und Storage Weak bedeutet, dass die Variable aus dem Speicher gelöscht werden darf, wenn die Klasse aus dem Speicher gelöscht wurde, dass ist ebenfalls okay. Mit einem Klick auf Connect wird die folgende Zeile in den Code geschrieben:

@IBOutlet weak var resultLabel: NSTextField!

Das @IBOutlet ist ein Hinweis für Xcode, dass hier ein Outlet steht, weak hatten wir eben schon, der Rest ist eine normale Variablendeklaration. Im Xcode Editor befindet sich außerdem noch ein ausgefüllter Punkt links neben dieser Zeile. Der signalisiert, dass das Outlet mit einem Control auf dem Storyboard verbunden ist. Wäre es das nicht, dann wäre der Punkt ein unausgefüllter Kreis.

Diesem Punkt kommen wir noch genauer auf die Schliche, indem wir nun die Action deklarieren. Eine Action ist eine Methode, eine Funktion, die aufgerufen wird, wenn auf einem Control eine Aktion ausgeführt wird. Und wir könnten diese Funktion, genau wie das Outlet, durch ein Drag & Drop vom Control hinein in den Code erstellen lassen.
Um ihnen aber eine Alternative zu beschreiben (die genauso auch beim Outlet funktioniert), gehen wir diesmal anders vor:

Immer noch im Assistant editor wie eben, schreiben wir jetzt die Action-Methode von Hand in den Code (unterhalb von viewDidLoad):

@IBAction func neuWürfelnButtonClicked(sender: NSButton) {
        
}

Das @IBAction ist hier, analog zum @IBOutlet oben, der Hinweis an Xcode, dass es sich hierbei um eine Action-Methode handelt – darum erstellt Xcode auch sofort links neben diese Deklaration einen unausgefüllten Kreis: Eine noch nicht verbundene Action. Der Rest ist geradeheraus: Das Schlüsselwort func deklariert eine Funktion mit dem Namen neuWürfelnButtonClicked:, die einen Parameter namens sender vom Typ NSButton hat. Es folgt der (noch leere) Codeblock, der ausgeführt wird, wenn der Button geklickt wurde, eingelossen zwischen geschweiften Klammern.

Um diese Action nun mit dem Button zu verbinden, klicken Sie bitte mit der linken Maustaste in den leeren Kreis, halten die Taste gedrückt, fahren mit der Maus über den Button auf der rechten Seite und lassen die Taste dort los. Sofort füllt sich der Kreis aus und die Action ist verbunden.

Bitte speichern sie nun noch – egal ob notwendig oder nicht – sowohl den Controller, als auch das Storyboard mit einem kurzen cmd+s.

Den Assistant editor können Sie nun wieder verlassen und in den Standard editor zurückwechseln, das Storyboard benötigen wir ersteinmal nicht mehr.

Mit ein bißchen Formatierung sollte Ihr Quelltext jetzt wie in Abbildung 7.4 aussehen:

Abbildung 7.4: Outlet und Action sind verbunden
Abbildung 7.4: Outlet und Action sind verbunden

Beitragsbild: Ricky Jay dice in exhibit von Susan Gerbic in abgewandelter Form (CC BY SA 3.0)

Projekt Zufall 6: Der View Controller

Da die GUI, die Benutzeroberfläche, wie Sie gerade gesehen haben, mehr oder weniger zusammengeclickt wird, der Programmcode hingegen nur aus Text besteht, muss es einen Übergang geben zwischen GUI und Code. Und zwar in beide Richtungen: Der Quelltext muss sozusagen mitbekommen können, wenn jemand den Button clickt und das Label muss vom Code aus mit einem anderen Text versehen werden können.

Die eine Richtung, also die, dass der Benutzer auf der GUI zum Beispiel einen Button clickt und der Code davon benachrichtigt wird, wird durch sogenannte Actions abgebildet. Eine Action bewirkt, das eine gekennzeichnete Methode aufgerufen wird, sobald ein bestimmtes GUI-Ereignis eintritt.

Die umgekehrte Richtung wird durch sogenannte Outlets erreicht. Ein Outlet repräsentiert das in der GUI grafisch erstellte Control als Variable im Quellcode. Auf diese Variable können Sie programmatisch zugreifen und durch Veränderungen der Eigenschaften oder durch Aufruf von Methoden das Control auf der GUI verändern.

Wir benötigen beides: Ein Outlet für das Label und eine Action, die beim Click auf den Button ausgelöst wird. Zuerst müssen wir allerdings wissen, in welchem Quelltext, in welcher Klasse wir Outlet und Action erstellen müssen, wo ist der richtige Ort?

Die Controls, um die es uns geht, liegen auf einer View und diese View hat einen Controller, den ViewController, das ist dieser Ort. Der ViewController kontrolliert die View, wenn man so will, dort kommt alles hinein, was die View verändert oder von der View verändert wird. (Seien Sie bitte nicht verwirrt: Die Controls auf der View sind etwas ganz anderes als der Controller der View, sie heißen nur ähnlich.)

Wählen Sie in Xcode bitte links im Project navigator die Datei ViewController.swift aus, so dass sie im Editor bearbeitet werden kann.

Sie finden in etwa folgendes vor (die Kommentare am Anfang habe ich weggelassen):

import Cocoa

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: AnyObject? {
        didSet {
        // Update the view, if already loaded.
        }
    }

}

Dies ist die sogenannte Implementierung der Klasse ViewControler. Ich will hier einmal kurz durchrauschen, damit Sie einen Überblick bekommen:

Es beginnt mit dem Import von Cocoa. Cocoa ist die wesentliche API (Programmierschnittstelle) für Apple-Programme und wir müssen Cocoa importieren, um die Befehle, die wir nutzen möchten, im Folgenden auch zur Verfügung zu haben.

Dann beginnt die Deklaration der Klasse: Sie heißt ViewController und ist abgeleitet von NSViewController. Abgeleitet bedeutet, grob gesprochen, dass unser View Controller von Beginn an bereits alles kann und enthält, was ein NSViewController kann und enthält, so dass wir nicht alles nocheinmal programmieren müssen. Die öffnende geschweifte Klammer umfasst den gesamten restlichen Code und wird erst in der letzten Zeile wieder geschlossen, die Klasse enthält also sämtlichen, noch folgenden Code.

Und der besteht aus zwei Dingen: Einer Funktion namens viewDidLoad und einer Variablen namens representedObject. Beide verwenden das Schlüsselwort override, das signalisiert, dass eine Funktion bzw. Variable desselben Namens bereits in der Klasse existiert, von der abgeleitet wurde (nämlich NSViewController), und das diese nun überschrieben wird.

Die Funktion viewDidLoad wird von System aufgerufen, wenn die View (auf der wir unsere Controls platziert haben und die diesem Controller zugeordnet ist) geladen wurde. Sie bietet also einen guten Ort, um zu diesem Zeitpunkt Initialisierungen vorzunehmen (darauf weist uns auch der angefügte Kommentar hin). Das wollen wir gleich auch noch machen, darum behalten wir diese Funktion im Code.

Die Variable representedObject wird verwendet, um Daten zwischen zwei Views auszutauschen. Da wir aber nur eine View haben, können wir diese Deklaration aus unserem Code entfernen (und tun das auch: den ganzen Block, alle vier Zeilen).

Nun können wir Action und Outlet platzieren.

Beitragsbild: Ricky Jay dice in exhibit von Susan Gerbic in abgewandelter Form (CC BY SA 3.0)

Projekt Zufall 5: Auto Layout und GUI Organisation (Teil 2)

Ähnlich gehen wir bei dem Button vor: Wählen Sie bitte den Button aus und setzen Sie die beiden Constraints: Horizontal Center in Container (Button ganz links) und Abstand vom unteren Rand des Containers = 20 (zweiter Button von links und dort den unteren Abstandshalter beim oberen Kreuz auswählen). In beiden Fällen das abschließende Add Constraints bitte nicht vergessen.

Hier machen wir uns zunutze, dass Xcode Höhe und Breite eines Buttons aus dem Text innerhalb des Buttons ableiten kann und benötigen so nur zwei Constraints.

Die GUI ist nun vollständig unter der Kontrolle von Auto Layout. Allerdings fehlt noch eine Sache: Der Text des Labels ist links ausgerichtet, sollte aber innerhalb der gesamten Breite des Labels zentriert sein, damit er immer in der Mitte des Fensters steht.

Um das zu erreichen, wählen Sie bitte das Label aus und anschließend in den Utilities die Ansicht Attributes inspector. Im Attributes Inspector können Sie sehen, welche veränderbaren Eigenschaften das ausgewählte Control hat und diese auch gleich verändern. Beim Label (NSTextfield) ist das neben vielen anderen die Eigenschaft Alignment (Ausrichtung, siehe Abbildung 5.5).

Abbildung 5.5: Der Attributes inspector eines Labels (teilweise)
Abbildung 5.5: Der Attributes inspector eines Labels (teilweise)

Setzen Sie bitte das Alignment auf „zentriert“, das ist der zweite Button von links. Starten Sie nun erneut die Applikation.

Wie Sie sehen, können Sie das Applikationsfenster beliebig groß und wieder klein ziehen, beide Controls behalten die Ihnen zugewiesene Position.

Ein kleines Problem gibt es allerdings immer noch: Sie können das Fenster nämlich so klein ziehen, dass der Button das Label überdeckt oder sogar so klein, das fast gar nichts mehr von der View zu sehen ist.

Wir könnten Auto Layout verwenden, um dieses Problem zu lösen, aber wir machen es anders: Bitte wählen Sie den Window Controller aus, das ist das mittlere der drei großen Elemente im Storyboard Editor. Dann wählen Sie den Size inspector im Utilities Bereich (Abbildung 5.6).

Abbildung 5.6: Der Size inspector des Windows
Abbildung 5.6: Der Size inspector des Windows

Unter Constraints können Sie hier die Checkbox Minimum Size auswählen, tun Sie das bitte. Die Werte für Width (Breite) und Height (Höhe) sind so vorbelegt, dass sie der initialen Größe des Fensters entsprechen, so dass Sie später das Fenster zwar größer und dann wieder kleiner ziehen können, aber die initiale Größe können Sie dabei nicht unterschreiten. Das ist genau, was wir wollen, also lassen sie diese Werte bitte so wie sie sind.

Wenn Sie nun die Applikation starten, können Sie alles ausprobieren, die GUI ist nun erst einmal fertig (Abbildung 5.7).

Abbildung 5.7: Die GUI ist fertig
Abbildung 5.7: Die GUI ist fertig

Nur beim clicken auf den Button Neu Würfeln passiert noch nichts. Das gehen wir als nächstes an.

Beitragsbild: Ricky Jay dice in exhibit von Susan Gerbic in abgewandelter Form (CC BY SA 3.0)

Projekt Zufall 5: Auto Layout und GUI Organisation (Teil 1)

Das noch relativ neue Auto Layout gibt uns die Möglichkeit, die Positionen und Größen von Controls relativ zu anderen Controls oder dem umgebenden Container (in unserem Fall der View) zu definieren.

Wenn wir uns im Storyboard Editor befinden, gibt es drei Möglichkeietn, um auf die Auto Layout Eigenschaften eines Controls Einfluss zu nehmen: Zum einen die Menüeinträge unter dem Menüpunkt Editor und als zweites die Einstellungen im Size inspector der Utilities bei ausgewähltem Control (Abbildung 5.1).

Abbildung 5.1: Der Size Inspector in den Utilities
Abbildung 5.1: Der Size inspector in den Utilities

Hauptsächlich aber werden wir die vier Buttons rechts unten im grafischen Editor verwenden (Abbildung 5.2).

Um nun unsere beiden Controls über Auto Layout zu positionieren, wählen wir zunächst das Label aus. Als ersten Schritt zentrieren wir es vertikal: Den linken der vier Buttons clicken, darin Vertical Center in Container auswählen und mit Add 1 Constraint bestätigen (Abbildung 5.2).

Abbildung 5.2: Vertical Center in Container
Abbildung 5.2: Vertical Center in Container

Zur Belohnung wird das Control warn-orange und in der Document Outline erscheint ein kleiner warnender Pfeil, um dieses Problem zu debuggen. Was ist passiert?

Wir haben unser Label mit dem ersten Constraint, der ersten Layout-Bedingung, die wir hinzugefügt haben, unter die Kontrolle von Auto Layout gestellt. Auto Layout benötigt aber Constraints zur horizontalen Position (x Positon), vertikalen Position (y Position), Höhe und Breite eines Controls. Fehlt eines dieser Constraints, dann kann Auto Layout dieses Control nicht positionieren und es kommt zu einer Fehlereldung in der beschriebenen Form.

In unserem Fall fehlen also noch drei Constraints. Hierfür gehen wir ungewöhnlich vor: Bitte wählen Sie das Label aus (falls es nicht noch ausgewählt ist) und greifen Sie von den acht kleinen Quadraten dasjenige auf der linken Kante, um das Label nach links in die Breite zu ziehen (Abbildung 5.3).

Abbildung 5.3: Breiterziehen des Labels
Abbildung 5.3: Breiterziehen des Labels

Dies kann ein wenig fummelig werden weil Sie sich mit dem Constraint (der orangen Linie) ins Gehege kommen können, aber ich bin mir sicher: Sie schaffen das (achten Sie auf den Mauscursor zur Veränderung von rechts-links, sobald der erscheint, haben Sie es).

Ziehen Sie die linke Kante so weit, dass sie an die linksbegrenzende Hilfslinie stößt. Ist es gelungen, machen Sie es bitte genauso mit der rechten Seite. Das Label soll mit kleinem Abstand zum rechten und linken Rand über die ganze Breite gehen.

Mit ausgewähltem Label verwenden Sie nun bitte den zweiten der vier Auto Layout Buttons und clicken auf die beiden Abstandshalter rechts und links beim oberen Kreuz (Abbildung 5.4). Die Zahlenwerte sollten nach rechts und links 20 betragen, dies ist der Wert, bei dem die Hilfslinien erschienen sind, als Sie das Label breiter gezogen haben. Abschließend bitte mit Add 2 Constraints bestätigen.

Abbildung 5.4: Vertikale Abstände des Labels
Abbildung 5.4: Vertikale Abstände des Labels

Was haben Sie gerade gemacht? Sie haben Auto Layout gesagt, dass der linke Rand des Labels 20 Einheiten von linken Rand des Containers (der View) entfernt sein soll und der rechte Rand entsprechend ebenfalls 20 Einheiten vom rechten Rand des Containers. Damit ist die Breite des Labels (nämlich immer fast so breit wie der Container) und dessen horizontale Position (die es genaugenommen gar nicht hat, da es über die gesamte Breite geht, mittig allenfalls) komplett bestimmt.

Nun treten keine Fehler mehr auf, weil Xcode die Höhe des Labels, das letzte fehlende Constraint, aus der Höhe der Schrift innerhalb des Labels ableitet und diese daher zwar explizit bestimmt werden kann – aber nicht muss.

Weiter geht’s im zweiten Teil..

Beitragsbild: Ricky Jay dice in exhibit von Susan Gerbic in abgewandelter Form (CC BY SA 3.0)

Projekt Zufall 4: Hinzufügen eines Buttons

Da wir nicht jedesmal die Applikation neu starten wollen, um eine neue Zufallszahl zu generieren, fügen wir unserer View noch einen Button hinzu.

Hierbei gehen Sie bitte genauso vor wie bie dem Label: Suchen Sie zunächst in der Object Library nach dem Wort „Button“. Es erscheinen ziemlich viele Ergebnisse, interessiert sind wir allerdings schon gleich an dem ersten Eintrag: Push Button. Der Tooltip verrät, dass es sich bei einem Push Button um ein Objekt der Klasse NSButton handelt.

Bitte platzieren Sie den Button unterhalb des Labels, auf der Hilfslinie nahe der unteren Kante und mittig auf der Horizontalen, so wie in Abbildung 4.1.

Abbildung 4.1: Button und Label auf der View
Abbildung 4.1: Button und Label auf der View

Das Label soll seinen neuen Text, nämlich die Zufallszahl, während des Programmablaufs bekommen, wir weisen den neuen Ausgabetext später programmatisch zu. Der Button allerdings wird seine Beschriftung während des Programmablaufs nicht ändern, wir können sie also bereits jetzt, im Storyboard anpassen.

Der Button soll mit „Neu Würfeln“ beschriftet sein. Hierzu wählen Sie bitte den Button zunächst mit einem einfachen Click aus, und führen dann auf dem Button einen Doppelclick aus, um die Beschriftung editieren zu können. Falls das nicht sofort klappt, de-selektieren Sie den Button zunächst, indem Sie z.B. auf das Label clicken, dann probieren Sie es wie beschrieben noch einmal.

Da der Button jetzt nicht mehr zentriert ist, korrigieren Sie bitte seine Position.

Wenn Sie nun die Applikation starten, sieht alles aus wie zuvor im Storyboard Editor, allerdings gibt es ein kleines Problem: Versuchen Sie einmal, das Applikationsfenster zu vergrößern, indem Sie an seiner rechten unteren Ecke ziehen (bitte nicht im Storyboard, sondern in der gestarteten Applikation).

Sie werden feststellen, dass unsere beiden Controls in der linken, oberen Ecke stehen bleiben, obwohl man erwarten würden, dass Sie ihre Positionen relativ zur Größe des Fensters verändern. Um dies zu korrigieren, gibt es Auto Layout.

Beitragsbild: Ricky Jay dice in exhibit von Susan Gerbic in abgewandelter Form (CC BY SA 3.0)

Projekt Zufall 3: Erstellen einer Textausgabe

Unser Programm soll Zufallszahlen erstellen und diese dann ausgeben können. Beginnen wir also mit der Ausgabe von Text.

Grundsätzlich nennt man so ziemlich alles, was sich in einem Fenster befindet, Control. Ein Button, eine Tabelle, ein Texteingabefeld, ein Textausgabefeld, das alles und vieles mehr sind Controls.

Ein anderer, geläufigerer Name für Textausgabefeld ist Label. Wir müssen uns also unter allen zur Verfügung stehenden Controls ein Label heraussuchen und es auf unserem Fenster platzieren.

Hierfür wählen Sie ganz links, im Project Navigator die Datei Main.storyboard aus. In ihr sind fast alle GUI Informationen unsrer Applikation gespeichert, fast die gesamte Benutzeroberfläche unseres Programms „Zufall“. Durch das Auswählen, wird die Datei im Storyboard Editor geöffnet (Abbildung 3.1).

Abbildung 3.1: Der Storyboard Editor
Abbildung 3.1: Der Storyboard Editor

Das Editor Fenster eines Storyboards besteht aus zwei Teilen: Dem grafischen Editor auf der rechten und der schmaleren Document Outline auf der linken Seite. Reicht Ihnen der Platz für den grafischen Editor nicht aus, können Sie mit den Button in seiner linken, unteren Ecke (Abbildung 3.2) die Document Outline aus- und wieder einblenden.

Abbildung 3.2: Die Document Outline ein- und ausblenden
Abb 3.2

Innerhalb des grafischen Editors sind drei große Elemente zu sehen: Das Main Menu ganz oben, darunter das Window mit dem Window Controller und darunter wiederum die View mit dem View Controller. Das Window ist das Fenster, das aufgeht, wenn unsrere Applikation startet. Und eingebettet in das Window ist die View, praktisch das Blatt Papier, auf dem wir zeichnen können. Der besseren Editierbarkeit halber sind Window und View, die später ja übereinander liegen werden, im grafischen Editor auseinandergezogen, lassen Sie sich dadurch bitte nicht verwirren. Unsere Controls platzieren wir jedenfalls auf der View.

Im unteren Teil der Utilities ist vermutlich bereits die Object library ausgewählt, falls nicht, wählen Sie sie bitte aus. Dann geben Sie dort unten in das Suchfeld das Wort „Label“ ein, gefunden werden sollte Label und Wrapping Label (Abbildung 3.1). Da wir uns mit einer einzeiligen Ausgabe begnügen wollen, ist Label das Control unserer Wahl. Wenn Sie mit dem Mauspfeil ein wenig über dem Eintrag für Label ausharren, dann erfahren Sie durch den Tooltip, dass ein Label eine Instanz der Klasse NSTextField ist und bekommen zudem noch eine kurze Beschreibung angezeigt.

Um ein Label zu platzieren, clicken Sie mit der linken Maustaste auf das Suchergebnis Label und ziehen Sie es bei gedrückter Maustaste auf die View (das untere der drei Elemente). Wenn Sie hierbei das Label über die View bewegen, können Sie Hilfslinien sehen, die Ihnen eine genaue Platzierung erleichtern. Versuchen Sie bitte, das Label genau in die Mitte der View zu bringen. Wenn Sie dann die Maustaste loslassen, wird das Label platziert (Abbildung 3.3).

Abbildung 3.3: Ein Label in der View
Abbildung 3.3: Ein Label in der View

Wollen Sie es später nocheinmal verschieben, dann positionieren Sie den Mauspfeil so über dem Label, dass sich der Mauspfeil in eine greifende Hand verwandelt. Mit clicken, ziehen, dann wieder loslassen (Drag and Drop) können sie nun das Label verschieben.

Bitte speichern Sie das Storyboard über die Tastenkombination cmd+s. Ob das tatsächlich nötig ist, darüber gibt es unterschiedliche Aussagen und Erfahrungen, schaden wird gelegentliches Speichern über cmd+s sowohl beim editieren des Storyboards, wie auch beim editieren von Quelltextdateien aber sicher nicht.

Wenn Sie jetzt die Applikation starten (links oben auf den Play-Button clicken), sollten Sie Ihr neues Label bereits sehen können.

Beitragsbild: Ricky Jay dice in exhibit von Susan Gerbic in abgewandelter Form (CC BY SA 3.0)

Projekt Zufall 2: Das Xcode Fenster

Das Xcode Fenster besteht aus vier grundlegenden Bereichen, die jeder für sich noch einmal unterteilt sind (Abbildung 2.1).

Abbildung 2.1: Das Xcode Fenster
Abbildung 2.1: Das Xcode Fenster

Den Navigator gibt es in insgesamt acht verschiedene Varianten. Wie die jeweils heißen, erfahren Sie als Tooltip, wenn Sie länger mit der Maus auf dem entsprechenden Icon ganz oben im Navigator verweilen. Wir bewegen uns hauptsächlich im Project Navigator, das entspricht dem ohnehin voreingestellten Icon in der oberen Zeile ganz links.

Wenn Sie im Navigator eine Datei auswählen, zum Beispiel eine .swift Datei, dann ermöglicht Ihnen der Editor, diese Datei zu bearbeiten. Der Editor kann sehr unterschiedlich aussehen, je nachdem welche Datei sie im Navigator ausgewählt haben.

Einen zusätzlichen Detailgrad zeigen die Utilities. Haben Sie im Editor etwas selektiert oder den Textcursor auf einem Schlüsselwort platziert, dann zeigen die Utilities Details zu dieser Auswahl an und geben Ihnen oft auch noch die Möglichkeit, die Auswahl zu konfigurieren. Richtig wichtig werden sie aber bei der Bearbeitung von GUIs (Benutzeroberflächen).

Schließlich gibt es noch die Debug area. Um Programmfehler aufzuspüren sehen Sie hier die Konsolenausgaben und – wenn Sie ihr Programm im Ablauf angehalten haben – den Kontext der Programmverarbeitung. Die Debug area ist zunächst ausgeblendet.

Um für den Editor Platz zu gewinnen, können Sie die drei übrigen Bereiche nämlich ein- und wieder ausblenden. Hierzu verwenden Sie die drei Buttons rechts oben im Fenster (Abbildung 2.2).

Abbildung 2.2: Bereiche ein- und ausblenden
Abbildung 2.2: Bereiche ein- und ausblenden

Hier, wie schon zuvor und wie auch im folgenden, können Sie die genaue Bezeichnung dessen was ein- oder ausgeblendet wird, dem Tooltip der entsprechenden Buttons entnehmen.

Mit den drei Buttons links neben denen zum Ein- und Ausblenden der Bereiche können Sie außerdem noch den Editor in einen von drei verschiedenen Modi versetzen (Abbildung 2.3).

Abbildung 2.3: Editormodi
Abbildung 2.3: Editormodi

Der Standard editor (Button ganz links) ist der vorausgewählte, fast immer verwendete Modus. Hier wird eine Datei dargestellt und kann bearbeitet werden.

Im Version editor (Button ganz rechts) können Sie zwei verschiedene Versionen einer Datei miteinander vergleichen und so zum Beispiel versehentlich gelöschte Textbereiche aus einer früheren Version wieder herstellen. Die einzelnen Versionen entstehen, indem Sie innerhalb der eingebauten Versionsverwaltung Git einen sogenannten Commit ausführen.

Im Assistant editor (mittlerer Button) werden zwei Dateien gleichzeitig nebeneinander dargestellt. Xcode versucht beim Wechsel in diesen Modus automatisch die Datei herauszufinden, die Sie als Counterpart (rechte Seite) zu Ihrer gerade editierten Datei (linke Seite) wohl sehen möchten. Das gelingt mal besser, mal schlechter. Um diese zweite Datei manuell auszuwählen, clicken Sie auf das Symbol mit den zwei Kreisen oben innerhalb des rechten Editorfensters (Abbildung 2.4).

Abbildung 2.4: Manuelle Auswahl im zweiten Editorfenster
Abbildung 2.4: Manuelle Auswahl im zweiten Editorfenster

Beitragsbild: Ricky Jay dice in exhibit von Susan Gerbic in abgewandelter Form (CC BY SA 3.0)