Kategorien-Archiv Xcode Swift DE

VonTobias Stephan

SwiftUI list refresh does not work funktioniert nicht

Ich hatte das Problem, dass sich die Liste schlichtweg nicht aktualisiert hat. Alle Versuche die Liste dazu zu bringen, sich zu verändern, wenn sich ein Wert des Arrays ändert, führte leider nicht zum Erfolg. Auch ein kompletter Reload des Arrays war nicht zielführend. Für die SwiftUI List habe ich diese Klasse ListDataSource als Observerable Object eingerichtet. Eigentlich hätte sich die Liste bei Änderung eines Wertes im Array ListOfListEntries automatisch alles ändern müssen, also ein Refresh hätte stattfinden sollen. Dem war aber nicht so. Nach langem Suchen war es nur eine Kleinigkeit – nämlich das @Published hat gefehlt. Ich hoffe denjenigen damit geholfen zu haben, die sich damit auch gerade die Finger „brechen“.

class ListDataSource: ObservableObject {
    //Nicht mehr erforderlich?
    //let didChange = PassthroughSubject()
    let didChange = PassthroughSubject()



   @Published var ListOfListEntries = [oListEntryFields]() //{
        //didSet { didChange.send() }

    //}
    var ListOfGroups = [oListGroups]()
    let oListoryParser = ListoryXMLParser()
    let defaults = UserDefaults.standard

    var ActiveListKey : String = ""
    var ActiveGroupKey : String = ""
    var ActiveListTitle : String = ""
    var ActiveGroupTitle : String = ""

    init() {
        reload()
        didChange.send()
    }
}
VonTobias Stephan

SwiftUI Textfield Textbox füllen

…das ist nun wirklich keine Raketenwissenschaft. Den aktuellen Wert hinterlegt man as String – direkte Texteingabe oder halt eine Variable. Die Eigenschaft Text findest Du dann der @State Variable $name wieder. Mit Hilfe der textfieldStyle Eigenschaft RoundedBorderTextFieldStyle() sieht die Textbox so aus, wie wir das aus den Storyboard-Zeiten kennen. Natürlich gibt es zahlreiche Möglichkeiten das Erscheinungsbild des TextField Objekts wunschgemäß anzupassen.

struct ContentView: View {
    @State private var name: String = "Peter"

    var body: some View {
        VStack {
            TextField("Enter your name", text: $name)
            .textFieldStyle(RoundedBorderTextFieldStyle())
            Text("Hello, \(name)!")
        }
    }
}

VonTobias Stephan

Swift Datum in string konvertieren Date to String Convert DE

Hier eine einfache Funktion mit der Du ein Date in ein deutsches Datumsformat als Stirng konvertieren kannst. Das in deutschland übliche Format sieht so aus: „dd.MM.yyyy hh:mm:ss“

Natürlich kannst Du das auch durch andere Formate prolbemlos ersetzen.

public static func ConvertDateToGermanFormat(DateValue: Date) - String {
        let df = DateFormatter()
        //Nun legen wir das in Deutschland übliche Format fest
        df.dateFormat = "dd.MM.yyyy hh:mm:ss"
        //aus dem Date erzeugen wir wiederum ein String
        let sNewDateFormat = df.string(from: DateValue)
        return sNewDateFormat
}

Gibt nur das Datum im lokalen Format je nach Nutzer einstellung aus.
Das Ergebnis kann wie folgt aussehen: “12/31/2019”

let today = Date()
let formatter1 = DateFormatter()
formatter1.dateStyle = .short
print(formatter1.string(from: today))

Hier die Ausgabe von Datum und Uhrzeit abhängig von den regionalen Einstellungen:
Das Ergebnis kann so aussehen: “20:27:32” or “8:27:32pm”

let formatter2 = DateFormatter()
formatter2.timeStyle = .medium
print(formatter2.string(from: today))

Hier ein paar fertige Datumsfunktionen in einer Klasse:

class Tools {


    public static func ConvertDateToGermanFormat(DateValue: Date) -> String {
        let df = DateFormatter()
        //Nun legen wir das in Deutschland übliche Format fest
        df.dateFormat = "dd.MM.yyyy HH:mm:ss"
        //aus dem Date erzeugen wir wiederum ein String
        let sNewDateFormat = df.string(from: DateValue)
        return sNewDateFormat
    }

