Ä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
- Sendet eine REST-Anforderung zum Löschen des ausgewählten Kontaktdatensatzes
- 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.
- Öffnen Sie im Xcode Project Explorer "Classes > SwiftUI > ContactDetailsView.swift".
- Blättern Sie zur Struktur
ContactDetailView
. Sie beginnt mit der Zeile, die die folgende Zeichenfolge enthält:struct ContactDetailView: View {
- Umschließen Sie in der Definition von
var body: some View
die Deklaration vonList
mit einemVStack
. Entfernen Sie das Schlüsselwortreturn
vorList
. -
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) } } }
- 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) } } }
- Fügen Sie oben in der Definition von
ContactDetailView
eine private Statusvariable namensdeleteWarning
hinzu und legen Sie sie auffalse
fest. Diese Variable steuert die Darstellung unseres Aktionsblatts.struct ContactDetailView: View { @State private var deleteWarning = false
- Legen Sie in der von Ihnen definierten Schaltflächenaktion
deleteWarning
auftrue
fest. Diese Zuordnung erfolgt, wenn der Kunde auf die Schaltfläche tippt.Button(action:{ self.deleteWarning = true print("Delete Contact button tapped.")})
- 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! } ] ) } }
- 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.
- Melden Sie sich bei Ihrer Entwicklerorganisation an und autorisieren Sie den Datenzugriff.
- Klicken Sie in der Ansicht "Accounts" auf einen beliebigen Namen eines Accounts, um dessen Kontaktliste anzuzeigen.
- Klicken Sie auf den Namen eines beliebigen Kontakts, um dessen Details einzusehen. Sie befinden sich nun in der Ansicht ContactDetails.
- Klicken Sie auf die Schaltfläche "Kontakt löschen". Wenn diese Schaltfläche nicht vorhanden ist, überprüfen Sie Ihren Code.
- 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".
- Gefallen Ihnen die Farben nicht? Ändern Sie die Eigenschaften
foregroundColor
undbackground
Ihrer Schaltfläche. Um die Änderungen zu sehen, müssen Sie die Anwendung beenden und neu starten.
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.
- Öffnen Sie im Xcode Project Explorer "Classes > SwiftUI > ContactDetailsModel.swift".
- Definieren Sie unter dem vorhandenen Code der Klasse
ContactDetailModel
eine neue leereFunktion
namensdeleteContact
. Diese neue Methode verwendet ein einzelnes Argument,contact
, des TypsKontakt
, und gibtvoid
zurück. -
class ContactDetailModel: ObservableObject{ @Published var contact: Contact init(with contact: Contact){ self.contact = contact } func deleteContact(contact: Contact) -> Void { } }
- Rufen Sie am Anfang Ihrer neuen Funktion die REST-API-Methode auf, um die
Anforderung
, IhrRestRequest
-Objekt, zu definieren.func deleteContact(contact: Contact) -> Void { let request = RestClient.shared.requestForDelete(withObjectType: "Contact", objectId: contact.Id, apiVersion: nil) }
- 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 } }
- 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. -
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.") } } }
deleteContact(_:)
-Methode auf. Können Sie erraten, wo dieser Aufruf erfolgen muss? Erinnern Sie sich an das Aktionsblatt?- Öffnen Sie die Datei "ContactDetailsView.swift".
- Blättern Sie zur Definition von
.actionSheet
. Im Arraybuttons
des Aktionsblatts bietet die Schaltfläche.default
(die Schaltfläche "OK") einen leeren Abschluss. - Fügen Sie Ihre Aufrufe dem Abschluss
.default
hinzu. Erstellen Sie zunächst eine Instanz vonContactDetailModel
, wobei Sie die lokale Variablecontact
übergeben, und rufen Sie danndeleteContact(_:)
für Ihre Model-Instanz auf. -
.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.
Ressourcen
- Entwicklerhandbuch: Verarbeiten von REST-Antworten
- Entwicklerhandbuch: Native Swift-Vorlage
- Entwicklerhandbuch: Managing Model Data in Your App (iOS Developer Library)
- Externer Link: Closures (The Swift Programming Language)