¡Hola a todos!
Para celebrar que por fin he puesto un avatar en mi perfil...

y animado al ver las últimas publicaciones (como la de iAds) y el buen "rollo" de este foro en español... he decidido hacer público este código, y así estrenar mi avatar por todo lo alto

aunque, igual me ha quedado un poco grande

Creo que cuando este tipo de "codesnippets" se hacen públicos pueden ser una gran ayuda para todos, porque así podremos avanzar más rápidamente con nuestros proyectos individuales y eliminar poco a poco las barreras que GLBasic pueda tener bajo iOS

Cuando empecé a escribir el código no tenía demasiados conocimientos de XCode, pero decidí que podría ser muy útil aprender lo necesario del lenguaje original de Apple para poder cubrir cualquier necesidad (fuese cual fuese) y llegar donde GLBasic no pudiera llegar, complementándolo...
Así que puede que alguno de vosotros ya se haya topado con este hilo:
http://www.glbasic.com/forum/index.php?topic=5747.0Lo arranqué para ver si alguien me echaba "un cable"... pero al final nadie pudo ayudarme demasiado con los problemas más importantes (bajo mi punto de vista)

y me pareció que el código que alguien presentó no era muy "definitivo" o correcto del todo...
Añadiendo el hecho de que (y no es que me importen esas cosas) todo el mérito parecía al final de otros...