    public static func ConvertDateOnlyFormat(DateValue: Date) -> String {
           let df = DateFormatter()
           //Nun legen wir das in Deutschland übliche Format fest
           df.dateFormat = "dd.MM.yyyy"
           //aus dem Date erzeugen wir wiederum ein String
           let sNewDateFormat = df.string(from: DateValue)
           return sNewDateFormat
       }

    public static func ConvertDateToLocalFormat(DateValue: Date) -> String {
        let formatter = DateFormatter()
        formatter.timeStyle = .medium
        return formatter.string(from: DateValue)
    }

    public static func ConvertDateToLocalDateOnlyFormat(DateValue: Date) -> String {
         let formatter = DateFormatter()
         formatter.dateStyle = .medium
         return formatter.string(from: DateValue)
     }

    public static func ConvertStringToDate(DateValue: String) -> Date {
        let formatter = DateFormatter()
        let dValue = DateValue

        //formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        var date = formatter.date(from: dValue)
        if (date==nil)
        {
            formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
                date = formatter.date(from: dValue)
        }
        return date!
    }



}
VonTobias Stephan

Swift String to Date function mit verschiedenen Formaten

Hier biete ich Dir eine kleine Klasse mit einer statischen Funktion, mit der Du problemlos ein String Wert in ein Date Format verwandeln kannst.

Datumsformate:
Wednesday, Sep 12, 2018           --> EEEE, MMM d, yyyy
09/12/2018                        --> MM/dd/yyyy
09-12-2018 14:11                  --> MM-dd-yyyy HH:mm
Sep 12, 2:11 PM                   --> MMM d, h:mm a
September 2018                    --> MMMM yyyy
Sep 12, 2018                      --> MMM d, yyyy
Wed, 12 Sep 2018 14:11:54 +0000   --> E, d MMM yyyy HH:mm:ss Z
2018-09-12T14:11:54+0000          --> yyyy-MM-dd'T'HH:mm:ssZ
12.09.18                          --> dd.MM.yy
10:41:02.112                      --> HH:mm:ss.SSS

Das passende Datumsformat habe ich hier fix in den Code gesetzt – das kannst Du natürlich auch noch hübscher machen.

class Tools {

    public static func ConvertStringToDate(DateValue: String) -> Date {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        let date = formatter.date(from: DateValue)
        return date!
    }

}

Hier ein Praxisbeispiel. Der String Wert befindet sich in der auskommentierten Zeile. In diesem Beipsiel ging es darum, ein XML-File von einem Websearver auszulesen und ein Wiedervorlagedatum in das richtige Date Format zu bringen. Spätestens beim Debuggen erkennt man das vorliegende Format oder man schaut sich das XML-File einfach online an.

//s["Wiedervorlage"]    String?    "2020-02-09T15:24:21.693+01:00"    
let dDate :Date = Tools.ConvertStringToDate(DateValue: s["Wiedervorlage"]!)

Das Setzen des Gebietsschemas auf en_US_POSIX wird beim Parsen von Daten von einem Server dringend empfohlen, um Probleme mit den lokalen Einstellungen des Geräts zu vermeiden. Für einige Hintergrundinformationen darüber gibt bei den TECH NOTES von Apple.

formatter.locale = Locale(identifier: "en_US")
formatter.dateStyle = .short

formatter.string(from: date) // returns 12/10/2018

//Als Beispiel UK
formatter.locale = Locale(identifier: "en_GB")
formatter.string(from: date) // returns 10/12/18
//Man beachte das zweistellige Jahr

//...wenn wir in Deutschland sind...

formatter.locale = Locale(identifier: "de_DE")
formatter.string(from: date) // returns 10.12.18
Turns out the periods are the accepted standard. In addition, DateFormatter has already translated names for you, so you don't have to worry about it:

//...oder aber in Spanien
formatter.locale = Locale(identifier: "es_ES") 
formatter.dateStyle = .long
formatter.string(from: date) // returns "10 de diciembre, 2018"

VonTobias Stephan

SwiftUI load new view neue View anzeigen mit NavigationLink

Das ist ja wirklich mal einfach gelöst. Der NavigationLink umfasst hier die jeweils aus der Liste zu verlinkende Zeile.

