may 09

Al pasar de la versión 3 a la 4 de Xcode una de las cosas más molestas que nos hemos encontrado fue la forma de mostrar la documentación. Antes, al abrir la documentación de una clase, en el lado izquierdo de la ventana podíamos ver una especie de índice que nos permitía visualizar directamente la lista de métodos de clase y de instancia que tenía esa clase concreta y podíamos saltar directamente a ver la info de un método determinado, etc.

Con la salida del Xcode 4 esa tabla de contenidos desapareció (con el tiempo que nos ahorraba).

Resumiendo, para volver a mostrar esa tabla de contenidos en la documentación hay que ejecutar el siguiente comando en la terminal (recomiendo hacer un backup de los docsets por si algo sale mal):

sudo egrep -lRZ "Prototype.Browser.Xcode4OrNewer=Prototype.Browser.XcodeVersion<1000;" /Library/Developer/Documentation/DocSets | xargs -0 -L % sudo sed -i '' -e 's/Prototype\.Browser\.Xcode4OrNewer\=Prototype\.Browser\.XcodeVersion\<1000\;/Prototype\.Browser\.Xcode4OrNewer\=false\;/g'

Esta información se ha obtenido de este hilo de stackoverflow.

VN:F [1.9.8_1114]
Rating: 4.0/5 (4 votes cast)
VN:F [1.9.8_1114]
Rating: 0 (from 0 votes)
Tagged with:
jul 25

Hoy vamos a ver qué es “weak linking” (linkado débil?), para qué sirve y como usarlo en nuestros proyecto.

Una de las decisiones a tomar cuando empezamos un nuevo proyecto es la de decidir cuál es el dispositivo y/o sistema básico que soportorá nuestra app (iPhone 2G con IOS 2.0? , sólo iPhone 4.0 con iOS4, ipad? o todos?).

Esta claro que cuanto más dispositivos y versiones de SO soportemos a más gente podremos llegar pero para eso tendremos que hacer esfuerzos extra.

El problema consiste en que de una versión a otra se introducen nuevos frameworks, se modifican funciones, se añaden nuevas funcionalidades, etc. A priori si usamos esos nuevos frameworks entonces nuestras apps no funcionarán en las versiones anteriores. Aquí es donde entra weak linking (entre otros) para ayudarnos.

Entonces, vamos a ver un caso práctico donde el “weak linking” nos puede ser útil.

Por ejemplo en iOS 3.0 se introdujo el framework llamado MessageUI que nos permite enviar emails ( y ahora con iOS 4 también SMSes) desde nuestra aplicación. Se encarga de mostrar la interfa de edición de email y permite enviarlo directamente desde nuestra app.

Entonces, que pasa si quieres usar ese nueve framework pero al mismo tiempo queremos que nuestra app siga siendo compatible con las versiones anteriores de iOS?

Muy simple, al incluir este nueva framework en nuestro proyecto lo tenemos que marcar como “weak”.

Para marcar el framework como weak tenemos que hacer click derecho en el Target  para el que queremos hacer el “weak linking” y en el menú desplegable seleccionar “Get Info”:

Luego en la ventana que se abre nos vamos a la pestaña General y abajo de todo veremos el listado de frameworks que se usan para el target seleccionado. En ese listado marcamos el MessageUI.framework como “weak”.

Y está con esto hemos hecho el “weak linking” y ahora el programa se ejecutará tanto en iOS 2,0 (que no tiene MessageUI) como en iOS 3.

He dicho que se ejecutará ahora porque hemos añadido el framework pero por ahora no hems usando ninguna de las clases o funcionces de ese framework.

Si en alguna parte de nuestra app queremos mostrar la vista de edición de email (proporcionado por MessageUI) pondríamos un código parecido a este:

MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
[mail setMessageBody:@"mi mensaje"  isHTML:NO];
mail.mailComposeDelegate = self;
[self presentModalViewController:mail animated:YES];
[mail release];

Después de poner este código la aplicación funcionará bien en iOS3 pero petará en iOS2. Entonces, a parte del weak linking tenemos que de alguna manera preguntar si durante la ejecución están disponibles las clases (también funcionar, métodos, etc) que necesitamos (en este caso tenemos que asegurarnos que el MFMailComposeViewController está disponible).

En el caso de ejemplo tendríamos que hacer lo siguiente:

if (NSClassFromString(@"MFMailComposeViewController") != nil) {
 
	MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
	[mail setMessageBody:@"mi mensaje"  isHTML:NO];
	mail.mailComposeDelegate = self;
	[self presentModalViewController:mail animated:YES];
	[mail release];
 
}else{
		//Hacer algo pensado para las versiones anteriores
}

Con esto si que conseguiremos que la app se ejecute sin problemas tanto en iOS3 como en iOS2.

Pero en este caso todavía podemos rizar más el rizo. La presencia de un framework en el sistema no significa que este puede usarlo. Por ejemplo en el iOS 4 tenemos el MFMessageComposeViewController que sirve para enviar SMS. Si tenemos un iPod touch con iOS4 instalado tendremos ese framework disponible pero eso no significa que vayamos a poder enviar SMSes desde el iPod.

Volviendo al ejemplo anterior, la versión con aun más seguridad/compatibilidad sería este:

if (NSClassFromString(@"MFMailComposeViewController") != nil) {
	if ([MFMailComposeViewController canSendMail]){
		MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
		[mail setMessageBody:@"mi mensaje"  isHTML:NO];
		mail.mailComposeDelegate = self;
		[self presentModalViewController:mail animated:YES];
		[mail release];
 
	}else{
		//hacer algo pensado para un dispositivo de donde no podemos enviar emails
	}
 
}else{
	//Hacer algo pensado para las versiones anteriores
}

Esto que acabamos de ver se llama programación condicional que básicamente nos permite asegurarnos que determinados recursos existen en el sistema antes de usarlos.
Apple recomienda hacer estas comprobaciones a nivel más abajo (funciones y clases) y no a nivel de dispositivo. Es decir, no se recomienda comprobar que estamos ejecutando en un iPhone y dar por seguro que ciertas funciones existen.

En los ejemplos hemos visto cómo comprobar si una clase existe usando la función NSClassFromString() que nos devuelve nul si la clase no existe.
Para comprobar si un método existe o no podemos usar los métodos instancesRespondToSelector y respondsToSelector.
En el caso de funciones podemos comprobar su existencia comparando el nombre de la función con NULL:

if (miFuncion==NULL)
     NSLog(@"La función miFunción no existe");

Para más detalles sobre este tema podéis consultar la SDK Compatibility Guide (está en inglés y tenéis que estar registrados apra verlo) de Apple.

Y como siempre, si tenéis dudas, consultas, sugerencias, correcciones no dudéis un usar los comentarios o nuestro foro.

VN:F [1.9.8_1114]
Rating: 5.0/5 (3 votes cast)
VN:F [1.9.8_1114]
Rating: +4 (from 4 votes)
Tagged with:
preload preload preload