En fin, no me enrollo más, vamos al grano:
En un archivo con extensión ".mm" que debemos arrastrar hasta nuestro proyecto en XCode (si es que no tenemos uno ya) agregamos:
#if defined (TARGET_OS_IPHONE)
// UIALERT
//#import <UIKit/UIAlert.h> // No es necesario duplicar la importación hecha con anterioridad
@interface GLBasicMessageBoxer: NSObject <UIAlertViewDelegate>
{
// Declaración de los punteros para los elementos comunes
UITextField* txtObject;
NSMutableArray* resObjects;
NSString* resValues;
NSString* pTitle,* pMessage,* pLabels,* pButtons;
}
@end
@implementation GLBasicMessageBoxer
// Llamada necesaria para llamar al código que muestra el Alert en el proceso principal
- (void)showAlertCaller:(NSString*)cTitle andMessage:(NSString*)cMessage andLabels:(NSString*)cLabels andButtons:(NSString*)cButtons
{
// Introducción de los valores pasados como parámetro punteros accesibles por "showAlert"
pTitle = [[NSString alloc] initWithString:cTitle];
pMessage = [[NSString alloc] initWithString:cMessage];
pLabels = [[NSString alloc] initWithString:cLabels];
pButtons = [[NSString alloc] initWithString:cButtons];
// Llamada a "showAlert" enviándola al proceso principal
[self performSelectorOnMainThread:@selector(showAlert) withObject:nil waitUntilDone:NO];
}
- (void)showAlert
{
// Creación de la vista para el Alert
UIAlertView* alert = [[UIAlertView alloc] init];
alert.title = pTitle;
alert.message = pMessage;
alert.delegate = self;
// Anulación de la asignación de la función de cancelar al botón con índice 0
alert.cancelButtonIndex = -1;
// Creación de la matriz de botones introduciendo valores según los parámetros pasados separados por "|"
NSArray* aButtons = [pButtons componentsSeparatedByString:@"|"];
// Creación de cada botón a partir de cada valor de la matriz
for (NSString* iObject in aButtons){
[alert addButtonWithTitle:iObject];
}
// Creación de la matriz de controles de texto introduciendo valores según los parámetros pasados separados por "|"
if (pLabels != @"") {
double iPos = 70.0;
NSArray* aLabels = [pLabels componentsSeparatedByString:@"|"];
resObjects = [[NSMutableArray alloc] init];
// Creación de cada control de texto con las propiedades adecuadas asegurando que no devuelve un valor "(null)" mediante .text = @""
for (NSString* iObject in aLabels){
txtObject = [[UITextField alloc] init];
txtObject.frame = CGRectMake(12.0, iPos, 260.0, 25.0);
txtObject.text = @"";
txtObject.placeholder = iObject;
txtObject.backgroundColor = [UIColor whiteColor];
txtObject.clearButtonMode = UITextFieldViewModeWhileEditing;
txtObject.keyboardType = UIKeyboardTypeAlphabet;
txtObject.keyboardAppearance = UIKeyboardAppearanceAlert;
txtObject.autocapitalizationType = UITextAutocapitalizationTypeNone;
txtObject.autocorrectionType = UITextAutocorrectionTypeNo;
txtObject.borderStyle = UITextBorderStyleLine;
// Colocación del foco si es el primer control creado para introducción de texto
if ([aLabels indexOfObject:iObject] == 0) {
[txtObject becomeFirstResponder];
// El teclado aparece automáticamente al colocar el foco en un control de texto
}
// Aumentar el valor de la variable que controla la coordenada de posición del "top" de cada control de texto
iPos = iPos + 30.0;
// Asociación de cada control a la matriz mutable
[resObjects addObject:txtObject];
// XCode soporta añadir controles de texto directamente a un Alert pero Apple no permite su uso directo al no estar documentado
// Para poder imitar el comportamiento pueden agregarse "subvistas" al Alert e introducir los controles necesarios en ellas
[alert addSubview:txtObject];
[txtObject release];
txtObject = nil;
}
}
[alert show];
[alert release];
}
// Recogida del botón pulsado en la memoria mediante la propiedad "delegate" (= self) asignada en "showAlert"
- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
resValues = [[NSString alloc] initWithFormat:@"%d", buttonIndex];
}
// Código que obtiene y trata los valores para construir el resultado mediante valores separados por "|"
- (void)getValues
{
// Agregado a la cadena del botón pulsado de los valores de cada control de texto en el Alert
for (UITextField* iObject in resObjects){
// Insertar el texto recogido del control en un NSMutableString
NSMutableString* tmpObjectValue = [[NSMutableString alloc] initWithString:iObject.text];
// Reemplazar el caracter usado en el código como separador de valores si el usuario lo ha introducido en los controles
[tmpObjectValue replaceOccurrencesOfString:@"|" withString:@"!" options:0 range:NSMakeRange(0, [tmpObjectValue length])];
// Agregar el valor obtenido al contenido anterior de la memoria
resValues = [resValues stringByAppendingFormat:@"|%@", tmpObjectValue];
// Liberar la memoria
[tmpObjectValue release];
tmpObjectValue = nil;
}
// Creación de otro puntero "NSData" temporal para albergar los valores obtenidos transformados para evitar errores por "encodings"
NSData* tmpValuesEncoded = [[NSData alloc] init];
// Conversión de la cadena obtenida a un "encoding" Windows Latin obviando los caracteres no reconocidos mediante "allowLossyConversion"
tmpValuesEncoded = [resValues dataUsingEncoding:NSWindowsCP1252StringEncoding allowLossyConversion:YES];
// Reintroducción de la cadena final convertida al "encoding" adecuado para que pueda devolverse desde "getValuesCaller"
resValues = [[NSString alloc] initWithData:tmpValuesEncoded encoding:NSWindowsCP1252StringEncoding];
// Liberar la memoria
tmpValuesEncoded = nil;
}
// Obtención de los valores del botón pulsado y texto introducido en los controles recuperando los valores desde el proceso principal
- (const char*)getValuesCaller
{
// Comprobación de si se ha pulsado un botón del Alert
if (resValues != nil){
// Llamada a "getValues" en el proceso principal
[self performSelectorOnMainThread:@selector(getValues) withObject:nil waitUntilDone:YES];
// Devolvemos el valor de la cadena preparada desde "getValues"
return [resValues cStringUsingEncoding:NSWindowsCP1252StringEncoding];
// Liberar la memoria
[resObjects release];
resObjects = nil;
[resValues release];
resValues = nil;
[pTitle release];
pTitle = nil;
[pMessage release];
pMessage = nil;
[pLabels release];
pLabels = nil;
[pButtons release];
pButtons = nil;
[self release];
[super dealloc];
}
else
{
// Si no se ha pulsado ningún botón se devuelve una cadena vacía
return "";
}
}
@end
// Creación del puntero para las funciones contenidas en "GLBasicMessageBoxer" a usar cada vez que se requiera un Alert
GLBasicMessageBoxer* newAlert;
// Creación de función "externalizada" a usar desde GLBasic (los parámetros "labels" y "buttons" pueden contener varios valores separados con "$")
extern "C" void iOSMessageBox(const char* cTitle, const char* cMessage, const char* cLabels, const char* cButtons)
{
newAlert = [[GLBasicMessageBoxer alloc] init];
// Conversión de tipos "C" a "NSString" al recuperar los parámetros enviados desde GLBasic y lanzado del Alert
[newAlert showAlertCaller:[NSString stringWithCString:cTitle encoding:NSASCIIStringEncoding] andMessage:[NSString stringWithCString:cMessage encoding:NSASCIIStringEncoding] andLabels:[NSString stringWithCString:cLabels encoding:NSASCIIStringEncoding] andButtons:[NSString stringWithCString:cButtons encoding:NSASCIIStringEncoding]];
}
// Creación de la función "externalizada" a usar desde GLBasic (los parámetros devueltos son valores separados con "$")
extern "C" const char* GetiOSMessageBoxValues()
{
// Se recuperan en primer lugar el índice de botón pulsado y a continuación los textos introducidos en los controles generados
return [newAlert getValuesCaller];
}
// FIN UIALERT
#endif
Después, desde GLBasic, podríamos hacer algo como esto:
IMPORT "C" void iOSMessageBox(const char*,const char*, const char*, const char*)
IMPORT "C" const char* GetiOSMessageBoxValues()
GLOBAL MENSAJE$
// El nuevo símbolo de separación para los parámetros a pasar a la función es la "tubería", antes era $, en mi código anterior...
iOSMessageBox("Título","Mensaje" + CHR$(0xD) + CHR$(0xD) + CHR$(0xD) + CHR$(0xD), "Esto es una prueba ü Ñ |:P", "Aceptar|Cancelar")
LOCAL InstanteComienzo% = GETTIMERALL()
MENSAJE$ = ""
WHILE MENSAJE$ = ""
SLEEP 500
WHILE ABS(GETTIMERALL() - InstanteComienzo%) < 500
HIBERNATE
WEND
MENSAJE$ = GetiOSMessageBoxValues()
WEND
PRINT MENSAJE$, 100, 100
SHOWSCREEN
HIBERNATE
MOUSEWAIT
iOSMessageBox("Título","Mensaje" + CHR$(0xD) + CHR$(0xD), "Esto es otra prueba", "Aceptar|Cancelar")
InstanteComienzo% = GETTIMERALL()
MENSAJE$ = ""
WHILE MENSAJE$ = ""
SLEEP 500
WHILE ABS(GETTIMERALL() - InstanteComienzo%) < 500
HIBERNATE
WEND
MENSAJE$ = GetiOSMessageBoxValues()
WEND
PRINT MENSAJE$, 100, 100
SHOWSCREEN
HIBERNATE
MOUSEWAIT
Como vereis, las funciones envían y recogen los valores como una cadena de valores separados por "|" (tubería), que desde GLBasic es muy fácil tratar...

además GetiOSMessageBoxValues devuelve como primer parámetro el índice del botón pulsado en el "alert".
También es totalmente parametrizable en cuanto a botones y cantidad de casillas de texto, probad a introducir más o menos valores separados por "|" en iOSMessageBox

Así, podemos conseguir un simple "alert" desde GLBasic haciendo algo como esto:
iOSMessageBox("Título","Mensaje de prueba", "", "Aceptar")
Y bueno... si alguien tiene alguna duda que lo pregunte por aquí y estaré encantado de hacer cualquier aclaración...
Tengo planeadas muchas "ampliaciones" al código a partir de aquí, como por ejemplo hacer aparecer el teclado, y recoger los caracteres, sin necesidad de un alert... aunque si alguien se atreve con ello ántes que yo...

Si alguien lo va probando me encantaría que posteara que tal le ha ido...
Y ya... si alguien que utilice éste código quiere simplemente mencionarme de pasada en los "agradecimientos" de los créditos de su juego... Hago una fiesta, vamos... XDDDDDDDDDDDD
Weno, ahí queda eso, ánimo con vuestro código!!!!
-David-