struct ListoryListView: View {

        @ObservedObject var oListDatasource = ListDataSource()

        let oListoryParser = ListoryXMLParser()
        @State var selection = Set()
        var body: some View {
            NavigationView {

                List(){
                    ForEach(oListDatasource.ListOfListEntries)
                    { item in
                        NavigationLink(destination: EditEntryView()) {
                            VStack(alignment: .leading){
                                Text(item.Caption)


                            }

                            .onTapGesture {
                                print("\(item.Caption)")
                            }
                        }

                        //.navigationBarItems(trailing: EditButton())

                    }.onDelete(perform: xdelete)
                }
                    
                .navigationBarTitle(Text(self.oListDatasource.ActiveListTitle))
            .navigationBarItems(trailing:

                           Button("Help") {
                               print("Help tapped!")
                           }
                       )
            }

        }
VonTobias Stephan

Swift User defaults löschen delete remove

Manchmal möchte man die gespeicherten User Defaults auch einfach mal wieder entfernen. Mit diesem kleinen Code-Snippet machst Du wieder alles sauber.

  
let domain = Bundle.main.bundleIdentifier!
UserDefaults.standard.removePersistentDomain(forName: domain)
UserDefaults.standard.synchronize()
print(Array(UserDefaults.standard.dictionaryRepresentation().keys).count)
VonTobias Stephan

swift user defaults read set lesen schreiben

Mit UserDefaults kannst Du jeden beliebigen Basisdatentyp so lange speichern, wie die Anwendung installiert ist. Sie können grundlegende Typen wie Bool, Float, Double, Int, String oder URL schreiben, aber auch komplexere Typen wie Arrays, Wörterbücher und Datum – und sogar Datenwerte.

Wenn Sie Daten in UserDefaults schreiben, werden diese automatisch geladen, wenn Ihre Anwendung ausgeführt wird, so dass Sie sie wieder zurücklesen können. Das macht die Benutzung wirklich einfach, aber Sie müssen wissen, dass es eine schlechte Idee ist, viele Daten darin zu speichern, weil es das Laden Ihrer Anwendung verlangsamt. Wenn Sie glauben, dass Ihre gespeicherten Daten mehr als sagen wir 100KB benötigen würden, ist UserDefaults mit ziemlicher Sicherheit die falsche Wahl.

Bevor wir mit der Modifizierung von Projekt 10 beginnen, werden wir zunächst ein wenig Testkodierung durchführen, um auszuprobieren, was UserDefaults uns erlaubt. Vielleicht finden Sie es nützlich, ein neues Single View App-Projekt zu erstellen, nur um den Code zu testen.

Um mit UserDefaults zu beginnen, erstellst Du eine neue Instanz der Klasse:

Defaults deklarieren:

let defaults = UserDefaults.standard

Speichern eines Werts:

defaults.set(self.txtBenutzername.text , forKey: "UsernameKey")

Lesen eines Werts:

  if (defaults.string(forKey: "UsernameKey") != nil) {
            self.txtBenutzername.text = defaults.string(forKey: "UsernameKey")
}        
VonTobias Stephan

swiftui list array example load from xml feed

Hier zeige ich Dir, wie du mit Swift UI eine Liste generierst. Zuerst laden wir ein XML-File aus dem Web. Dann durchlaufen wir das Array und füllen eine neue DataSource Class mit einem identifiable struct. Wir achten darauf, dass wir nicht @State verwenden, sondern @ObservedObject. Die DataSource class hat den Typ ObservableObject. Für die Liste gibt es ein eigenes Struct, das macht die ganze sache übersichtlicher. Ich selber habe den Fehler als Swift UI Neuling hier @State zu verwenden. Bei dem Versuch die Datenquelle zu füllen, bekam ich keine Fehlermeldung, aber die Anzahl der Datensätze aus dem gelesenen XML-File blieb schlichtweg 0.

Hierfür ein Swift-File anlegen. Das ist die Klasse um XML zu parsen.
//
//  XMLParser.swift
//  Listory
//
//  Created by T. Stephan on 15.02.20.
//  Copyright © 2020 eCommerce - Tobias Stephan. All rights reserved.
//
import UIKit
import Foundation
class ListoryXMLParser: UIViewController, XMLParserDelegate {
    var parser = XMLParser()

