Skip to main content
Join the Agentforce Hackathon on Nov. 18-19 to compete for a $20,000 Grand Prize. Sign up now. Terms apply.

Ändern der nativen Forceios-Anwendung

Lernziele

Nachdem Sie diese Lektion abgeschlossen haben, sind Sie in der Lage, die folgenden Aufgaben auszuführen:

  • Hinzufügen einer Schaltfläche, mit der Benutzer einen Salesforce-Kontakt löschen können
  • Hinzufügen einer neuen REST-Anforderung zur nativen iOS-Vorlagenanwendung
  • Verarbeiten der REST-Antwort

Mit Trail Together einem Dozenten folgen

Möchten Sie bei diesem Schritt einem Experten folgen? Schauen Sie sich dieses Video an, das Teil der Reihe "Trail Together" ist.

(Dieser Clip beginnt bei Minute 18:11, für den Fall, dass Sie zurückspringen und den Anfang des Schritts noch einmal sehen möchten.)

Anpassen einer forceios-Swift-Anwendung

Die Vorlage, die von forceios zur Erstellung von Swift-Anwendungen verwendet wird, zeigt eine Liste von Accountnamen einer Salesforce-Organisation an. In dieser Liste können Sie Details zu einem ausgewählten Account und anschließend eine Liste mit den Kontakten des Accounts anzeigen. Sie können dann einen Kontakt auswählen, um dessen Details anzuzeigen. Kunden können in der Anwendung nicht mit Daten interagieren, sondern sie nur einsehen. Lassen Sie uns eine forceios-Swift-Anwendung ein wenig aufpeppen, indem wir der Detailansicht "Kontakt" eine Schaltfläche hinzufügen, mit der der Benutzer den Datensatz des jeweiligen Kontakts löschen kann. Wenn der Benutzer auf diese Schaltfläche tippt, antwortet Ihr Code wie folgt:
  1. Sendet eine REST-Anforderung zum Löschen des ausgewählten Kontaktdatensatzes
  2. Bittet den Kunden um Bestätigung des Löschvorgangs

Für diese Übung können Sie die Arbeitsumgebung "Mobile SDK" verwenden, die Sie in der Eröffnungseinheit für natives iOS erstellt haben.

Ansichten und Modelle

Wenn Sie sich den Ordner Classes Ihres Xcode-Projekts anschauen, sehen Sie zwei Unterordner: "SwiftUI" und "Models". Wie ihre Namen schon andeuten, drücken diese Ordner die View-Model-Architektur von SwiftUI-Anwendungen aus. 

  • Der Ordner SwiftUI enthält Ansichtsdefinitionen. Diese Dateien enthalten größtenteils SwiftUI-Layoutkonfigurationen und deren visuelle Attribute. SwiftUI-Ansichten werden typischerweise als Strukturen definiert.
  • Der Ordner Models enthält die Funktionalität, die die SwiftUI-Ansichten mit Daten versorgt. Ansichten rufen Modelle auf, um Datenaufgaben durchzuführen, z. B. Abrufen von Salesforce-Accountnamen oder Löschen eines Kontaktdatensatzes. Modelle enthalten in der Regel eine zentrale Klassendefinition zur Definition der Funktionalität und eventuell einige Strukturen für die Datenorganisation.

Jedes Modell in dieser Vorlagenanwendung teilt sich ein Dateinamenspräfix mit der gekoppelten Ansicht. Zum Beispiel stellt ContactDetailsModel.swift das Modell für ContactDetailsView.swift bereit.

Hinzufügen der Löschschaltfläche

Das Wichtigste zuerst! Lassen Sie uns mit der Implementierung der kosmetischen bzw. visuellen Seite beginnen. Wir können die Schaltfläche "Kontakt löschen" entwerfen, programmieren und testen, bevor wir sie voll funktionsfähig machen. 

Die ContactDetailView-Struktur der Vorlage ist eine aggregierte Liste von Elementen, die an anderer Stelle in dieser Datei definiert sind. Um die Schaltfläche und dieses bereits vorhandene List-Element unabhängig voneinander zu halten, erstellen Sie einen VStack-Container, der beide umschließt. Dieser Container weist iOS an, seine Elemente vertikal so anzuordnen, wie sie im Code angeordnet sind. Damit die Schaltfläche "Löschen" z. B. am unteren Rand der Szene erscheint, platzieren Sie sie hinter dem Element List im VStack. 

