Hace unos días, se liberó la versión 2.0 de la aplicación del Metro de México DF para iOS, hecha con GeneXus Tilo, y que tiene como novedad que incorpora la funcionalidad de generación Offline de esta versión. Hasta donde sé(1), esta es la primera aplicación Offline en iOS con GeneXus.
La generación Offline para aplicaciones de Smart Devices es una de las características principales de la versión Tilo, de la cual estamos por liberar una beta que agrega esta funcionalidad para iOS.
Por "aplicaciones Offline" en este caso, entendemos aplicaciones que tienen una base de datos en el dispositivo (SQLite, tanto en iOS como en Android), y tienen generación de código del lado del cliente, por lo que pueden funcionar completamente desconectadas del servidor.
En la versión Evolution 2 lo más parecido, es el caché de datos, que permitía acceder a los mismos a pesar de no tener conexión, pero no permitía ejecutar código del lado del cliente ni realizar modificaciones en la base de datos.
En particular la aplicación del Metro DF usa varias características del nuevo generador.
Para empezar, tiene todos los datos embebido en el SQLite, por lo que los accesos son mucho más rápidos.
Además se hace uso del generador de Objective-C, por lo que todos los cálculos se realizan locales, no hay ninguna llamada al servidor por ejemplo para calcular las rutas entre dos estaciones dadas.
También se realizan modificaciones a la base de datos mediante procedimientos, para cálculos internos, aunque esto no es visible para el usuario final ya que no hay ningún formulario de entrada de datos.
Otra cosa para destacar es que en la aplicación se usó la sincronización automática de datos (del servidor al cliente), para la carga inicial de datos en el SQLite, que luego se agregaron a la aplicación compilada (para evitar que cada instalación tenga que sincronizar).
Como decía, en breve vamos a tener una beta liberada para que puedan probar esta funcionalidad. No es una versión completa, porque quedan cosas por hacer, pero por lo menos tenemos la certeza de que ya hay un conjunto de aplicaciones que se pueden hacer. Y para muestra, ya pueden bajar la aplicación del Metro de México DF(2)
(1) Dado que el generador no está liberado, creo estar bastante seguro de que no hay otra aplicación liberada para iOS que use base de datos Offline. Si me equivoco, me avisan :)
(2) La aplicación tiene algunos puntos a mejorar, por lo que se va a estar subiendo una nueva versión, pero igual me pareció destacable que la aplicación ya esté en producción...
Blog de Marcos Crispino
Sobre desarrollo de software, tecnología, y algunas otras cosas
lunes, 17 de junio de 2013
jueves, 13 de junio de 2013
Literales de tipo Date y DateTime en GeneXus
Cuando programamos, ya sea en GeneXus o en cualquier otro lenguaje, es muy común usar literales en el código, para valores conocidos o especiales de la aplicación.
Por ejemplo, si voy a hacer una suma de varios registros, inicializo la variable en cero:
En GeneXus hay unos cuantos tipos de datos, pero podríamos decir que los principales son cuatro: números, strings, booleanos y fechas (o fecha-hora para ser más precisos).
Para los tres primeros, es bien sabido como expresar literales, ¿pero para las fechas?
Esta funcionalidad creo que no es muy conocida, pero en GeneXus también se pueden escribir literales de fechas, utilizando el caracter # como delimitador (así como usamos las comillas simples o dobles para los strings).
Así por ejemplo, las siguientes expresiones son válidas:
Esto en sí no parece tener demasiadas ventajas con respecto a usar las funciones YMDtoD y YMDHMStoT, pero hay un caso donde sí en necesario usarlos: cuando queremos hacer un call dinámico a un objeto SD, que recibe una fecha por parámetro. Por ejemplo:
Por ejemplo, si voy a hacer una suma de varios registros, inicializo la variable en cero:
&suma = 0O si estoy por ejemplo en una transacción y quiero saber si estoy en modo Insert, puedo preguntar
if &Mode = 'INS'(nota: es un ejemplo... lo recomendable en este caso es usar el dominio enumerado TrnMode)
...
endif
En GeneXus hay unos cuantos tipos de datos, pero podríamos decir que los principales son cuatro: números, strings, booleanos y fechas (o fecha-hora para ser más precisos).
Para los tres primeros, es bien sabido como expresar literales, ¿pero para las fechas?
Esta funcionalidad creo que no es muy conocida, pero en GeneXus también se pueden escribir literales de fechas, utilizando el caracter # como delimitador (así como usamos las comillas simples o dobles para los strings).
Así por ejemplo, las siguientes expresiones son válidas:
&date = #2013-06-13#Por más información, pueden ver la documentación oficial en el Wiki.
&dateTime = #2013-06-13 06:23p#
Esto en sí no parece tener demasiadas ventajas con respecto a usar las funciones YMDtoD y YMDHMStoT, pero hay un caso donde sí en necesario usarlos: cuando queremos hacer un call dinámico a un objeto SD, que recibe una fecha por parámetro. Por ejemplo:
&callObject = "sd:MiObjetoSD?#2013-06-13#"En todo caso, es una herramienta más de la que disponemos a la hora de escribir nuestras aplicaciones en GeneXus.
call(&callObject)
Etiquetas:
desarrollo,
genexus,
útiles
martes, 11 de junio de 2013
iOS 7
En el día de ayer Apple presentó la nueva versión de iOS, que ya se puede obtener en versión beta y estará disponible más adelante este año.
La presentación se puede ver completa en el sitio de Apple, donde tambiéan anunciaron una nueva versión de OS X (con poca cosa nueva...), nuevas MacBook Air y una nueva Mac Pro. Si quieren ver el video de presentación de iOS 7 específicamente (no la presentación), también lo pueden hacer.
Si bien se esperaba que el nuevo diseño en iOS 7 fuera más "flat" que en versiones anteriores, creo que con lo que mostraron se pasaron para el otro lado...
Todavía no instalé la beta, y dudo que lo vaya a hacer. Eventualmente voy a terminar actualizando, pero el diseño de esta nueva versión me parece mucho más descuidado que en iOS 6.
Por ejemplo, la aplicación del WWDC que liberaron hace unos días para el evento de desarrolladores, tiene "tabs" en la barra de navegación que se ven así:
En contraste, por ejemplo la aplicación de Calendario en iOS 6, tiene botones similares en la "toolbar", que se ven así:
Entre estos dos diseños, ya se nota la diferencia. En la aplicación del WWDC se le saca el aspecto redondeado a los botones y a la barra misma.
Sin embargo, a pesar que podía ser esperable algo similar para iOS 7, hicieron un cambio mucho más grande.
En iOS 7, ese mismo componente de UI se ve así:
En temas de diseño, evidentemente es una cuestión de gustos... pero el estilo "flat" que eligieron me resulta bastante malo.
En fin... Ya veremos el próximo año cuando anuncien el porcentaje de adopción de iOS 7, a ver si se acerca al que tiene iOS 6 hoy en día (que es del 93% de acuerdo a la presentación de ayer).
La presentación se puede ver completa en el sitio de Apple, donde tambiéan anunciaron una nueva versión de OS X (con poca cosa nueva...), nuevas MacBook Air y una nueva Mac Pro. Si quieren ver el video de presentación de iOS 7 específicamente (no la presentación), también lo pueden hacer.
Si bien se esperaba que el nuevo diseño en iOS 7 fuera más "flat" que en versiones anteriores, creo que con lo que mostraron se pasaron para el otro lado...
Todavía no instalé la beta, y dudo que lo vaya a hacer. Eventualmente voy a terminar actualizando, pero el diseño de esta nueva versión me parece mucho más descuidado que en iOS 6.
Por ejemplo, la aplicación del WWDC que liberaron hace unos días para el evento de desarrolladores, tiene "tabs" en la barra de navegación que se ven así:
En contraste, por ejemplo la aplicación de Calendario en iOS 6, tiene botones similares en la "toolbar", que se ven así:
Entre estos dos diseños, ya se nota la diferencia. En la aplicación del WWDC se le saca el aspecto redondeado a los botones y a la barra misma.
Sin embargo, a pesar que podía ser esperable algo similar para iOS 7, hicieron un cambio mucho más grande.
En iOS 7, ese mismo componente de UI se ve así:
En temas de diseño, evidentemente es una cuestión de gustos... pero el estilo "flat" que eligieron me resulta bastante malo.
En fin... Ya veremos el próximo año cuando anuncien el porcentaje de adopción de iOS 7, a ver si se acerca al que tiene iOS 6 hoy en día (que es del 93% de acuerdo a la presentación de ayer).
jueves, 16 de mayo de 2013
Realidad Aumentada en aplicaciones iOS con GeneXus
Hace un tiempo, Gastón hablaba sobre las ventajas del "Model Driven Development", y una de las que menciona es la extensibilidad.
Hoy sin duda esto queda demostrado, gracias a aplicaciones como ArTur MVD.
ArTur MVD es una guía turística de Montevideo para iOS y Android, desarrollada por la gente de DevXtend. Fue premiada durante el XXI Encuentro GeneXus (año 2011), y en su momento incluía una función de reconocimiento de monumentos, para lo cual alcanzaba con tomar una foto del monumento, y la aplicación nos mostraba la información del mismo.
Hace unos días subieron una nueva versión al App Store, que incluye la funcionalidad de realidad aumentada. Cuando uno apunta la cámara del dispositivo en una determinada dirección, muestra los restaurantes, comercios, hoteles, etc. que hay en esa dirección, dentro de un radio de 5 kilómetros.
La aplicación está hecha con GeneXus X Evolution 2, y la funcionalidad de realidad aumentada está provista por un user control desarrollado por la misma gente de DevXtend, que usa la información de "geolocation" de los items de un grid, la posición actual y la orientación del dispositivo, para saber que información debe mostrar.
El control por ahora lo tienen solamente para iOS, pero están trabajando también en una versión para Android. Además, estará disponible en el Marketplace para que lo pueda utilizar cualquiera (aclaro que desconozco como será el licenciamiento, si será pago o no...).
En la página correspondiente del Showcase pueden ver un video del control en acción.
Hoy sin duda esto queda demostrado, gracias a aplicaciones como ArTur MVD.
ArTur MVD es una guía turística de Montevideo para iOS y Android, desarrollada por la gente de DevXtend. Fue premiada durante el XXI Encuentro GeneXus (año 2011), y en su momento incluía una función de reconocimiento de monumentos, para lo cual alcanzaba con tomar una foto del monumento, y la aplicación nos mostraba la información del mismo.
Hace unos días subieron una nueva versión al App Store, que incluye la funcionalidad de realidad aumentada. Cuando uno apunta la cámara del dispositivo en una determinada dirección, muestra los restaurantes, comercios, hoteles, etc. que hay en esa dirección, dentro de un radio de 5 kilómetros.
La aplicación está hecha con GeneXus X Evolution 2, y la funcionalidad de realidad aumentada está provista por un user control desarrollado por la misma gente de DevXtend, que usa la información de "geolocation" de los items de un grid, la posición actual y la orientación del dispositivo, para saber que información debe mostrar.
El control por ahora lo tienen solamente para iOS, pero están trabajando también en una versión para Android. Además, estará disponible en el Marketplace para que lo pueda utilizar cualquiera (aclaro que desconozco como será el licenciamiento, si será pago o no...).
En la página correspondiente del Showcase pueden ver un video del control en acción.
Etiquetas:
genexus,
user controls
lunes, 22 de abril de 2013
Mi primer media maratón
En el día de ayer corrí por primera vez una media maratón (21 kilómetros). Capaz que esta mal que yo lo diga, pero fue todo un logro :)
No hace mucho que empecé a correr, menos de tres años, y la verdad si en ese momento me hubieran dicho que iba a poder correr esa distancia, no les hubiera creído.
Hoy creo que con el entrenamiento adecuado, cualquiera puede correr la distancia que se proponga (salvo por algún impedimento médico, obviamente). Ayer por ejemplo, la edición de 10km de la carrera, la corrió un hombre con dos muletas...
El entrenamiento
Desde antes de empezar a prepararme para la media maratón, ya estaba usando una aplicación que se llama RunKeeper, que además de permitir registrar las corridas, tiene la opción de seguir programas de entrenamiento.
El que elegí yo era para correr la media maratón en menos de 2 horas y 15 minutos. Implicaba salir a correr entre cuatro y cinco veces por semana, con distintas distancias, velocidades, y con sesiones con cambio de ritmo. Fueron algo más de tres meses de entrenamiento y casi 500 km recorridos, que sin duda valieron la pena.
La carrera
La carrera fue ayer, como decía, a las 9 de la mañana.
Hubo bastante gente. No la cantidad que hay en las carreras masivas de 10km, pero me sorprendió tanta gente para correr los 21km. Después viendo los resultados, llegaron a la meta más de 800 personas.
El día estuvo muy lindo. Demasiado lindo capaz, cerca de las 11 de la mañana se hizo sentir el calor...
Pude cumplir mi objetivo de terminar la carrera primero, y luego de hacerla en menos de 2:15' ya que puse un tiempo de 2:09'30".
De todas formas venía mejor hasta el km 18, y los últimos tres fueron bastante difíciles. Así que en parte quedé con esa sensación de derrota, como cuando te empatan el partido en la hora.
¿Y ahora qué?
Por lo pronto ahora a descansar unos días, para darle un respiro a las rodillas.
En la primavera correré alguna de las carreras de 10km, a ver si puedo bajar de los 55 minutos, que era el objetivo para el 2012 y no logré cumplir.
Y después veremos... No creo que estos hayan sido los últimos 21km ;)
No hace mucho que empecé a correr, menos de tres años, y la verdad si en ese momento me hubieran dicho que iba a poder correr esa distancia, no les hubiera creído.
Hoy creo que con el entrenamiento adecuado, cualquiera puede correr la distancia que se proponga (salvo por algún impedimento médico, obviamente). Ayer por ejemplo, la edición de 10km de la carrera, la corrió un hombre con dos muletas...
El entrenamiento
Desde antes de empezar a prepararme para la media maratón, ya estaba usando una aplicación que se llama RunKeeper, que además de permitir registrar las corridas, tiene la opción de seguir programas de entrenamiento.
El que elegí yo era para correr la media maratón en menos de 2 horas y 15 minutos. Implicaba salir a correr entre cuatro y cinco veces por semana, con distintas distancias, velocidades, y con sesiones con cambio de ritmo. Fueron algo más de tres meses de entrenamiento y casi 500 km recorridos, que sin duda valieron la pena.
La carrera
La carrera fue ayer, como decía, a las 9 de la mañana.
Hubo bastante gente. No la cantidad que hay en las carreras masivas de 10km, pero me sorprendió tanta gente para correr los 21km. Después viendo los resultados, llegaron a la meta más de 800 personas.
El día estuvo muy lindo. Demasiado lindo capaz, cerca de las 11 de la mañana se hizo sentir el calor...
Pude cumplir mi objetivo de terminar la carrera primero, y luego de hacerla en menos de 2:15' ya que puse un tiempo de 2:09'30".
De todas formas venía mejor hasta el km 18, y los últimos tres fueron bastante difíciles. Así que en parte quedé con esa sensación de derrota, como cuando te empatan el partido en la hora.
¿Y ahora qué?
Por lo pronto ahora a descansar unos días, para darle un respiro a las rodillas.
En la primavera correré alguna de las carreras de 10km, a ver si puedo bajar de los 55 minutos, que era el objetivo para el 2012 y no logré cumplir.
Y después veremos... No creo que estos hayan sido los últimos 21km ;)
jueves, 11 de abril de 2013
Cosas que me gustaría tener en Objective-C
En los últimos tiempos, el lenguaje Objective-C ha mejorado bastante, como ya hemos comentado en el blog (por ejemplo acá).
Pero (siempre hay un "pero"), igual hay algunas cosas que todavía se podrían mejorar o agregar al lenguaje.
Cuando uso una variable que está basada en este protocolo (id<MyProtocol> myVar), puedo ver cuantos elementos tiene el array escribiendo
Una alternativa sería tener algo así como "method templates", donde se pudiera definir la implementación del método en el protocolo mismo. Estos templates solo podrían usar otros métodos y propiedades definidos en el protocolo.
El ejemplo más claro de esto es con los "singleton". Una posible implementación es la siguiente:
Nótese que en esta implementación no se hace nunca referencia a la clase donde está definido el método. Lo único que se requiere es que tenga un método init.
Si tuviera algo equivalente a los módulos de Ruby (cuando se usan como "mixins"), podría simplemente "declarar" que una clase es un singleton, y que eso incluya la implementación del método sharedInstance.
Esto es muy útil, y por ejemplo los arrays no controlan el tipo de objeto, por lo que podemos tener por ejemplo un número y un texto en el mismo array.
Sin embargo, hay veces que es útil saber de que tipo son los elementos de una colección, y forzar a que no se agreguen elementos de otro tipo.
Supongamos el caso que tenemos un protocolo que define una propiedad
Pero (siempre hay un "pero"), igual hay algunas cosas que todavía se podrían mejorar o agregar al lenguaje.
Implementación default para métodos de protocolos
Supongamos que tenemos un @protocol MyProtocol, que define una @property NSArray *someArray.Cuando uso una variable que está basada en este protocolo (id<MyProtocol> myVar), puedo ver cuantos elementos tiene el array escribiendo
[[myVar someArray] count]Pero supongamos que esto lo hago muy seguido, entonces quiero cambiar esto, para que el protocolo ya defina la propiedad elementCount para poder usarla como
[myVar elementCount]¿Cuál es el problema con esto? Que si agrego la propiedad elementCount al protocolo, tengo que implementarla en todas las clases que implementan el protocolo.
Una alternativa sería tener algo así como "method templates", donde se pudiera definir la implementación del método en el protocolo mismo. Estos templates solo podrían usar otros métodos y propiedades definidos en el protocolo.
Templates o módulos
Yendo en la misma línea, hay casos en que una implementación de un método es genérica, sin importar la clase en la que esté.El ejemplo más claro de esto es con los "singleton". Una posible implementación es la siguiente:
+ (instancetype)sharedInstance {(tomada de NSHipster, un excelente blog sobre Objective-C, ya que estamos)
static id _sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
Nótese que en esta implementación no se hace nunca referencia a la clase donde está definido el método. Lo único que se requiere es que tenga un método init.
Si tuviera algo equivalente a los módulos de Ruby (cuando se usan como "mixins"), podría simplemente "declarar" que una clase es un singleton, y que eso incluya la implementación del método sharedInstance.
Generics
En las APIs de Objective-C, cuando un método espera recibir un objeto genérico, declara que recibe un id, que indica que puede recibir cualquier tipo de objeto.Esto es muy útil, y por ejemplo los arrays no controlan el tipo de objeto, por lo que podemos tener por ejemplo un número y un texto en el mismo array.
Sin embargo, hay veces que es útil saber de que tipo son los elementos de una colección, y forzar a que no se agreguen elementos de otro tipo.
Supongamos el caso que tenemos un protocolo que define una propiedad
@property (nonatomic, strong) NSArray *actions;¿De qué tipo pueden ser las actions? No lo sabemos, a no ser que quien escribió el protocolo haya puesto un comentario... El lenguaje me debería ayudar a que esto quede más claro.
Boxing (y unboxing) de tipos básicos
En Objective-C, los arrays y los diccionarios solo pueden contener objetos, por lo que si queremos guardar por ejemplo un int en un array, tenemos que hacer el "boxing"y pasarlo al array como un NSNumber *.
Si bien no es algo complicado de hacer, por ejemplo;
int someInteger = 1;podría ser el compilador el que se encargue de hacerlo...
NSArray *myArray = [NSArray arrayWithObject: @(someInteger) ];
Map & Reduce
Las funciones que tiene la API para manipular colecciones, en ciertos aspectos son bastante limitados.
Por ejemplo, no tengo funciones para Map y Reduce, que son muy útiles. Son fáciles de implementar, pero ya podrían venir incluidas.
Otras, por ejemplo para filtrar un array, son demasiado complicadas:
Por ejemplo, no tengo funciones para Map y Reduce, que son muy útiles. Son fáciles de implementar, pero ya podrían venir incluidas.
Otras, por ejemplo para filtrar un array, son demasiado complicadas:
[[someArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^(id evaluatedObject, NSDictionary *bindings) {Debería poder escribir simplemente
/* filtering code goes here */
}];
[someArray filterWithBlock:^(id evaluatedObject) {
/* filtering code goes here */
}];
Conclusión
Por suerte Objective-C es un lenguaje en evolución, así que tal vez podamos contar con alguna de estas cosas en el futuro...
Etiquetas:
desarrollo,
objective-c,
reflexiones
sábado, 6 de abril de 2013
Comandos útiles de Google Search
Hace ya bastante tiempo que la página de búsqueda de Google dejó de ser un simple buscador de páginas web, y ha pasado a ser más una especie de aplicación de línea de comandos, que brinda información de contexto y no solo una lista de resultados.
Lo que sigue son algunos comandos útiles que se pueden usar en Google Search. No pretende ser una lista exhaustiva, son los que conosco y uso con cierta frecuencia.
Lo que sigue son algunos comandos útiles que se pueden usar en Google Search. No pretende ser una lista exhaustiva, son los que conosco y uso con cierta frecuencia.
Calculadora
Si en vez de ingresar un texto a buscar, ingresamos una operación aritmética como por ejemplo "2+3", Google nos devuelve el resultado, y muestra una calculadora como para poder seguir haciendo operaciones.
También permite usar funciones trigonométricas, logaritmos, exponenciales, factoriales, etc. Es bastante completa.
Gráfica de funciones
Si uno escribe una función, por ejemplo "x^2+1", el resultado que obtiene es la gráfica de la misma.
No es que use mucho esta funcionalidad, pero me hubiera servido en otro momento :)
Conversión de monedas
Si queremos saber algún tipo de cambio, digamos para saber cuantos dólares son 100 euros, escribimos "convert 100 euros to dollars".
Funciona también para pesos uruguayos, la única dificultad es que hay que escribir el comando en inglés: convert 100 uruguayan pesos to dollars.
Estado del tiempo
También podemos consultar el estado del tiempo en algún lugar, por ejemplo preguntando "weather montevideo", o simplemente "weather" y (a veces) Google se da cuenta en donde estamos.
El resultado muestra pronóstico por hora de la temperatura, lluvia y viento, y el pronóstico para los próximos días. Bastante completo, aunque no me puse a sacar estadísticas para ver que tan acertado es...
Información sobre películas, libros y música
Si buscamos por el título de una película, serie, libro, disco, o por autor, actor, director, etc., además de la clásica lista de resultados, muestra a la derecha de la página información sobre lo que estamos buscando.
Conclusión
La búsqueda de páginas web a veces es útil, pero puede ser una pérdida de tiempo si queremos encontrar algo específico. Google va por el camino de tratar de mostrar la información más relevante dada la búsqueda que estamos haciendo.
La lista de comandos que mencioné en el artículo puede resultar útil, seguramente haya otras cosas que no conozco, y seguramente se vayan agregando más comandos con el paso del tiempo.
¿Alguien sabe de otros comandos que se puedan usar en Google Search? ¿Algún otro buscador que haga este tipo de cosas?
Suscribirse a:
Entradas (Atom)