       let recordKey = "export"
       var dictionaryKeys = [String]() //"ASIN","Titel","Hersteller","Marke","BuyBoxPreis","Logdatum","Gesamtangebote","Bulletpoints"]

       // a few variables to hold the results as we parse the XML

       public var results: [[String: String]]? = [[String: String]]()         // the whole array of dictionaries
       var currentDictionary: [String: String]!                        // the current dictionary
       var currentValue: String?

       let defaults = UserDefaults.standard

       func beginParsing(tablename: String,criterion: String){
           let sASIN = ""
           beginParsing(tablename: tablename, criterion: criterion, asin: sASIN)
       }

       func beginParsing(tablename: String,criterion: String,asin: String)
       {
           results?.removeAll()
           //posts = []
           //let defaults = UserDefaults.standard

           var sHostname = "https://www.hostname.de/"

           if (defaults.string(forKey: "httpHostname") != nil){
               sHostname = defaults.string(forKey: "httpHostname")!
           }


           var sUrl = sHostname + "/exportxml.aspx?table=" + tablename + "&criterion=" + criterion



           if asin != "" {
               sUrl = sUrl + "&asin=" + asin
           }

           if (defaults.string(forKey: "fcm") != nil){
               sUrl = sUrl + "&token=" + defaults.string(forKey: "fcm")!
           }



           parser = XMLParser(contentsOf:(NSURL(string: sUrl))! as URL)!


           parser.delegate = self
           parser.parse()

       }


       func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {

           if elementName == recordKey {

               currentDictionary = [String : String]()

           } else if dictionaryKeys.contains(elementName) {

               currentValue = String()

           }
       }



       func parser(_ parser: XMLParser, foundCharacters string: String) {

           currentValue? += string

       }


       func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {

           if elementName == recordKey {

               results?.append(currentDictionary)
               currentDictionary = nil

           } else if dictionaryKeys.contains(elementName) {

               currentDictionary[elementName] = currentValue
               currentValue = nil

           }
       }

       func parserDidStartDocument(_ parser: XMLParser) {
           //results = [[:]]
       }

       func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {

           print(parseError)

       }
}

Dann legen wir noch ein SwiftUI File ein und definieren hier das struct für die Datenquelle.

Grundlage für die Datenquelle:
import SwiftUI



struct oListEntryFields: Identifiable {
    var id = UUID()
    var rowID : Int64
    var ListKey : String
    var ListenGruppenKey : String
    var ListenKeyView : String
    var Caption: String

}

Hier bewegen wir uns nun im ContentView.swift File. Hier findet man dann auch die Klasse für die Datenquelle.

import SwiftUI
import Combine

class ListDataSource: ObservableObject {

    var ListOfListEntries = [oListEntryFields]()
    let oListoryParser = ListoryXMLParser()

    init() {
        oListoryParser.dictionaryKeys.removeAll()
        oListoryParser.dictionaryKeys.append("ID");
        oListoryParser.dictionaryKeys.append("ListenKey");
        oListoryParser.dictionaryKeys.append("ListenGruppenKey");
        oListoryParser.dictionaryKeys.append("ListenKeyView");
        oListoryParser.dictionaryKeys.append("Bezeichnung");
        oListoryParser.dictionaryKeys.append("Aenderungsdatum");
        oListoryParser.dictionaryKeys.append("Erstanlagedatum");
        oListoryParser.dictionaryKeys.append("Archiviert");
        oListoryParser.dictionaryKeys.append("Wiedervorlage");
        oListoryParser.beginParsing(tablename: "key", criterion: "bsCQ2ivUHXOyk")


        var iRow = -1
        for s in oListoryParser.results! {
            iRow += 1
            let rowID = Int64(s["ID"]!)
            let ListEntry = oListEntryFields(rowID: rowID!, ListKey: s["ListenKey"]!, ListenGruppenKey: s["ListenGruppenKey"]!, ListenKeyView: s["ListenKeyView"]!, Caption: s["Bezeichnung"]!)
            //LoadListData.append(ListEntry)
            ListOfListEntries.append(ListEntry)

        }
    }
}

public struct ContentView: View {
    @State var selection: Int = 0



    let defaults = UserDefaults.standard