In SwiftUI benötigen die Konstruktoren von Schaltflächen ein action-Argument. Diese Aktion wird ausgeführt, wenn der Kunde auf die Schaltfläche tippt. Vorläufig senden wir nur eine Nachricht an die Xcode-Konsole, die das Antippen durch den Kunden bestätigt.

  1. Öffnen Sie im Xcode Project Explorer "Classes > SwiftUI > ContactDetailsView.swift".
  2. Blättern Sie zur Struktur ContactDetailView. Sie beginnt mit der Zeile, die die folgende Zeichenfolge enthält: 
    struct ContactDetailView: View {
  3. Umschließen Sie in der Definition von var body: some View die Deklaration von List mit einem VStack. Entfernen Sie das Schlüsselwort return vor List.
  4. var body: some View { 
        VStack(alignment: .center, spacing: 3) {
            List {
                FieldView(label: "First Name", value: contact.FirstName)
                FieldView(label: "Last Name", value: contact.LastName)
                FieldView(label: "Email", value: contact.Email)
                FieldView(label: "Phone Number", value: contact.PhoneNumber)
                AddressView(contact: contact)
            }
        }
    }
  5. Fügen Sie unter dem Block List unmittelbar vor der schließenden geschweiften Klammer von VStack den Block Button hinzu.
    var body: some View { 
        VStack(alignment: .center, spacing: 3) {
            List {
                FieldView(label: "First Name", value: contact.FirstName)
                FieldView(label: "Last Name", value: contact.LastName)
                FieldView(label: "Email", value: contact.Email)
                FieldView(label: "Phone Number", value: contact.PhoneNumber)
                AddressView(contact: contact)
            }                  
            Button(action:{
                print("Delete Contact button tapped.")})
            {
                Text("Delete Contact")
                .bold()
                .font(.title)
                .padding()
                .foregroundColor(Color.white)
                .background(Color.gray)
            }
        }
    }
Wenn Sie die Anwendung jetzt ausführen würden, sähen Sie die Schaltfläche am unteren Rand der Ansicht, die aber nichts Sinnvolles täte. Wenn Sie darauf tippen, wird in Xcode nur eine Informationsmeldung an Sie, den Entwickler, ausgegeben.

Kunden laufen Gefahr, unbeabsichtigt auf die Schaltfläche "Kontakt löschen" zu tippen, z. B. wenn sie während der Nutzung Ihrer Anwendung in holprigen öffentlichen Verkehrsmitteln unterwegs sind. Um die Daten des Kunden zu schützen, ist es sinnvoll, vor dem Löschen eines Kontakts eine Bestätigung anzufordern. Lassen Sie uns ein Aktionsblatt hinzufügen, um Kunden daran zu erinnern, dass sie den Kontaktdatensatz in ihrer Salesforce-Organisation löschen. Ein Aktionsblatt ist wie eine Warnung mit mehreren Aktionsschaltflächen. In diesem Fall reichen zwei Schaltflächen, "OK" und "Abbrechen", aus. Wenn der Kunde auf die Schaltfläche "Abbrechen" klickt, bricht die Anwendung die Löschanforderung ab.
  1. Fügen Sie oben in der Definition von ContactDetailView eine private Statusvariable namens deleteWarning hinzu und legen Sie sie auf false fest. Diese Variable steuert die Darstellung unseres Aktionsblatts.
    struct ContactDetailView: View {
        @State private var deleteWarning = false
  2. Legen Sie in der von Ihnen definierten Schaltflächenaktion deleteWarning auf true fest. Diese Zuordnung erfolgt, wenn der Kunde auf die Schaltfläche tippt. 
    Button(action:{
            self.deleteWarning = true
            print("Delete Contact button tapped.")})
  3. Fügen Sie hinter der schließenden Klammer des VStack-Blocks die Definition des Aktionsblatts ein.
    .actionSheet(isPresented: $deleteWarning) {
        ActionSheet(title: Text("Deleting Contact"),
            message: Text("This action deletes this contact in your org."),
            buttons: [
                .cancel {},
                .default(Text("OK")) {
                    // TO DO
                }
            ]
        )
    }

Hier ist Ihre Ansichtsdefinition bis zu diesem Punkt.

var body: some View {
    VStack(alignment: .center, spacing: 3) {
        List {
            FieldView(label: "First Name", value: contact.FirstName)
            FieldView(label: "Last Name", value: contact.LastName)
            FieldView(label: "Email", value: contact.Email)
            FieldView(label: "Phone Number", value: contact.PhoneNumber)
            AddressView(contact: contact)
        }
        Button(action:{
            self.deleteWarning = true
            print("Delete Contact button tapped.")})
        {
            Text("Delete Contact")
            .bold()
            .font(.title)
            .padding()
            .foregroundColor(Color.white)
            .background(Color.gray)
        }
    }
    .actionSheet(isPresented: $deleteWarning) {
        ActionSheet(title: Text("Deleting Contact"),
            message: Text("This action deletes this contact in your org."),
            buttons: [
                .cancel {},
                .default(Text("OK")) {
                    // TODO! 
                }
            ]
        )
    }
}
Sie haben eine ganze Menge Code hinzugefügt. Testen wir nun die Einrichtung.
  1. Klicken Sie auf "Ausführen", um Ihre Anwendung auf Fehler zu prüfen. Wenn Ihre bisherige Programmierung keine Fehler aufweist, startet ein iPhone-Simulator und zeigt nach einigen Sekunden den Salesforce-Anmeldebildschirm an.
  2. Melden Sie sich bei Ihrer Entwicklerorganisation an und autorisieren Sie den Datenzugriff.
  3. Klicken Sie in der Ansicht "Accounts" auf einen beliebigen Namen eines Accounts, um dessen Kontaktliste anzuzeigen.
  4. Klicken Sie auf den Namen eines beliebigen Kontakts, um dessen Details einzusehen. Sie befinden sich nun in der Ansicht ContactDetails.
  5. Klicken Sie auf die Schaltfläche "Kontakt löschen". Wenn diese Schaltfläche nicht vorhanden ist, überprüfen Sie Ihren Code.
  6. Um zu bestätigen, dass die Schaltfläche richtig konfiguriert ist, suchen Sie in der Debug-Konsole von Xcode nach einer Zeile mit dem Text "Delete Contact button tapped".
  7. Gefallen Ihnen die Farben nicht? Ändern Sie die Eigenschaften foregroundColor und background Ihrer Schaltfläche. Um die Änderungen zu sehen, müssen Sie die Anwendung beenden und neu starten.
Hinweis

Bei der Erstellung und Ausführung Ihrer Anwendung wird in Xcode möglicherweise die folgende Warnung (mit unterschiedlichen IDs) angezeigt. Falls dem so ist, können Sie sie getrost ignorieren. 

[LayoutConstraints] Unable to simultaneously satisfy constraints.
                                   Probably at least one of the constraints in the following list is one you don't want. 
                                      Try this: 
                                      (1) look at each constraint and try to figure out which you don't expect; 
                                      (2) find the code that added the unwanted constraint or constraints and fix it. 
                                      (
                                          "<NSLayoutConstraint:0x600003c4ecb0 UIView:0x7fca9dd27330.width == - 16   (active)>"
                                      )
                                      Will attempt to recover by breaking constraint 
                                          <NSLayoutConstraint:0x600003c4ecb0 UIView:0x7fca9dd27330.width == - 16   (active)>

Weitere Informationen finden Sie in dieser Diskussion auf Stack Overflow.

Jetzt lassen wir diese Schaltfläche ihren gleichnamigen Auftrag ausführen: Löschen des Kontaktdatensatzes. 

Übermitteln der Löschanforderung an Salesforce

Um einen Kontaktdatensatz zu löschen, fügen Sie Code zur Quelldatei des Modells hinzu. Wenn Sie zur Datei "Classes/Models/ContactDetailModel.swift" navigieren, sehen Sie, dass die ContactDetailModel-Klasse sehr klein ist.

class ContactDetailModel: ObservableObject{
    @Published var contact: Contact
    init(with contact: Contact){
        self.contact = contact
    }
}

Sie können den Member Id der Eigenschaft self.contact verwenden, um den aktuell angezeigten Datensatz zu bestimmen.

Zum Erstellen der REST-Anforderung rufen Sie die Methode RestClient.shared.requestForDelete(withObjectType:objectId:apiVersion:) auf. Diese Anforderung ist unter den Salesforce-API-Anforderungen ungewöhnlich, da sie im Erfolgsfall nichts Wichtiges an den Aufrufer zurückzugeben hat. Da Ihre Anwendung kein Datenpaket zum Analysieren und Bereitstellen erhält, können Sie die REST-Antwort in einem einfachen Fertigstellungsabschluss behandeln. 

  1. Öffnen Sie im Xcode Project Explorer "Classes > SwiftUI > ContactDetailsModel.swift".
  2. Definieren Sie unter dem vorhandenen Code der Klasse ContactDetailModel eine neue leere Funktion namens deleteContact. Diese neue Methode verwendet ein einzelnes Argument, contact, des Typs Kontakt, und gibt void zurück.
  3. class ContactDetailModel: ObservableObject{
        @Published var contact: Contact
        init(with contact: Contact){
            self.contact = contact
        }
        func deleteContact(contact: Contact) -> Void {
        }
    }
  4. Rufen Sie am Anfang Ihrer neuen Funktion die REST-API-Methode auf, um die Anforderung, Ihr RestRequest-Objekt, zu definieren.
    func deleteContact(contact: Contact) -> Void {
        let request = RestClient.shared.requestForDelete(withObjectType: "Contact", 
                                                               objectId: contact.Id, 
                                                             apiVersion: nil)
    }
  5. Für die Übertragung der Anforderung an Salesforce rufen Sie die Funktion RestClient.shared.send(request:_:) auf. Das erste Argument ist die vorformatierte Anforderung, die Sie erstellt haben. Fügen Sie für das zweite Argument einen Fertigstellungsabschluss ein. 
    func deleteContact(contact: Contact) -> Void {
        let request = RestClient.shared.requestForDelete(withObjectType: "Contact", 
                                                               objectId: contact.Id, 
                                                             apiVersion: nil)
        RestClient.shared.send(request: request) {result in
        }
    }
  6. Füllen Sie in den Fertigstellungsabschluss einen switch-Block ein, der zwei Fälle verarbeitet: .success(_) und .failure(_). Für diese einfache Übung geben Sie für jedes Ergebnis eine Statusmeldung in der Debug-Konsole von Xcode aus.
  7. func deleteContact(contact: Contact) -> Void {
        let request = RestClient.shared.requestForDelete(withObjectType: "Contact", 
                                                               objectId: contact.Id, 
                                                             apiVersion: nil)
        RestClient.shared.send(request: request) {result in
            switch result {
                case .success(_):
                    print("Contact deleted.")
                case .failure(_):
                    print("Your attempt to delete this contact could not be completed. This is possibly because it is associated with cases or other dependencies.")
            }
        }
    }
Und schon ist die Model-Klasse fertig! Sie haben eine Mobile SDK-Funktionalität zum Löschen eines Salesforce-Datensatzes programmiert. Bleibt nur noch eines zu tun: Rufen Sie Ihre neue deleteContact(_:)-Methode auf. Können Sie erraten, wo dieser Aufruf erfolgen muss? Erinnern Sie sich an das Aktionsblatt?
  1. Öffnen Sie die Datei "ContactDetailsView.swift".
  2. Blättern Sie zur Definition von .actionSheet. Im Array buttons des Aktionsblatts bietet die Schaltfläche .default (die Schaltfläche "OK") einen leeren Abschluss.
  3. Fügen Sie Ihre Aufrufe dem Abschluss .default hinzu. Erstellen Sie zunächst eine Instanz von ContactDetailModel, wobei Sie die lokale Variable contact übergeben, und rufen Sie dann deleteContact(_:) für Ihre Model-Instanz auf.
  4. .actionSheet(isPresented: $deleteWarning) {
        ActionSheet(title: Text("Deleting Contact"),
            message: Text("This action deletes this contact in your org."),
            buttons: [
                .cancel {},
                .default(Text("OK")) {
                    let model = ContactDetailModel(with: contact)
                    model.deleteContact(contact: contact) 
                }
            ]
        )
    }

Das fertige Produkt genügt nicht der Produktionsqualität. Kunden wissen erst dann, ob das Löschen erfolgreich war, wenn sie zur Listenansicht "Kontakte" zurückkehren und sehen, dass der Kontakt nicht mehr aufgeführt ist. Oder, wenn sie feststellen, dass der Kontakt nicht aus der Ansicht verschwunden ist, erhalten sie keinen Hinweis darauf, was schief gelaufen ist. Eine Möglichkeit, dieses Manko zu beheben, wäre, die Anweisung RestClient.shared.send(request:_:) durch einen Combine-Publisher zu ersetzen und das Ergebnis des Löschaufrufs zu veröffentlichen. Zeigen Sie dann in ContactDetailView dem Kunden das Ergebnis auf der Benutzeroberfläche der Ansicht oder in einem Warnfeld an.

Probieren Sie es aus!

Sie sind nun bereit, den Build für Ihren Code im iOS-Simulator zu erstellen und auszuführen. Achten Sie darauf: Für jeden Standardkontakt in der Developer Edition-Datenbank, den Sie zu löschen versuchen, wird eine Fehlerantwort angezeigt. Diese Fehler treten auf, weil jeder Kontakt, der bereits in einer Developer Edition-Organisation vordefiniert ist, das übergeordnete Element anderer Datensätze ist. Zur Vorbereitung auf die Tests müssen Sie sich bei Ihrer Developer Edition-Organisation anmelden und einen oder mehrere Kontakte erstellen, die keine anderen Datensätze besitzen.

Teilen Sie Ihr Trailhead-Feedback über die Salesforce-Hilfe.

Wir würden uns sehr freuen, von Ihren Erfahrungen mit Trailhead zu hören: Sie können jetzt jederzeit über die Salesforce-Hilfe auf das neue Feedback-Formular zugreifen.

Weitere Infos Weiter zu "Feedback teilen"