Skip to main content

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

La plantilla utilizada por forceios para crear aplicaciones Swift muestra una lista de nombres de cuenta de una organización de Salesforce. En esa lista, puede ver los detalles de una cuenta seleccionada y, desde allí, una lista de los contactos de la cuenta. Luego, puede seleccionar un contacto para ver sus detalles. Los clientes no pueden usar la aplicación para interactuar con los datos; solo pueden verlos. Vamos a animar un poco una aplicación Swift de forceios incorporando un botón a la vista Detalles del contacto que permita al usuario eliminar el registro de ese contacto. Si el usuario toca este botón, el código responde del modo siguiente:
  1. Envía una solicitud REST para eliminar el registro Contacto seleccionado.
  2. 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.

  1. En Project Explorer de Xcode, abra Classes > SwiftUI > ContactDetailsView.swift.
  2. Desplácese a la estructura ContactDetailView. Comienza con la línea que contiene la siguiente cadena: 
    struct ContactDetailView: View {
  3. En la definición de var body: some View, envuelva la declaración List con VStack. Elimine la palabra clave return antes de 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. 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)
            }
        }
    }
Si ejecutara la aplicación ahora, vería el botón en la parte inferior de la vista, pero no haría nada significativo. Si lo toca, solo le imprime un mensaje informativo a usted, el desarrollador, en Xcode.

Los clientes corren el riesgo de tocar el botón Eliminar contacto de manera involuntaria, por ejemplo, si están en el transporte público y se mueven demasiado mientras usan su aplicación. Para proteger los datos del cliente, es una buena idea solicitar la confirmación antes de eliminar un contacto. Agreguemos una hoja de acciones para recordar a los clientes que están eliminando el registro Contacto en su organización de Salesforce. Una hoja de acciones es como una alerta con varios botones de acciones. En este caso, dos botones, Aceptar y Cancelar, son suficientes. Si el cliente hace clic en el botón Cancelar, la aplicación abandona la solicitud de eliminación.
  1. En la parte superior de la definición de ContactDetailView, agregue una variable de estado privada llamada deleteWarning y establézcala en false. Esta variable controlará la presentación de nuestra hoja de acciones.
    struct ContactDetailView: View {
        @State private var deleteWarning = false
  2. En la acción del Botón que definió, establezca deleteWarning en true. Esta asignación ocurre cuando el cliente toca el botón. 
    Button(action:{
            self.deleteWarning = true
            print("Delete Contact button tapped.")})
  3. 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! 
                }
            ]
        )
    }
}
Agregó una buena cantidad de código. Probemos la configuración.
  1. 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.
  2. Inicie sesión en su organización de desarrollador y autorice el acceso a los datos.
  3. En la vista Cuentas, haga clic en el nombre de cualquier cuenta para ver su lista de contactos.
  4. Haga clic en el nombre de cualquier contacto para ver sus detalles. Está en la vista ContactDetails.
  5. Haga clic en el botón Eliminar contacto. Si este botón no está, vuelva a comprobar su código.
  6. 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".
  7. ¿No le gustan los colores? Pruebe cambiar las propiedades foregroundColor y background del botón. Para ver los cambios, detenga y reinicie la aplicación.
Nota

Mientras compila y ejecuta su aplicación, es posible que vea la siguiente advertencia (con diferentes Id.) en Xcode. Si es así, puede ignorarlas de manera segura. 

[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)>

Para obtener más información, consulte este debate sobre Stack Overflow.

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. 

  1. En Project Explorer de Xcode, abra Classes > SwiftUI > ContactDetailsModel.swift.
  2. Debajo del código existente de la clase ContactDetailModel, defina una nueva func vacía llamada deleteContact. Este nuevo método toma un solo argumento, contact, de tipo Contact, y devuelve void.
  3. class ContactDetailModel: ObservableObject{
        @Published var contact: Contact
        init(with contact: Contact){
            self.contact = contact
        }
        func deleteContact(contact: Contact) -> Void {
        }
    }
  4. En la parte superior de su nueva función, llame al método API de REST para definir request, su objeto RestRequest.
    func deleteContact(contact: Contact) -> Void {
        let request = RestClient.shared.requestForDelete(withObjectType: "Contact", 
                                                               objectId: contact.Id, 
                                                             apiVersion: nil)
    }
  5. 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
        }
    }
  6. 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.
  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.")
            }
        }
    }
Aquí termina la clase de modelos. Codificó la funcionalidad de Mobile SDK para que elimine un registro de Salesforce. Solo queda una cosa por hacer: Llame al nuevo método deleteContact(_:). ¿Adivina a dónde llamar? ¿Recuerda la hoja de acciones?
  1. Abra el archivo ContactDetailsView.swift.
  2. Desplácese a la definición de .actionSheet. En la matriz buttons de la hoja de acciones, el botón .default (el botón "Aceptar") ofrece un cierre vacío.
  3. Agregue sus llamadas en el cierre .default. Primero, cree una instancia de ContactDetailModel, al pasar el var contact local y, luego, llame a deleteContact(_:) en la instancia de su modelo.
  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) 
                }
            ]
        )
    }

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.

¡Siga aprendiendo gratis!
Regístrese para obtener una cuenta y continuar.
¿Qué hay para usted?
  • Consiga recomendaciones personalizadas para sus objetivos profesionales
  • Practique sus aptitudes con retos prácticos y pruebas
  • Siga y comparta su progreso con empleadores
  • Póngase en contacto para recibir asesoramiento y oportunidades laborales