Crear de aplicaciones de iOS SWIFT con Microsoft Graph
Este tutorial te enseña a crear una aplicación de iOS con Swift que usa la API de Microsoft Graph para recuperar información de calendario para un usuario.
Sugerencia
Si prefiere descargar el tutorial completado, puede descargar o clonar el repositorio GitHub archivo.
Requisitos previos
Antes de iniciar este tutorial, debe tener lo siguiente instalado en el equipo de desarrollo.
También debe tener una cuenta personal de Microsoft con un buzón en Outlook.com, o una cuenta de Trabajo o escuela de Microsoft. Si no tienes una cuenta de Microsoft, hay un par de opciones para obtener una cuenta gratuita:
- Puedes suscribirte a una nueva cuenta personal de Microsoft.
- Puedes suscribirte al programa Microsoft 365 desarrolladores para obtener una suscripción Microsoft 365 gratuita.
Nota
Este tutorial se escribió con Xcode versión 12.3 y CocoaPods versión 1.10.1 Los pasos de esta guía pueden funcionar con otras versiones, pero eso no se ha probado.
Comentarios
Proporcione cualquier comentario sobre este tutorial en el repositorio GitHub usuario.
Crear una aplicación de iOS SWIFT
Comience creando un nuevo proyecto de Swift.
Abra Xcode. En el menú Archivo, seleccione Nuevo y, a continuación, Project.
Elija la plantilla Aplicación y seleccione Siguiente.
Establezca el nombre del producto en y el
GraphTutorial
idioma en Swift.Rellene los campos restantes y seleccione Siguiente.
Elija una ubicación para el proyecto y seleccione Crear.
Instalar dependencias
Antes de seguir adelante, instale algunas dependencias adicionales que usará más adelante.
- Biblioteca de autenticación de Microsoft (MSAL) para iOS para autenticarse con Azure AD.
- Microsoft Graph SDK para objective C para realizar llamadas a Microsoft Graph.
- Sdk Graph modelos de Microsoft para objective C para objetos fuertemente typed que representan microsoft Graph recursos como usuarios o eventos.
Salga de Xcode.
Abra Terminal y cambie el directorio a la ubicación del proyecto GraphTutorial.
Ejecute el siguiente comando para crear un podfile.
pod init
Abra el podfile y agregue las siguientes líneas justo después de la
use_frameworks!
línea.pod 'MSAL', '~> 1.1.13' pod 'MSGraphClientSDK', ' ~> 1.0.0' pod 'MSGraphClientModels', '~> 1.3.0'
Guarde el podfile y, a continuación, ejecute el siguiente comando para instalar las dependencias.
pod install
Una vez completado el comando, abra el graphtutorial.xcworkspace recién creado en Xcode.
Diseñar la aplicación
En esta sección, crearás las vistas de la aplicación: una página de inicio de sesión, un navegador de barras de pestañas, una página de bienvenida y una página de calendario. También crearás una superposición de indicador de actividad.
Crear página de inicio de sesión
Expanda la carpeta GraphTutorial en Xcode y, a continuación, seleccione ViewController.swift.
En el Inspector de archivos, cambie el nombre del archivo a
SignInViewController.swift
.Abra SignInViewController.swift y reemplace su contenido por el siguiente código.
import UIKit class SignInViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } @IBAction func signIn() { self.performSegue(withIdentifier: "userSignedIn", sender: nil) } }
Abra Main.storyboard. Expanda Ver escena del controlador y, a continuación, seleccione Ver controlador.
Seleccione el Inspector de identidades y, a continuación, cambie el desplegable Clase a SignInViewController.
Seleccione la biblioteca y, a continuación, arrastre un botón al controlador de vista de inicio de sesión.
Con el botón seleccionado, seleccione el Inspector de atributos y cambie el Título del botón a
Sign In
.Con el botón seleccionado, selecciona el botón Alinear en la parte inferior del guión gráfico. Seleccione horizontalmente en contenedor y verticalmente en restricciones de contenedor, deje sus valores como 0 y, a continuación, seleccione Agregar 2 restricciones.
Seleccione el controlador de vista Iniciar sesión y, a continuación, seleccione el Inspector de conexiones.
En Acciones recibidas, arrastre el círculo sin rellenar junto a signIn al botón. Seleccione Retoco dentro en el menú emergente.
Crear barra de pestañas
Seleccione la biblioteca y, a continuación, arrastre un controlador de barra de pestañas al guión gráfico.
Seleccione el controlador de vista Iniciar sesión y, a continuación, seleccione el Inspector de conexiones.
En Segues desencadenados, arrastre el círculo no rellenado junto al manual al controlador de barra de pestañas en el guión gráfico. Seleccione Presentar modalmente en el menú emergente.
Seleccione el segue que acaba de agregar y, a continuación, seleccione el Inspector de atributos. Establezca el campo Identificador en y
userSignedIn
establezca Presentation en Pantalla completa.Seleccione la escena elemento 1 y, a continuación, seleccione el Inspector de conexiones.
En Segues desencadenados, arrastre el círculo no rellenado junto a manual al controlador de vista de inicio de sesión en el guión gráfico. Seleccione Presentar modalmente en el menú emergente.
Seleccione el segue que acaba de agregar y, a continuación, seleccione el Inspector de atributos. Establezca el campo Identificador en y
userSignedOut
establezca Presentation en Pantalla completa.
Crear página de bienvenida
Seleccione el archivo Assets.xcassets.
En el menú Editor, seleccione Agregar nuevo activo y, a continuación, Conjunto de imágenes.
Seleccione el nuevo activo Image y use el Inspector de atributos para establecer su nombre en
DefaultUserPhoto
.Agrega cualquier imagen que quieras que sirva como foto de perfil de usuario predeterminada.
Cree un nuevo archivo cocoa touch class en la carpeta GraphTutorial denominada
WelcomeViewController
. Elija UIViewController en la subclase del campo.Abra WelcomeViewController.swift y reemplace su contenido por el siguiente código.
import UIKit class WelcomeViewController: UIViewController { @IBOutlet var userProfilePhoto: UIImageView! @IBOutlet var userDisplayName: UILabel! @IBOutlet var userEmail: UILabel! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. // TEMPORARY self.userProfilePhoto.image = UIImage(imageLiteralResourceName: "DefaultUserPhoto") self.userDisplayName.text = "Default User" self.userEmail.text = "default@contoso.com" } @IBAction func signOut() { self.performSegue(withIdentifier: "userSignedOut", sender: nil) } }
Abra Main.storyboard. Seleccione la escena elemento 1 y, a continuación, seleccione el Inspector de identidades. Cambie el valor class a WelcomeViewController.
Mediante la biblioteca, agregue los siguientes elementos a la escena del elemento 1.
- Una vista de imagen
- Dos etiquetas
- Un botón
Con el Inspector de conexiones, realice las siguientes conexiones.
- Vincula la salida userDisplayName a la primera etiqueta.
- Vincula la salida userEmail a la segunda etiqueta.
- Vincula la salida userProfilePhoto a la vista de imagen.
- Vincule la acción signOut recibida al botón Touch Up Inside.
Seleccione la vista de imagen y, a continuación, seleccione el Inspector de tamaño.
Establezca width y height en 196.
Use el botón Alinear para agregar la restricción Horizontalmente en contenedor con un valor de 0.
Use el botón Agregar nuevas restricciones (junto al botón Alinear) para agregar las siguientes restricciones:
- Alinear arriba a: Caja fuerte área, valor: 0
- Espacio inferior a: Nombre para mostrar del usuario, valor: Estándar
- Alto, valor: 196
- Width, value: 196
Seleccione la primera etiqueta y, a continuación, use el botón Alinear para agregar la restricción Horizontalmente en contenedor con un valor de 0.
Use el botón Agregar nuevas restricciones para agregar las siguientes restricciones:
- Espacio superior a: Foto de perfil de usuario, valor: Estándar
- Espacio inferior a: Correo electrónico del usuario, valor: Estándar
Seleccione la segunda etiqueta y, a continuación, seleccione el Inspector de atributos.
Cambie el color a color gris oscuro y cambie la fuente a Sistema 12.0.
Use el botón Alinear para agregar la restricción Horizontalmente en contenedor con un valor de 0.
Use el botón Agregar nuevas restricciones para agregar las siguientes restricciones:
- Espacio superior a: Nombre para mostrar del usuario, valor: Estándar
- Espacio inferior a: Cerrar sesión, valor: 14
Seleccione el botón y, a continuación, seleccione el Inspector de atributos.
Cambie el título a
Sign Out
.Use el botón Alinear para agregar la restricción Horizontalmente en contenedor con un valor de 0.
Use el botón Agregar nuevas restricciones para agregar las siguientes restricciones:
- Espacio superior a: Correo electrónico del usuario, valor: 14
Seleccione el elemento de la barra de pestañas en la parte inferior de la escena y, a continuación, seleccione el Inspector de atributos. Cambie el título a
Me
.
La escena de bienvenida debe ser similar a esta una vez que haya terminado.
Crear página de calendario
Cree un nuevo archivo cocoa touch class en la carpeta GraphTutorial denominada
CalendarViewController
. Elija UIViewController en la subclase del campo.Abra CalendarViewController.swift y reemplace su contenido por el siguiente código.
import UIKit class CalendarViewController: UIViewController { @IBOutlet var calendarJSON: UITextView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. // TEMPORARY calendarJSON.text = "Calendar" calendarJSON.sizeToFit() } }
Abra Main.storyboard. Seleccione la escena del elemento 2 y, a continuación, seleccione el Inspector de identidades. Cambie el valor class a CalendarViewController.
Mediante la biblioteca, agregue una vista de texto a la escena del elemento 2.
Seleccione la vista de texto que acaba de agregar. En el menú Editor, elija Insertar en y, a continuación, Vista de desplazamiento.
Cambie el tamaño de la vista de desplazamiento y la vista de texto para tomar toda la pantalla.
Con el Inspector de conexiones, conecte la salida calendarJSON a la vista de texto.
Seleccione el elemento de la barra de pestañas en la parte inferior de la escena y, a continuación, seleccione el Inspector de atributos. Cambie el título a
Calendar
.En el menú Editor, seleccione Resolver problemas de diseño automático y, a continuación, seleccione Agregar restricciones que faltan debajo de Todas las vistas en el controlador de vista de calendario.
La escena del calendario debe ser similar a esta una vez que haya terminado.
Crear indicador de actividad
Cree un nuevo archivo cocoa touch class en la carpeta GraphTutorial denominada
SpinnerViewController
. Elija UIViewController en la subclase del campo.Abra SpinnerViewController.swift y reemplace su contenido por el siguiente código.
import UIKit class SpinnerViewController: UIViewController { var spinner = UIActivityIndicatorView(style: .large) override func loadView() { view = UIView() view.backgroundColor = UIColor(white: 0, alpha: 0.7) spinner.translatesAutoresizingMaskIntoConstraints = false spinner.startAnimating() view.addSubview(spinner) spinner.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true spinner.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true } public func start(container: UIViewController) { container.addChild(self) self.view.frame = container.view.frame container.view.addSubview(self.view) self.didMove(toParent: container) } public func stop() { self.willMove(toParent: nil) self.view.removeFromSuperview() self.removeFromParent() } }
Probar la aplicación
Guarda los cambios e inicia la aplicación. Debería poder moverse entre las pantallas con los botones Iniciar sesión y Cerrar sesión y la barra de pestañas.
Registrar la aplicación en el portal
En este ejercicio, creará una nueva aplicación nativa de Azure AD con el centro Azure Active Directory administración.
Abra un explorador y vaya al centro de administración de Azure Active Directory e inicie sesión con una cuenta personal (también conocida como: cuenta Microsoft) o una cuenta profesional o educativa.
Seleccione Azure Active Directory en el panel de navegación izquierdo y, a continuación, seleccione Registros de aplicaciones en Administrar.
Seleccione Nuevo registro. En la página Registrar una aplicación, establezca los valores siguientes.
- Establezca Nombre como
iOS Swift Graph Tutorial
. - Establezca Tipos de cuenta admitidos en Cuentas en cualquier directorio de organización y cuentas personales de Microsoft.
- Deje URI de redireccionamiento vacía.
- Establezca Nombre como
Seleccione Registrar. En la página Tutorial de swift Graph iOS, copie el valor del identificador de aplicación (cliente) y guárdelo, lo necesitará en el paso siguiente.
Seleccione Autenticación en Administrar. Seleccione Agregar una plataforma y, a continuación, iOS /macOS.
Escribe el id. de agrupación de la aplicación y selecciona Configurar y, a continuación, selecciona Listo.
Agregar autenticación de Azure AD
En este ejercicio, extenderá la aplicación desde el ejercicio anterior para admitir la autenticación con Azure AD. Esto es necesario para obtener el token de acceso OAuth necesario para llamar a Microsoft Graph. Para ello, integrará la Biblioteca de autenticación de Microsoft (MSAL) para iOS en la aplicación.
Cree un nuevo archivo de lista de propiedades en el proyecto GraphTutorial denominado AuthSettings.plist.
Agregue los siguientes elementos al archivo en el diccionario raíz.
Key Tipo Valor AppId
String El identificador de aplicación de Azure Portal GraphScopes
Matriz Tres valores de cadena: User.Read
MailboxSettings.Read
, yCalendars.ReadWrite
Importante
Si usas el control de código fuente como git, ahora sería un buen momento para excluir el archivo AuthSettings.plist del control de código fuente para evitar la pérdida involuntaria del identificador de la aplicación.
Implementar el inicio de sesión
En esta sección, configurará el proyecto para MSAL, creará una clase de administrador de autenticación y actualizará la aplicación para iniciar sesión y cerrar sesión.
Configurar el proyecto para MSAL
Agregue un nuevo grupo de llaves a las capacidades del proyecto.
- Seleccione el proyecto GraphTutorial y, a continuación, & funcionalidades.
- Seleccione + Funcionalidad y, a continuación, haga doble clic en Compartir cadena de teclas.
- Agregue un grupo de llaves con el valor
com.microsoft.adalcache
.
Control click Info.plist and select Open As, then Source Code.
Agregue lo siguiente dentro del
<dict>
elemento.<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>msauth.$(PRODUCT_BUNDLE_IDENTIFIER)</string> </array> </dict> </array> <key>LSApplicationQueriesSchemes</key> <array> <string>msauthv2</string> <string>msauthv3</string> </array>
Abra AppDelegate.swift y agregue la siguiente instrucción import en la parte superior del archivo.
import MSAL
Agregue la siguiente función a la clase
AppDelegate
.func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { guard let sourceApplication = options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String else { return false } return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: sourceApplication) }
Crear administrador de autenticación
Cree un nuevo archivo Swift en el proyecto GraphTutorial denominado AuthenticationManager.swift. Agregue el siguiente código al archivo.
import Foundation import MSAL import MSGraphClientSDK // Implement the MSAuthenticationProvider interface so // this class can be used as an auth provider for the Graph SDK class AuthenticationManager: NSObject, MSAuthenticationProvider { // Implement singleton pattern static let instance = AuthenticationManager() private let publicClient: MSALPublicClientApplication? private let appId: String private let graphScopes: Array<String> private override init() { // Get app ID and scopes from AuthSettings.plist let bundle = Bundle.main let authConfigPath = bundle.path(forResource: "AuthSettings", ofType: "plist")! let authConfig = NSDictionary(contentsOfFile: authConfigPath)! self.appId = authConfig["AppId"] as! String self.graphScopes = authConfig["GraphScopes"] as! Array<String> do { // Create the MSAL client try self.publicClient = MSALPublicClientApplication(clientId: self.appId) } catch { print("Error creating MSAL public client: \(error)") self.publicClient = nil } } // Required function for the MSAuthenticationProvider interface func getAccessToken(for authProviderOptions: MSAuthenticationProviderOptions!, andCompletion completion: ((String?, Error?) -> Void)!) { getTokenSilently(completion: completion) } public func getTokenInteractively(parentView: UIViewController, completion: @escaping(_ accessToken: String?, Error?) -> Void) { let webParameters = MSALWebviewParameters(authPresentationViewController: parentView) let interactiveParameters = MSALInteractiveTokenParameters(scopes: self.graphScopes, webviewParameters: webParameters) interactiveParameters.promptType = MSALPromptType.selectAccount // Call acquireToken to open a browser so the user can sign in publicClient?.acquireToken(with: interactiveParameters, completionBlock: { (result: MSALResult?, error: Error?) in guard let tokenResult = result, error == nil else { print("Error getting token interactively: \(String(describing: error))") completion(nil, error) return } print("Got token interactively: \(tokenResult.accessToken)") completion(tokenResult.accessToken, nil) }) } public func getTokenSilently(completion: @escaping(_ accessToken: String?, Error?) -> Void) { // Check if there is an account in the cache var userAccount: MSALAccount? do { userAccount = try publicClient?.allAccounts().first } catch { print("Error getting account: \(error)") } if (userAccount != nil) { // Attempt to get token silently let silentParameters = MSALSilentTokenParameters(scopes: self.graphScopes, account: userAccount!) publicClient?.acquireTokenSilent(with: silentParameters, completionBlock: { (result: MSALResult?, error: Error?) in guard let tokenResult = result, error == nil else { print("Error getting token silently: \(String(describing: error))") completion(nil, error) return } print("Got token silently: \(tokenResult.accessToken)") completion(tokenResult.accessToken, nil) }) } else { print("No account in cache") completion(nil, NSError(domain: "AuthenticationManager", code: MSALError.interactionRequired.rawValue, userInfo: nil)) } } public func signOut() -> Void { do { // Remove all accounts from the cache let accounts = try publicClient?.allAccounts() try accounts!.forEach({ (account: MSALAccount) in try publicClient?.remove(account) }) } catch { print("Sign out error: \(String(describing: error))") } } }
Agregar inicio de sesión y salida
Abra SignInViewController.swift y reemplace su contenido por el siguiente código.
import UIKit class SignInViewController: UIViewController { private let spinner = SpinnerViewController() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. // See if a user is already signed in spinner.start(container: self) AuthenticationManager.instance.getTokenSilently { (token: String?, error: Error?) in DispatchQueue.main.async { self.spinner.stop() guard let _ = token, error == nil else { // If there is no token or if there's an error, // no user is signed in, so stay here return } // Since we got a token, a user is signed in // Go to welcome page self.performSegue(withIdentifier: "userSignedIn", sender: nil) } } } @IBAction func signIn() { spinner.start(container: self) // Do an interactive sign in AuthenticationManager.instance.getTokenInteractively(parentView: self) { (token: String?, error: Error?) in DispatchQueue.main.async { self.spinner.stop() guard let _ = token, error == nil else { // Show the error and stay on the sign-in page let alert = UIAlertController(title: "Error signing in", message: error.debugDescription, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) self.present(alert, animated: true) return } // Signed in successfully // Go to welcome page self.performSegue(withIdentifier: "userSignedIn", sender: nil) } } } }
Abra WelcomeViewController.swift y reemplace la función
signOut
existente por lo siguiente.@IBAction func signOut() { AuthenticationManager.instance.signOut() self.performSegue(withIdentifier: "userSignedOut", sender: nil) }
Guarde los cambios y reinicie la aplicación en Simulador.
Si inicias sesión en la aplicación, deberías ver un token de acceso que se muestra en la ventana de salida en Xcode.
Obtener detalles del usuario
En esta sección, creará una clase auxiliar para contener todas las llamadas a Microsoft Graph y actualizar la para usar esta nueva clase para obtener el usuario que ha WelcomeViewController
iniciado sesión.
Cree un nuevo archivo Swift en el proyecto GraphTutorial denominado GraphManager.swift. Agregue el siguiente código al archivo.
import Foundation import MSGraphClientSDK import MSGraphClientModels class GraphManager { // Implement singleton pattern static let instance = GraphManager() private let client: MSHTTPClient? public var userTimeZone: String private init() { client = MSClientFactory.createHTTPClient(with: AuthenticationManager.instance) userTimeZone = "UTC" } public func getMe(completion: @escaping(MSGraphUser?, Error?) -> Void) { // GET /me let select = "$select=displayName,mail,mailboxSettings,userPrincipalName" let meRequest = NSMutableURLRequest(url: URL(string: "\(MSGraphBaseURL)/me?\(select)")!) let meDataTask = MSURLSessionDataTask(request: meRequest, client: self.client, completion: { (data: Data?, response: URLResponse?, graphError: Error?) in guard let meData = data, graphError == nil else { completion(nil, graphError) return } do { // Deserialize response as a user let user = try MSGraphUser(data: meData) completion(user, nil) } catch { completion(nil, error) } }) // Execute the request meDataTask?.execute() } }
Abra WelcomeViewController.swift y agregue la siguiente
import
instrucción en la parte superior del archivo.import MSGraphClientModels
Agregue la siguiente propiedad a la clase
WelcomeViewController
.private let spinner = SpinnerViewController()
Reemplace el existente
viewDidLoad
por el código siguiente.override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. self.spinner.start(container: self) // Get the signed-in user self.userProfilePhoto.image = UIImage(imageLiteralResourceName: "DefaultUserPhoto") GraphManager.instance.getMe { (user: MSGraphUser?, error: Error?) in DispatchQueue.main.async { self.spinner.stop() guard let currentUser = user, error == nil else { print("Error getting user: \(String(describing: error))") return } // Set display name self.userDisplayName.text = currentUser.displayName ?? "Mysterious Stranger" self.userDisplayName.sizeToFit() // AAD users have email in the mail attribute // Personal accounts have email in the userPrincipalName attribute self.userEmail.text = currentUser.mail ?? currentUser.userPrincipalName ?? "" self.userEmail.sizeToFit() // Save the user's time zone GraphManager.instance.userTimeZone = currentUser.mailboxSettings?.timeZone ?? "UTC" } } }
Si guardas los cambios y reinicias la aplicación ahora, después de iniciar sesión, la interfaz de usuario se actualiza con el nombre para mostrar y la dirección de correo electrónico del usuario.
Obtener una vista de calendario
En este ejercicio, incorporará el Graph Microsoft en la aplicación. Para esta aplicación, usará el SDK de Microsoft Graph para el objetivo C para realizar llamadas a Microsoft Graph.
Obtener eventos del calendario desde Outlook
En esta sección, extenderá la clase para agregar una función para obtener los eventos del usuario de la semana actual y actualizar para usar GraphManager
CalendarViewController
estas nuevas funciones.
Abra GraphManager.swift y agregue el siguiente método a la
GraphManager
clase.public func getCalendarView(viewStart: String, viewEnd: String, completion: @escaping(Data?, Error?) -> Void) { // GET /me/calendarview // Set start and end of the view let start = "startDateTime=\(viewStart)" let end = "endDateTime=\(viewEnd)" // Only return these fields in results let select = "$select=subject,organizer,start,end" // Sort results by when they were created, newest first let orderBy = "$orderby=start/dateTime" // Request at most 25 results let top = "$top=25" let eventsRequest = NSMutableURLRequest(url: URL(string: "\(MSGraphBaseURL)/me/calendarview?\(start)&\(end)&\(select)&\(orderBy)&\(top)")!) // Add the Prefer: outlook.timezone header to get start and end times // in user's time zone eventsRequest.addValue("outlook.timezone=\"\(self.userTimeZone)\"", forHTTPHeaderField: "Prefer") let eventsDataTask = MSURLSessionDataTask(request: eventsRequest, client: self.client, completion: { (data: Data?, response: URLResponse?, graphError: Error?) in guard let eventsData = data, graphError == nil else { completion(nil, graphError) return } // TEMPORARY completion(eventsData, nil) }) // Execute the request eventsDataTask?.execute() }
Nota
Tenga en cuenta lo que está
getCalendarView
haciendo el código.- La dirección URL a la que se llamará es
/v1.0/me/calendarview
.- Los
startDateTime
parámetros y de consulta definen el inicio y el final de la vista deendDateTime
calendario. - El
select
parámetro de consulta limita los campos devueltos para cada evento a solo aquellos que la vista usará realmente. - El
orderby
parámetro query ordena los resultados por hora de inicio. - El
top
parámetro de consulta solicita 25 resultados por página. - el encabezado hace que el Graph Microsoft devuelva las horas de inicio y finalización de cada evento en la
Prefer: outlook.timezone
zona horaria del usuario.
- Los
- La dirección URL a la que se llamará es
Cree un nuevo archivo Swift en el proyecto GraphTutorial denominado GraphToIana.swift. Agregue el siguiente código al archivo.
import Foundation // Basic lookup for mapping Windows time zone identifiers to // IANA identifiers // Mappings taken from // https://github.com/unicode-org/cldr/blob/master/common/supplemental/windowsZones.xml class GraphToIana { private static let timeZoneMap = [ "Dateline Standard Time" : "Etc/GMT+12", "UTC-11" : "Etc/GMT+11", "Aleutian Standard Time" : "America/Adak", "Hawaiian Standard Time" : "Pacific/Honolulu", "Marquesas Standard Time" : "Pacific/Marquesas", "Alaskan Standard Time" : "America/Anchorage", "UTC-09" : "Etc/GMT+9", "Pacific Standard Time (Mexico)" : "America/Tijuana", "UTC-08" : "Etc/GMT+8", "Pacific Standard Time" : "America/Los_Angeles", "US Mountain Standard Time" : "America/Phoenix", "Mountain Standard Time (Mexico)" : "America/Chihuahua", "Mountain Standard Time" : "America/Denver", "Central America Standard Time" : "America/Guatemala", "Central Standard Time" : "America/Chicago", "Easter Island Standard Time" : "Pacific/Easter", "Central Standard Time (Mexico)" : "America/Mexico_City", "Canada Central Standard Time" : "America/Regina", "SA Pacific Standard Time" : "America/Bogota", "Eastern Standard Time (Mexico)" : "America/Cancun", "Eastern Standard Time" : "America/New_York", "Haiti Standard Time" : "America/Port-au-Prince", "Cuba Standard Time" : "America/Havana", "US Eastern Standard Time" : "America/Indianapolis", "Turks And Caicos Standard Time" : "America/Grand_Turk", "Paraguay Standard Time" : "America/Asuncion", "Atlantic Standard Time" : "America/Halifax", "Venezuela Standard Time" : "America/Caracas", "Central Brazilian Standard Time" : "America/Cuiaba", "SA Western Standard Time" : "America/La_Paz", "Pacific SA Standard Time" : "America/Santiago", "Newfoundland Standard Time" : "America/St_Johns", "Tocantins Standard Time" : "America/Araguaina", "E. South America Standard Time" : "America/Sao_Paulo", "SA Eastern Standard Time" : "America/Cayenne", "Argentina Standard Time" : "America/Buenos_Aires", "Greenland Standard Time" : "America/Godthab", "Montevideo Standard Time" : "America/Montevideo", "Magallanes Standard Time" : "America/Punta_Arenas", "Saint Pierre Standard Time" : "America/Miquelon", "Bahia Standard Time" : "America/Bahia", "UTC-02" : "Etc/GMT+2", "Azores Standard Time" : "Atlantic/Azores", "Cape Verde Standard Time" : "Atlantic/Cape_Verde", "UTC" : "Etc/GMT", "GMT Standard Time" : "Europe/London", "Greenwich Standard Time" : "Atlantic/Reykjavik", "Sao Tome Standard Time" : "Africa/Sao_Tome", "Morocco Standard Time" : "Africa/Casablanca", "W. Europe Standard Time" : "Europe/Berlin", "Central Europe Standard Time" : "Europe/Budapest", "Romance Standard Time" : "Europe/Paris", "Central European Standard Time" : "Europe/Warsaw", "W. Central Africa Standard Time" : "Africa/Lagos", "Jordan Standard Time" : "Asia/Amman", "GTB Standard Time" : "Europe/Bucharest", "Middle East Standard Time" : "Asia/Beirut", "Egypt Standard Time" : "Africa/Cairo", "E. Europe Standard Time" : "Europe/Chisinau", "Syria Standard Time" : "Asia/Damascus", "West Bank Standard Time" : "Asia/Hebron", "South Africa Standard Time" : "Africa/Johannesburg", "FLE Standard Time" : "Europe/Kiev", "Israel Standard Time" : "Asia/Jerusalem", "Kaliningrad Standard Time" : "Europe/Kaliningrad", "Sudan Standard Time" : "Africa/Khartoum", "Libya Standard Time" : "Africa/Tripoli", "Namibia Standard Time" : "Africa/Windhoek", "Arabic Standard Time" : "Asia/Baghdad", "Turkey Standard Time" : "Europe/Istanbul", "Arab Standard Time" : "Asia/Riyadh", "Belarus Standard Time" : "Europe/Minsk", "Russian Standard Time" : "Europe/Moscow", "E. Africa Standard Time" : "Africa/Nairobi", "Iran Standard Time" : "Asia/Tehran", "Arabian Standard Time" : "Asia/Dubai", "Astrakhan Standard Time" : "Europe/Astrakhan", "Azerbaijan Standard Time" : "Asia/Baku", "Russia Time Zone 3" : "Europe/Samara", "Mauritius Standard Time" : "Indian/Mauritius", "Saratov Standard Time" : "Europe/Saratov", "Georgian Standard Time" : "Asia/Tbilisi", "Volgograd Standard Time" : "Europe/Volgograd", "Caucasus Standard Time" : "Asia/Yerevan", "Afghanistan Standard Time" : "Asia/Kabul", "West Asia Standard Time" : "Asia/Tashkent", "Ekaterinburg Standard Time" : "Asia/Yekaterinburg", "Pakistan Standard Time" : "Asia/Karachi", "Qyzylorda Standard Time" : "Asia/Qyzylorda", "India Standard Time" : "Asia/Calcutta", "Sri Lanka Standard Time" : "Asia/Colombo", "Nepal Standard Time" : "Asia/Katmandu", "Central Asia Standard Time" : "Asia/Almaty", "Bangladesh Standard Time" : "Asia/Dhaka", "Omsk Standard Time" : "Asia/Omsk", "Myanmar Standard Time" : "Asia/Rangoon", "SE Asia Standard Time" : "Asia/Bangkok", "Altai Standard Time" : "Asia/Barnaul", "W. Mongolia Standard Time" : "Asia/Hovd", "North Asia Standard Time" : "Asia/Krasnoyarsk", "N. Central Asia Standard Time" : "Asia/Novosibirsk", "Tomsk Standard Time" : "Asia/Tomsk", "China Standard Time" : "Asia/Shanghai", "North Asia East Standard Time" : "Asia/Irkutsk", "Singapore Standard Time" : "Asia/Singapore", "W. Australia Standard Time" : "Australia/Perth", "Taipei Standard Time" : "Asia/Taipei", "Ulaanbaatar Standard Time" : "Asia/Ulaanbaatar", "Aus Central W. Standard Time" : "Australia/Eucla", "Transbaikal Standard Time" : "Asia/Chita", "Tokyo Standard Time" : "Asia/Tokyo", "North Korea Standard Time" : "Asia/Pyongyang", "Korea Standard Time" : "Asia/Seoul", "Yakutsk Standard Time" : "Asia/Yakutsk", "Cen. Australia Standard Time" : "Australia/Adelaide", "AUS Central Standard Time" : "Australia/Darwin", "E. Australia Standard Time" : "Australia/Brisbane", "AUS Eastern Standard Time" : "Australia/Sydney", "West Pacific Standard Time" : "Pacific/Port_Moresby", "Tasmania Standard Time" : "Australia/Hobart", "Vladivostok Standard Time" : "Asia/Vladivostok", "Lord Howe Standard Time" : "Australia/Lord_Howe", "Bougainville Standard Time" : "Pacific/Bougainville", "Russia Time Zone 10" : "Asia/Srednekolymsk", "Magadan Standard Time" : "Asia/Magadan", "Norfolk Standard Time" : "Pacific/Norfolk", "Sakhalin Standard Time" : "Asia/Sakhalin", "Central Pacific Standard Time" : "Pacific/Guadalcanal", "Russia Time Zone 11" : "Asia/Kamchatka", "New Zealand Standard Time" : "Pacific/Auckland", "UTC+12" : "Etc/GMT-12", "Fiji Standard Time" : "Pacific/Fiji", "Chatham Islands Standard Time" : "Pacific/Chatham", "UTC+13" : "Etc/GMT-13", "Tonga Standard Time" : "Pacific/Tongatapu", "Samoa Standard Time" : "Pacific/Apia", "Line Islands Standard Time" : "Pacific/Kiritimati" ] public static func getIanaIdentifier(graphIdentifer: String) -> String { // If a mapping was not found, assume the value passed // was already an IANA identifier return timeZoneMap[graphIdentifer] ?? graphIdentifer } }
Esto hace una búsqueda sencilla para buscar un identificador de zona horaria IANA en función del nombre de zona horaria devuelto por Microsoft Graph.
Abra CalendarViewController.swift y reemplace todo su contenido por el siguiente código.
import UIKit import MSGraphClientModels class CalendarViewController: UIViewController { @IBOutlet var calendarJSON: UITextView! private let spinner = SpinnerViewController() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. self.spinner.start(container: self) // Calculate the start and end of the current week let timeZone = GraphToIana.getIanaIdentifier(graphIdentifer: GraphManager.instance.userTimeZone) let now = Date() var calendar = Calendar(identifier: .gregorian) calendar.timeZone = TimeZone(identifier: timeZone)! let startOfWeek = calendar.dateComponents([.calendar, .yearForWeekOfYear, .weekOfYear], from: now).date! let endOfWeek = calendar.date(byAdding: .day, value: 7, to: startOfWeek)! // Convert start and end to ISO 8601 strings let isoFormatter = ISO8601DateFormatter() let viewStart = isoFormatter.string(from: startOfWeek) let viewEnd = isoFormatter.string(from: endOfWeek) GraphManager.instance.getCalendarView(viewStart: viewStart, viewEnd: viewEnd) { (data: Data?, error: Error?) in DispatchQueue.main.async { self.spinner.stop() // TEMPORARY guard let eventsData = data, error == nil else { self.calendarJSON.text = error.debugDescription return } let jsonString = String(data: eventsData, encoding: .utf8) self.calendarJSON.text = jsonString self.calendarJSON.sizeToFit() } } } }
Ahora puedes ejecutar la aplicación, iniciar sesión y pulsar el elemento de navegación Calendario en el menú. Debería ver un volcado JSON de los eventos en la aplicación.
Mostrar los resultados
Ahora puede reemplazar el volcado JSON por algo para mostrar los resultados de una manera fácil de usar. En esta sección, modificará la función para devolver objetos fuertemente especificados y modificará para usar una vista de tabla getCalendarView
CalendarViewController
para representar los eventos.
Abra GraphManager.swift. Reemplace la función
getCalendarView
existente por lo siguiente.public func getCalendarView(viewStart: String, viewEnd: String, completion: @escaping([MSGraphEvent]?, Error?) -> Void) { // GET /me/calendarview // Set start and end of the view let start = "startDateTime=\(viewStart)" let end = "endDateTime=\(viewEnd)" // Only return these fields in results let select = "$select=subject,organizer,start,end" // Sort results by when they were created, newest first let orderBy = "$orderby=start/dateTime" // Request at most 25 results let top = "$top=25" let eventsRequest = NSMutableURLRequest(url: URL(string: "\(MSGraphBaseURL)/me/calendarview?\(start)&\(end)&\(select)&\(orderBy)&\(top)")!) // Add the Prefer: outlook.timezone header to get start and end times // in user's time zone eventsRequest.addValue("outlook.timezone=\"\(self.userTimeZone)\"", forHTTPHeaderField: "Prefer") let eventsDataTask = MSURLSessionDataTask(request: eventsRequest, client: self.client, completion: { (data: Data?, response: URLResponse?, graphError: Error?) in guard let eventsData = data, graphError == nil else { completion(nil, graphError) return } do { // Deserialize response as events collection let eventsCollection = try MSCollection(data: eventsData) var eventArray: [MSGraphEvent] = [] eventsCollection.value.forEach({ (rawEvent: Any) in // Convert JSON to a dictionary guard let eventDict = rawEvent as? [String: Any] else { return } // Deserialize event from the dictionary let event = MSGraphEvent(dictionary: eventDict)! eventArray.append(event) }) // Return the array completion(eventArray, nil) } catch { completion(nil, error) } }) // Execute the request eventsDataTask?.execute() }
Cree un nuevo archivo de clase táctil de Cocoa en el proyecto GraphTutorial denominado
CalendarTableViewController.swift
. Elija UITableViewController en la subclase del campo.Abra CalendarTableViewController.swift y reemplace su contenido por lo siguiente.
import UIKit import MSGraphClientModels class CalendarTableViewController: UITableViewController { private let tableCellIdentifier = "EventCell" private var events: [MSGraphEvent]? override func viewDidLoad() { super.viewDidLoad() tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 100 } // Number of sections, always 1 override func numberOfSections(in tableView: UITableView) -> Int { return 1 } // Return the number of events in the table override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return events?.count ?? 0 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: tableCellIdentifier, for: indexPath) as! CalendarTableViewCell // Get the event that corresponds to the row let event = events?[indexPath.row] // Configure the cell cell.subject = event?.subject cell.organizer = event?.organizer?.emailAddress?.name // Build a duration string let duration = "\(self.formatGraphDateTime(dateTime: event?.start)) to \(self.formatGraphDateTime(dateTime: event?.end))" cell.duration = duration return cell } private func formatGraphDateTime(dateTime: MSGraphDateTimeTimeZone?) -> String { guard let graphDateTime = dateTime else { return "" } // Create a formatter to parse Graph's date format let isoFormatter = DateFormatter() isoFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS" let date = isoFormatter.date(from: graphDateTime.dateTime) // Output like 5/5/2019, 2:00 PM let dateFormatter = DateFormatter() dateFormatter.dateStyle = .short dateFormatter.timeStyle = .short return dateFormatter.string(from: date!) } public func setEvents(events: [MSGraphEvent]?) -> Void { self.events = events self.tableView.reloadData() } }
Cree un nuevo archivo de clase táctil de Cocoa en el proyecto GraphTutorial denominado
CalendarTableViewCell.swift
. Elija UITableViewCell en la subclase del campo.Abra CalendarTableViewCell.swift y agregue las siguientes propiedades a la
CalendarTableViewCell
clase.@IBOutlet var subjectLabel: UILabel! @IBOutlet var organizerLabel: UILabel! @IBOutlet var durationLabel: UILabel! var subject: String? { didSet { subjectLabel.text = subject } } var organizer: String? { didSet { organizerLabel.text = organizer } } var duration: String? { didSet { durationLabel.text = duration } }
Abra Main.storyboard y busque la escena del calendario. Elimine la vista de desplazamiento de la vista raíz.
Con la biblioteca, agregue una barra de navegación a la parte superior de la vista.
Haga doble clic en el título de la barra de navegación y actualíquelo a
Calendar
.Mediante la biblioteca, agregue un elemento de botón de barra al lado derecho de la barra de navegación.
Seleccione el nuevo botón de barra y, a continuación, seleccione el Inspector de atributos. Cambiar imagen a más.
Agregue una vista contenedora desde la biblioteca a la vista debajo de la barra de navegación. Cambie el tamaño de la vista contenedora para tomar todo el espacio restante de la vista.
Establezca las restricciones en la barra de navegación y la vista contenedora de la siguiente manera.
- Barra de navegación
- Restricción Add: Height, value: 44
- Agregar restricción: espacio inicial a Caja fuerte area, valor: 0
- Agregar restricción: espacio final a Caja fuerte area, valor: 0
- Agregar restricción: Espacio superior a Caja fuerte área, valor: 0
- Vista contenedora
- Agregar restricción: espacio inicial a Caja fuerte area, valor: 0
- Agregar restricción: espacio final a Caja fuerte area, valor: 0
- Agregar restricción: Espacio superior a la parte inferior de la barra de navegación, valor: 0
- Restricción Agregar: espacio inferior a Caja fuerte Area, value: 0
- Barra de navegación
Busque el segundo controlador de vista agregado al guión gráfico cuando agregó la vista contenedora. Se conecta a la escena del calendario mediante un segue de inserción. Seleccione este controlador y use el Inspector de identidades para cambiar Clase a CalendarTableViewController.
Elimine la vista del controlador de vista de tabla de calendario.
Agregue una vista de tabla de la biblioteca al controlador de vista de tabla de calendario.
Seleccione la vista de tabla y, a continuación, seleccione el Inspector de atributos. Establecer celdas prototipo en 1.
Arrastre el borde inferior de la celda prototipo para darle un área más grande con la que trabajar.
Use la biblioteca para agregar tres etiquetas a la celda prototipo.
Seleccione la celda prototipo y, a continuación, seleccione el Inspector de identidades. Cambiar clase a CalendarTableViewCell.
Seleccione el Inspector de atributos y establezca Identifier en
EventCell
.Con eventcell seleccionado, seleccione el Inspector de conexiones y conecte , y a las etiquetas que agregó a la celda en
durationLabel
elorganizerLabel
subjectLabel
guión gráfico.Establezca las propiedades y restricciones de las tres etiquetas de la siguiente manera.
- Etiqueta de sujeto
- Agregar restricción: Espacio inicial a margen inicial de la vista de contenido, valor: 0
- Agregar restricción: espacio final a margen final de la vista de contenido, valor: 0
- Agregar restricción: Espacio superior a margen superior de la vista de contenido, valor: 0
- Etiqueta de organizador
- Fuente: System 12.0
- Restricción Add: Height, value: 15
- Agregar restricción: Espacio inicial a margen inicial de la vista de contenido, valor: 0
- Agregar restricción: espacio final a margen final de la vista de contenido, valor: 0
- Restricción Agregar: Espacio superior a La parte inferior de la etiqueta del sujeto, valor: Estándar
- Etiqueta de duración
- Fuente: System 12.0
- Color: color gris oscuro
- Restricción Add: Height, value: 15
- Agregar restricción: Espacio inicial a margen inicial de la vista de contenido, valor: 0
- Agregar restricción: espacio final a margen final de la vista de contenido, valor: 0
- Restricción Agregar: Espacio superior a La parte inferior de la etiqueta del organizador, valor: Estándar
- Restricción agregar: espacio inferior a la vista de contenido Margen inferior, valor: 0
- Etiqueta de sujeto
Seleccione eventcell y, a continuación, seleccione el Inspector de tamaño. Habilitar Automático para altura de fila.
Abra CalendarViewController.swift y reemplace su contenido por el siguiente código.
import UIKit import MSGraphClientModels class CalendarViewController: UIViewController { private let spinner = SpinnerViewController() private var tableViewController: CalendarTableViewController? override func viewDidLoad() { super.viewDidLoad() self.spinner.start(container: self) // Calculate the start and end of the current week let timeZone = GraphToIana.getIanaIdentifier(graphIdentifer: GraphManager.instance.userTimeZone) let now = Date() var calendar = Calendar(identifier: .gregorian) calendar.timeZone = TimeZone(identifier: timeZone)! let startOfWeek = calendar.dateComponents([.calendar, .yearForWeekOfYear, .weekOfYear], from: now).date! let endOfWeek = calendar.date(byAdding: .day, value: 7, to: startOfWeek)! // Convert start and end to ISO 8601 strings let isoFormatter = ISO8601DateFormatter() let viewStart = isoFormatter.string(from: startOfWeek) let viewEnd = isoFormatter.string(from: endOfWeek) GraphManager.instance.getCalendarView(viewStart: viewStart, viewEnd: viewEnd) { (eventArray: [MSGraphEvent]?, error: Error?) in DispatchQueue.main.async { self.spinner.stop() guard let events = eventArray, error == nil else { // Show the error let alert = UIAlertController(title: "Error getting events", message: error.debugDescription, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) self.present(alert, animated: true) return } self.tableViewController?.setEvents(events: events) } } } internal override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Save reference to the contained table view if segue.destination is CalendarTableViewController { self.tableViewController = segue.destination as? CalendarTableViewController } } @IBAction func showNewEventForm() { self.performSegue(withIdentifier: "showEventForm", sender: self) } }
Ejecuta la aplicación, inicia sesión y pulsa la pestaña Calendario. Debería ver la lista de eventos.
Crear un nuevo evento
En esta sección, agregará la capacidad de crear eventos en el calendario del usuario.
Abra GraphManager.swift y agregue la siguiente función para crear un nuevo evento en el calendario del usuario.
public func createEvent(subject: String, start: Date, end: Date, attendees: [Substring]?, body: String?, completion: @escaping(MSGraphEvent?, Error?) -> Void) { let isoFormatter = DateFormatter() isoFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" // Create a dictionary to represent the event // Current version of the Graph SDK models don't serialize properly // see https://github.com/microsoftgraph/msgraph-sdk-objc-models/issues/27 var newEventDict: [String: Any] = [ "subject": subject, "start": [ "dateTime": isoFormatter.string(from: start), "timeZone": self.userTimeZone ], "end": [ "dateTime": isoFormatter.string(from: end), "timeZone": self.userTimeZone ] ] if attendees?.count ?? 0 > 0 { var attendeeArray: [Any] = [] for attendee in attendees! { let attendeeDict: [String: Any] = [ "type": "required", "emailAddress": [ "address": String(attendee) ] ] attendeeArray.append(attendeeDict) } newEventDict["attendees"] = attendeeArray } if !(body?.isEmpty ?? false) { newEventDict["body"] = [ "content": body, "contentType": "text" ] } let eventData = try? JSONSerialization.data(withJSONObject: newEventDict) let createEventRequest = NSMutableURLRequest(url: URL(string: "\(MSGraphBaseURL)/me/events")!) createEventRequest.httpMethod = "POST" createEventRequest.httpBody = eventData createEventRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") let createEventTask = MSURLSessionDataTask(request: createEventRequest, client: self.client, completion: { (data: Data?, response: URLResponse?, graphError: Error?) in guard let eventData = data, graphError == nil else { completion(nil, graphError) return } do { // Deserialize response as event let returnedEvent = try MSGraphEvent(data: eventData) // Return the event completion(returnedEvent, nil) } catch { completion(nil, error) } }) // Execute the task createEventTask?.execute() }
Cree un nuevo archivo cocoa touch class en la carpeta GraphTutorial denominada
NewEventViewController
. Elija UIViewController en la subclase del campo.Abra NewEventViewController.swift y reemplace su contenido por lo siguiente.
import UIKit import MSGraphClientModels class NewEventViewController: UIViewController { @IBOutlet var subject: UITextField! @IBOutlet var attendees: UITextField! @IBOutlet var start: UIDatePicker! @IBOutlet var end: UIDatePicker! @IBOutlet var body: UITextView! private let spinner = SpinnerViewController() override func viewDidLoad() { super.viewDidLoad() // Add border around text view let borderColor : UIColor = UIColor(red: 0.85, green: 0.85, blue: 0.85, alpha: 1.0) body.layer.borderWidth = 0.5 body.layer.borderColor = borderColor.cgColor body.layer.cornerRadius = 5.0 // Set start picker to the next closest half-hour let now = Date() let calendar = Calendar.current let components = calendar.dateComponents([.minute], from:now) let offset = 30 - (components.minute! % 30) let start = calendar.date(byAdding: .minute, value: offset, to: now) self.start.date = start! // Set end picker to start + 30 min let end = calendar.date(byAdding: .minute, value: 30, to: start!) self.end.date = end! } @IBAction func createEvent() { self.spinner.start(container: self) // Do create let subject = self.subject.text ?? "" let attendees = self.attendees.text?.split(separator: ";") let start = self.start.date let end = self.end.date let body = self.body.text ?? "" GraphManager.instance.createEvent(subject: subject, start: start, end: end, attendees: attendees, body: body) { (event: MSGraphEvent?, error: Error?) in DispatchQueue.main.async { self.spinner.stop() guard let _ = event, error == nil else { // Show the error let alert = UIAlertController(title: "Error creating event", message: error.debugDescription, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) self.present(alert, animated: true) return } let alert = UIAlertController(title: "Success", message: "Event created", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action: UIAlertAction?) in self.dismiss(animated: true, completion: nil) })) self.present(alert, animated: true) } } } @IBAction func cancel() { self.dismiss(animated: true, completion: nil) } }
Abra Main.storyboard. Use la biblioteca para arrastrar un controlador de vista al guión gráfico.
Mediante la biblioteca, agregue una barra de navegación al controlador de vista.
Haga doble clic en el título de la barra de navegación y actualíquelo a
New Event
.Con la biblioteca, agregue un elemento de botón de barra al lado izquierdo de la barra de navegación.
Seleccione el nuevo botón de barra y, a continuación, seleccione el Inspector de atributos. Cambie Title a
Cancel
.Mediante la biblioteca, agregue un elemento de botón de barra al lado derecho de la barra de navegación.
Seleccione el nuevo botón de barra y, a continuación, seleccione el Inspector de atributos. Cambie Title a
Create
.Seleccione el controlador de vista y, a continuación, seleccione el Inspector de identidad. Cambie clase a NewEventViewController.
Agregue los siguientes controles de la biblioteca a la vista.
- Agregue una etiqueta debajo de la barra de navegación. Establezca su texto en
Subject
. - Agregue un campo de texto bajo la etiqueta. Establezca su atributo Placeholder en
Subject
. - Agregue una etiqueta bajo el campo de texto. Establezca su texto en
Attendees
. - Agregue un campo de texto bajo la etiqueta. Establezca su atributo Placeholder en
Separate multiple entries with ;
. - Agregue una etiqueta bajo el campo de texto. Establezca su texto en
Start
. - Agregue un selector de fecha bajo la etiqueta. Establece su estilo preferido en Compacto, su intervalo en 15 minutos y su altura en 35.
- Agregue una etiqueta en el selector de fecha. Establezca su texto en
End
. - Agregue un selector de fecha bajo la etiqueta. Establece su estilo preferido en Compacto, su intervalo en 15 minutos y su altura en 35.
- Agregue una vista de texto en el selector de fecha.
- Agregue una etiqueta debajo de la barra de navegación. Establezca su texto en
Seleccione el nuevo controlador de vista de eventos y use el Inspector de conexión para realizar las siguientes conexiones.
- Conectar la acción cancelar recibida al botón Cancelar barra.
- Conectar la acción createEvent recibida en el botón Crear barra.
- Conectar salida del asunto al primer campo de texto.
- Conectar la salida de los asistentes al segundo campo de texto.
- Conectar la salida de inicio al primer selector de fecha.
- Conectar la salida final al segundo selector de fechas.
- Conectar la salida del cuerpo a la vista de texto.
Agregue las siguientes restricciones.
- Barra de navegación
- Espacio inicial al Caja fuerte, valor: 0
- Espacio final a Caja fuerte area, valor: 0
- Espacio superior para Caja fuerte area, valor: 0
- Alto, valor: 44
- Etiqueta de sujeto
- Espacio inicial a Margen de vista, valor: 0
- Espacio final a Margen de vista, valor: 0
- Espacio superior a barra de navegación, valor: 20
- Campo texto del asunto
- Espacio inicial a Margen de vista, valor: 0
- Espacio final a Margen de vista, valor: 0
- Espacio superior a Etiqueta de sujeto, valor: Estándar
- Etiqueta de asistentes
- Espacio inicial a Margen de vista, valor: 0
- Espacio final a Margen de vista, valor: 0
- Espacio superior al campo texto del sujeto, valor: Estándar
- Campo de texto de los asistentes
- Espacio inicial a Margen de vista, valor: 0
- Espacio final a Margen de vista, valor: 0
- Espacio superior a Etiqueta de asistentes, valor: Estándar
- Etiqueta de inicio
- Espacio inicial a Margen de vista, valor: 0
- Espacio final a Margen de vista, valor: 0
- Espacio superior al campo texto del sujeto, valor: Estándar
- Selector de fecha de inicio
- Espacio inicial a Margen de vista, valor: 0
- Espacio final a Margen de vista, valor: 0
- Espacio superior a Etiqueta de asistentes, valor: Estándar
- Alto, valor: 35
- Etiqueta de finalización
- Espacio inicial a Margen de vista, valor: 0
- Espacio final a Margen de vista, valor: 0
- Espacio superior al Selector de fecha de inicio, valor: Estándar
- Selector de fecha de finalización
- Espacio inicial a Margen de vista, valor: 0
- Espacio final a Margen de vista, valor: 0
- Espacio superior a Etiqueta final, valor: Estándar
- Alto: 35
- Vista texto del cuerpo
- Espacio inicial a Margen de vista, valor: 0
- Espacio final a Margen de vista, valor: 0
- Espacio superior a Selector de fecha de finalización, valor: Estándar
- Espacio inferior a Ver margen, valor: 0
- Barra de navegación
Seleccione la escena del calendario y, a continuación, seleccione el Inspector de conexiones.
En Segues desencadenados, arrastre el círculo no rellenado junto a manual al nuevo controlador de vista de eventos en el guión gráfico. Seleccione Presentar modalmente en el menú emergente.
Seleccione el segue que acaba de agregar y, a continuación, seleccione el Inspector de atributos. Establezca el campo Identificador en
showEventForm
.Conectar la acción showNewEventForm recibió una acción en el botón + de la barra de navegación.
Guarde los cambios y reinicie la aplicación. Ve a la página del calendario y pulsa el + botón. Rellene el formulario y pulse Crear para crear un nuevo evento.
¡Enhorabuena!
Has completado el tutorial de microsoft swift Graph iOS. Ahora que tienes una aplicación de trabajo que llama a Microsoft Graph, puedes experimentar y agregar nuevas características. Visite la información general de Microsoft Graph para ver todos los datos a los que puede acceder con Microsoft Graph.
Comentarios
Proporcione cualquier comentario sobre este tutorial en el repositorio GitHub archivo.
¿Tiene algún problema con esta sección? Si es así, envíenos sus comentarios para que podamos mejorarla.