    public var body: some View {



        TabView(selection: $selection){

            VStack{
                ListoryListView()
            }
            .tabItem {
                VStack {
                    Image("first")
                    Text("First")
                }
            }


            .tag(0)
            Text("Second View")
                .font(.title)
                .tabItem {
                    VStack {
                        Image("second")
                        Text("Second")
                    }
            }
            .tag(1)
        }.onAppear(){

        }
    }


    struct ListoryListView: View {



        @ObservedObject var oListDatasource = ListDataSource()

        let oListoryParser = ListoryXMLParser()
        @State var selection = Set()
        var body: some View {
            NavigationView {
                List(){
                    ForEach(oListDatasource.ListOfListEntries)
                    { item in

                        VStack(alignment: .leading){
                            Text(item.Caption)


                        }

                        .onTapGesture {
                            print("\(item.Caption)")

                        }
                        .navigationBarTitle(Text("List"))

                    }.onDelete(perform: xdelete)
                }
            }

        }
        
        func xdelete(at offsets: IndexSet) {
            if let first = offsets.first {
                print("remove \(first)")
                oListDatasource.ListOfListEntries.remove(at: first)
            }
        }

 
    }
}




struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
VonTobias Stephan

Swift UI arbeiten mit @State

Alle Apps ändern ihren Status. Zum Beispiel könnte der Benutzer auf eine Schaltfläche getippt haben, um weitere Informationen anzuzeigen, er könnte einen Text in ein Textfeld eingegeben oder ein Datum aus einer Datumsauswahl gewählt haben – alles Dinge, bei denen die App von einem Zustand in einen anderen wechselt.

Das Problem mit dem Zustand ist, dass er unübersichtlich ist: Wenn er sich ändert, müssen wir diese Änderung erkennen und unsere Layouts entsprechend aktualisieren. Das klingt zunächst vielleicht einfach, aber wenn unser Zustand wächst und wächst, wird es immer schwieriger – man vergisst leicht, eine Sache zu aktualisieren oder die Reihenfolge der Aktualisierung zu verwechseln, so dass der Zustand der Benutzeroberfläche nicht mit dem übereinstimmt, was erwartet wurde.

SwiftUI löst dieses Problem, indem es den Zustand aus unserer Kontrolle entfernt. Wenn wir Eigenschaften zu unseren Ansichten hinzufügen, sind sie effektiv inaktiv – sie haben zwar Werte, aber ihre Änderung bewirkt nichts. Wenn wir jedoch das spezielle @State-Attribut vor ihnen hinzugefügt haben, wird SwiftUI automatisch auf Änderungen achten und alle Teile unserer Ansichten, die diesen Zustand verwenden, aktualisieren.

Wenn es darum geht, sich auf einen Zustand zu beziehen – zum Beispiel, eine Zustands-Eigenschaft anzuweisen, sich zu ändern, wenn sich ein Kippschalter ändert – können wir nicht direkt auf die Eigenschaft verweisen. Das liegt daran, dass Swift denken würde, dass wir uns gerade auf den Wert beziehen, anstatt zu sagen: „Bitte passen Sie auf das Ding auf“. Glücklicherweise besteht die Lösung von SwiftUI darin, ein Dollarzeichen vor den Namen des Grundstücks zu setzen, wodurch wir uns auf die Daten selbst und nicht auf ihren aktuellen Wert beziehen können. Ich weiß, dass dies am Anfang etwas verwirrend ist, aber nach ein oder zwei Stunden wird es zur zweiten Natur.

Denken Sie daran, dass SwiftUI deklarativ ist, d.h. wir teilen ihm alle Layouts für alle möglichen Zustände im Voraus mit und lassen es herausfinden, wie es sich zwischen ihnen bewegen kann, wenn sich die Eigenschaften ändern. Wir nennen dies Bindung – wir bitten SwiftUI, Änderungen zwischen einem UI-Steuerelement und einer zugrunde liegenden Eigenschaft zu synchronisieren.

Die Arbeit mit State wird Ihnen anfangs einige Kopfschmerzen bereiten, wenn Sie an einen imperativeren Programmierstil gewöhnt sind, aber vertrauen Sie mir – wenn Sie damit fertig sind, ist die Sache klar. Übersetzt mit www.DeepL.com/Translator (kostenlose Version)

VonTobias Stephan

XCode Git Wiederherstellung Repository

Egal ob Sie als Solo-Entwickler oder im Team arbeiten, wenn Sie für Ihre Projekte keine Quellcodekontrolle verwenden, sollten Sie es tun. Die Versionsverwaltung ist erstaunlich, weil sie Ihnen hilft, leichter zu älteren Versionen Ihres Codes zurückzukehren, neue Funktionen ohne Risiko zu Ihrer funktionierenden Anwendung hinzuzufügen, zu sehen, wie sich Ihr Code im Laufe der Zeit verändert hat, und als Team zu arbeiten. Und eines der besten Quellcode-Kontrollsysteme ist direkt in Xcode integriert – Git!

Git ist ein verteiltes Versionskontrollsystem, das ursprünglich von Linus Torvalds entwickelt wurde, dem Hauptverantwortlichen für die Entwicklung des Linux-Kernels. Das Schöne an Git ist, dass es kein zentrales Repository geben muss – jeder kann seine eigene Sicht auf den Code haben und Änderungen aus anderen Quellen einziehen.

In diesem Tutorial werden Sie praktische Erfahrungen mit Git sammeln und lernen, wie Sie es direkt in Xcode verwenden können.

Erste Schritte
Anstatt über die Theorie des Git zu schwafeln, tauchen Sie gleich ein und probieren es aus. Sie werden ein neues Xcode-Projekt erstellen und einige Aufgaben ausprobieren, die Sie normalerweise täglich mit der Git-Quellcode-Kontrolle durchführen werden.

Starten Sie Xcode und erstellen Sie ein neues Single View Application-Projekt. Wählen Sie einen Speicherort und stellen Sie sicher, dass die Option Git-Repository auf meinem Mac erstellen ausgewählt ist, bevor Sie fortfahren. Sobald Sie dies getan haben, klicken Sie auf Erstellen.


Xcode wird Ihr neues Projekt zusammen mit einem neuen Git-Repository erstellen.

Alle Versionskontrollsysteme, einschließlich Git, speichern ihre Daten in einem Repository, damit sie Ihre Projektversionen verwalten und Änderungen während des gesamten Entwicklungszyklus verfolgen können. Stellen Sie sich ein Repository als eine Datenbank für Versionen vor.

Versions-Datenbank

Im Laufe der Arbeit an Ihrem Projekt werden Sie Dateien hinzufügen, Code modifizieren und Ihr Projekt viele Male ändern.

Nachdem Sie eine große Anzahl von Änderungen vorgenommen haben und sich Ihr Projekt in einem „bekannt guten“ Zustand befindet (normalerweise ein oder mehrere Male pro Tag), ist es eine gute Idee, Ihre Änderungen in das Repository einzuchecken. Dadurch erhalten Sie eine Aufzeichnung der „bekannt guten“ Zustände, zu denen Sie jederzeit zurückkehren können.

Aber was ist mit dem Code, der von der Projektvorlage erstellt wurde?

Ihr Projekt enthält nach wie vor nur die Vorlagendateien. Sie müssen noch nichts übergeben, weil Xcode dies für Sie getan hat, als Sie Ihr Projekt erstellt haben.

Um dies zu überprüfen, öffnen Sie den Navigator der Versionsverwaltung (Befehlstaste-2 ist die Tastenkombination). Stellen Sie nun sicher, dass der Versionsverwaltungsinspektor (Befehl-Option-3) ebenfalls geöffnet ist. Klicken Sie mit der Option auf das Offenlegungsdreieck neben GitUseExample im linken Fensterbereich, um alle in Ihrem Repository konfigurierten Zweige, Tags und Fernbedienungen anzuzeigen. Klicken Sie auf den Master-Zweig und dann auf die Erstübergabe im Editor-Fenster und Sie sehen die Details der automatischen Übertragung von Xcode.

XCode Git Repository wiederherstellen

Nehmen Sie jetzt einige Änderungen an Ihrem Projekt vor. Geänderte Dateien werden mit einem „M“ gekennzeichnet. Klicken sie mit der rechten Maustaste auf die Datei und wählen Commit. Nun befindet sich die Änderung im Repository und kann in dem Zustand jederzeit wiederhergestellt werden.