Modificar la aplicación nativa Forceios
Objetivos de aprendizaje
Después de completar esta unidad, podrá:
- Agregar un botón que permita a los usuarios eliminar un contacto de Salesforce.
- Agregar una nueva solicitud REST a la aplicación de plantilla iOS nativa.
- Controlar la respuesta REST.
Siga el proceso con Trail Together
¿Desea seguir el proceso con un experto a medida que realiza este paso? Mire este video que forma parte de la serie Trail Together.
(Este video comienza en el minuto 18:11, en caso de que desee rebobinar y mirar el comienzo del paso nuevamente).
Personalizar una aplicación Swift de forceios
- Envía una solicitud REST para eliminar el registro Contacto seleccionado.
- Le solicita al cliente que confirme la eliminación.
Para hacer este ejercicio, puede usar el espacio de trabajo de Mobile SDK que creó en la unidad de apertura de iOS nativo.
Vistas y modelos
Si examina la carpeta Classes de su proyecto de Xcode, verá dos subcarpetas: SwiftUI y Models. Como sus nombres lo indican, estas carpetas expresan la arquitectura de vista y modelo de las aplicaciones SwiftUI.
- La carpeta SwiftUI contiene definiciones de vistas (también conocidas como "cuestiones de la interfaz de usuario"). En su mayoría, estos archivos contienen configuración de formato de SwiftUI y sus atributos visuales. Las vistas de SwiftUI suelen definirse como estructuras.
- La carpeta Models contiene la funcionalidad de datos que impulsa las vistas de SwiftUI. Las vistas llaman a modelos para que realicen tareas de datos, como obtener nombres de cuentas de Salesforce o eliminar un registro Contacto. Generalmente, los modelos incluyen una definición de clase central para definir la funcionalidad y, quizás, algunas estructuras para la organización de datos.
Cada modelo de esta aplicación de plantilla comparte un prefijo de nombre de archivo con su vista emparejada. Por ejemplo, ContactDetailsModel.swift proporciona el modelo para ContactDetailsView.swift.
Agregar el botón Eliminar
¡Lo primero es lo primero! Para comenzar, implementemos el lado cosmético o visual. Podemos diseñar, codificar y probar el botón Eliminar contacto antes de hacerlo completamente funcional.
La estructura ContactDetailView
de la plantilla es una lista agregada de elementos definidos en otra parte de este archivo. Para mantener el botón y este elemento List
preexistente independientes entre sí, debe crear un contenedor VStack
que los envuelva a ambos. Este contenedor le indica a iOS que alinee sus elementos verticalmente tal como están ordenados en el código. Para hacer que el botón Eliminar aparezca en la parte inferior de la escena, por ejemplo, debe colocarlo después de List
en VStack.
En SwiftUI, los constructores de Button requieren un argumento action
. Esta acción se ejecuta cuando el cliente toca el botón. Por ahora, solo enviaremos un mensaje a la consola de Xcode que confirme el toque del cliente.
- En Project Explorer de Xcode, abra Classes > SwiftUI > ContactDetailsView.swift.
- Desplácese a la estructura
ContactDetailView
. Comienza con la línea que contiene la siguiente cadena:struct ContactDetailView: View {
- En la definición de
var body: some View
, envuelva la declaraciónList
conVStack
. Elimine la palabra clavereturn
antes deList
. -
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) } } }
- Debajo del bloque List, justo antes de la llave de cierre de VStack, agregue el bloque de
Button
.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) } } }
- En la parte superior de la definición de
ContactDetailView
, agregue una variable de estado privada llamadadeleteWarning
y establézcala enfalse
. Esta variable controlará la presentación de nuestra hoja de acciones.struct ContactDetailView: View { @State private var deleteWarning = false
- En la acción del Botón que definió, establezca
deleteWarning
entrue
. Esta asignación ocurre cuando el cliente toca el botón.Button(action:{ self.deleteWarning = true print("Delete Contact button tapped.")})
- Después de la llave de cierre del bloque
VStack
, agregue la definición de la hoja de acciones..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 } ] ) }
Esta es la definición de su vista hasta este punto.
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! } ] ) } }
- Haga clic en Ejecutar para comprobar si la aplicación tiene errores. Si su trabajo hasta ahora no tiene errores, se inicia un simulador de iPhone y, después de unos segundos, se muestra la pantalla de inicio de sesión de Salesforce.
- Inicie sesión en su organización de desarrollador y autorice el acceso a los datos.
- En la vista Cuentas, haga clic en el nombre de cualquier cuenta para ver su lista de contactos.
- Haga clic en el nombre de cualquier contacto para ver sus detalles. Está en la vista ContactDetails.
- Haga clic en el botón Eliminar contacto. Si este botón no está, vuelva a comprobar su código.
- Para confirmar que el botón esté configurado correctamente, verifique que en la consola de depuración de Xcode una línea diga "Se presionó el botón Eliminar contacto".
- ¿No le gustan los colores? Pruebe cambiar las propiedades
foregroundColor
ybackground
del botón. Para ver los cambios, detenga y reinicie la aplicación.
Ahora, hagamos que este botón haga el trabajo que su nombre indica: Eliminar el registro Contacto.
Enviar la solicitud de eliminación a Salesforce
Para eliminar un registro Contacto, agregue código al archivo de origen del modelo. Si examina el archivo Classes/Models/ContactDetailModel.swift, verá que la clase ContactDetailModel
es mínima.
class ContactDetailModel: ObservableObject{ @Published var contact: Contact init(with contact: Contact){ self.contact = contact } }
Puede utilizar el miembro Id
de la propiedad self.contact
para identificar el registro visualizado actualmente.
Para crear la solicitud REST, llama al método RestClient.shared.requestForDelete(withObjectType:objectId:apiVersion:)
. Esta solicitud es inusual entre las solicitudes de API de Salesforce porque, si tiene éxito, no tiene nada importante que devolver a la persona que realiza la llamada. Dado que su aplicación no recibirá un paquete de datos para analizar e implementar, puede controlar la respuesta REST en un cierre de realización simple.
- En Project Explorer de Xcode, abra Classes > SwiftUI > ContactDetailsModel.swift.
- Debajo del código existente de la clase
ContactDetailModel
, defina una nuevafunc
vacía llamadadeleteContact
. Este nuevo método toma un solo argumento,contact
, de tipoContact
, y devuelvevoid
. -
class ContactDetailModel: ObservableObject{ @Published var contact: Contact init(with contact: Contact){ self.contact = contact } func deleteContact(contact: Contact) -> Void { } }
- En la parte superior de su nueva función, llame al método API de REST para definir
request
, su objetoRestRequest
.func deleteContact(contact: Contact) -> Void { let request = RestClient.shared.requestForDelete(withObjectType: "Contact", objectId: contact.Id, apiVersion: nil) }
- Para enviar la solicitud a Salesforce, llame la función
RestClient.shared.send(request:_:)
. El primer argumento es la solicitud preformateada que creó. Para el segundo argumento, use código auxiliar en un cierre de realización.func deleteContact(contact: Contact) -> Void { let request = RestClient.shared.requestForDelete(withObjectType: "Contact", objectId: contact.Id, apiVersion: nil) RestClient.shared.send(request: request) {result in } }
- Complete el cierre de realización con un bloque
switch
que controle dos casos:.success(_)
y.failure(_)
. Para este simple ejercicio, imprima un mensaje de estado para cada resultado en la consola de depuración de Xcode. -
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(_:)
. ¿Adivina a dónde llamar? ¿Recuerda la hoja de acciones?- Abra el archivo ContactDetailsView.swift.
- Desplácese a la definición de
.actionSheet
. En la matrizbuttons
de la hoja de acciones, el botón.default
(el botón "Aceptar") ofrece un cierre vacío. - Agregue sus llamadas en el cierre
.default
. Primero, cree una instancia deContactDetailModel
, al pasar el varcontact
local y, luego, llame adeleteContact(_:)
en la instancia de su modelo. -
.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) } ] ) }
Este producto terminado no da la talla de la calidad de producción. Los clientes no sabrán si su eliminación se realizó correctamente hasta que regresen a la vista de lista de Contactos y vean que el contacto ya no está en la lista. O, si descubren que el contacto no desapareció de la vista, no se les indica qué salió mal. Una forma de solucionar ese déficit sería reemplazar la declaración RestClient.shared.send(request:_:)
con un editor Combine
y publicar el resultado de la llamada de eliminación. Luego, en ContactDetailView
, muestre el resultado al cliente en la interfaz de usuario de la vista o en un cuadro de alerta.
¡Pruébelo!
Ya está listo para crear y ejecutar su código en el simulador de iOS. Observe que obtiene una respuesta de error al intentar eliminar cualquier contacto predeterminado de la base de datos de Developer Edition. Estos errores se producen porque cada contacto que viene empaquetado previamente de una organización de Developer Edition es el elemento principal de otros registros. Para prepararse para las pruebas, inicie sesión en su organización de Developer Edition y cree uno o varios contactos de prueba que no tengan otros registros en propiedad.
Recursos
- Guías de desarrollador: Control de respuestas REST
- Guías de desarrollador: Plantilla Swift nativa
- Guías de desarrollador: Gestión de datos modelo en su aplicación (biblioteca para desarrolladores de iOS)
- Vínculo externo Cierres (El lenguaje de programación Swift)